| OLD | NEW | 
 | (Empty) | 
|    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.111 2009/07/09 05:07:38 danielk1977 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_pager_stats ID |  | 
|  162 ** |  | 
|  163 ** Returns pager statistics |  | 
|  164 */ |  | 
|  165 static int btree_pager_stats( |  | 
|  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 i; |  | 
|  173   int *a; |  | 
|  174  |  | 
|  175   if( argc!=2 ){ |  | 
|  176     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |  | 
|  177        " ID\"", 0); |  | 
|  178     return TCL_ERROR; |  | 
|  179   } |  | 
|  180   pBt = sqlite3TestTextToPtr(argv[1]); |  | 
|  181   |  | 
|  182   /* Normally in this file, with a b-tree handle opened using the  |  | 
|  183   ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly. |  | 
|  184   ** But this function is sometimes called with a btree handle obtained |  | 
|  185   ** from an open SQLite connection (using [btree_from_db]). In this case |  | 
|  186   ** we need to obtain the mutex for the controlling SQLite handle before |  | 
|  187   ** it is safe to call sqlite3BtreeEnter(). |  | 
|  188   */ |  | 
|  189   sqlite3_mutex_enter(pBt->db->mutex); |  | 
|  190  |  | 
|  191   sqlite3BtreeEnter(pBt); |  | 
|  192   a = sqlite3PagerStats(sqlite3BtreePager(pBt)); |  | 
|  193   for(i=0; i<11; i++){ |  | 
|  194     static char *zName[] = { |  | 
|  195       "ref", "page", "max", "size", "state", "err", |  | 
|  196       "hit", "miss", "ovfl", "read", "write" |  | 
|  197     }; |  | 
|  198     char zBuf[100]; |  | 
|  199     Tcl_AppendElement(interp, zName[i]); |  | 
|  200     sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]); |  | 
|  201     Tcl_AppendElement(interp, zBuf); |  | 
|  202   } |  | 
|  203   sqlite3BtreeLeave(pBt); |  | 
|  204  |  | 
|  205   /* Release the mutex on the SQLite handle that controls this b-tree */ |  | 
|  206   sqlite3_mutex_leave(pBt->db->mutex); |  | 
|  207   return TCL_OK; |  | 
|  208 } |  | 
|  209  |  | 
|  210 /* |  | 
|  211 ** Usage:   btree_cursor ID TABLENUM WRITEABLE |  | 
|  212 ** |  | 
|  213 ** Create a new cursor.  Return the ID for the cursor. |  | 
|  214 */ |  | 
|  215 static int btree_cursor( |  | 
|  216   void *NotUsed, |  | 
|  217   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */ |  | 
|  218   int argc,              /* Number of arguments */ |  | 
|  219   const char **argv      /* Text of each argument */ |  | 
|  220 ){ |  | 
|  221   Btree *pBt; |  | 
|  222   int iTable; |  | 
|  223   BtCursor *pCur; |  | 
|  224   int rc; |  | 
|  225   int wrFlag; |  | 
|  226   char zBuf[30]; |  | 
|  227  |  | 
|  228   if( argc!=4 ){ |  | 
|  229     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |  | 
|  230        " ID TABLENUM WRITEABLE\"", 0); |  | 
|  231     return TCL_ERROR; |  | 
|  232   } |  | 
|  233   pBt = sqlite3TestTextToPtr(argv[1]); |  | 
|  234   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; |  | 
|  235   if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; |  | 
|  236   pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize()); |  | 
|  237   memset(pCur, 0, sqlite3BtreeCursorSize()); |  | 
|  238   sqlite3BtreeEnter(pBt); |  | 
|  239   rc = sqlite3BtreeLockTable(pBt, iTable, wrFlag); |  | 
|  240   if( rc==SQLITE_OK ){ |  | 
|  241     rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); |  | 
|  242   } |  | 
|  243   sqlite3BtreeLeave(pBt); |  | 
|  244   if( rc ){ |  | 
|  245     ckfree((char *)pCur); |  | 
|  246     Tcl_AppendResult(interp, errorName(rc), 0); |  | 
|  247     return TCL_ERROR; |  | 
|  248   } |  | 
|  249   sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); |  | 
|  250   Tcl_AppendResult(interp, zBuf, 0); |  | 
|  251   return SQLITE_OK; |  | 
|  252 } |  | 
|  253  |  | 
|  254 /* |  | 
|  255 ** Usage:   btree_close_cursor ID |  | 
|  256 ** |  | 
|  257 ** Close a cursor opened using btree_cursor. |  | 
|  258 */ |  | 
|  259 static int btree_close_cursor( |  | 
|  260   void *NotUsed, |  | 
|  261   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */ |  | 
|  262   int argc,              /* Number of arguments */ |  | 
|  263   const char **argv      /* Text of each argument */ |  | 
|  264 ){ |  | 
|  265   BtCursor *pCur; |  | 
|  266   Btree *pBt; |  | 
|  267   int rc; |  | 
|  268  |  | 
|  269   if( argc!=2 ){ |  | 
|  270     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |  | 
|  271        " ID\"", 0); |  | 
|  272     return TCL_ERROR; |  | 
|  273   } |  | 
|  274   pCur = sqlite3TestTextToPtr(argv[1]); |  | 
|  275   pBt = pCur->pBtree; |  | 
|  276   sqlite3BtreeEnter(pBt); |  | 
|  277   rc = sqlite3BtreeCloseCursor(pCur); |  | 
|  278   sqlite3BtreeLeave(pBt); |  | 
|  279   ckfree((char *)pCur); |  | 
|  280   if( rc ){ |  | 
|  281     Tcl_AppendResult(interp, errorName(rc), 0); |  | 
|  282     return TCL_ERROR; |  | 
|  283   } |  | 
|  284   return SQLITE_OK; |  | 
|  285 } |  | 
|  286  |  | 
|  287 /* |  | 
|  288 ** Usage:   btree_next ID |  | 
|  289 ** |  | 
|  290 ** Move the cursor to the next entry in the table.  Return 0 on success |  | 
|  291 ** or 1 if the cursor was already on the last entry in the table or if |  | 
|  292 ** the table is empty. |  | 
|  293 */ |  | 
|  294 static int btree_next( |  | 
|  295   void *NotUsed, |  | 
|  296   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */ |  | 
|  297   int argc,              /* Number of arguments */ |  | 
|  298   const char **argv      /* Text of each argument */ |  | 
|  299 ){ |  | 
|  300   BtCursor *pCur; |  | 
|  301   int rc; |  | 
|  302   int res = 0; |  | 
|  303   char zBuf[100]; |  | 
|  304  |  | 
|  305   if( argc!=2 ){ |  | 
|  306     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |  | 
|  307        " ID\"", 0); |  | 
|  308     return TCL_ERROR; |  | 
|  309   } |  | 
|  310   pCur = sqlite3TestTextToPtr(argv[1]); |  | 
|  311   sqlite3BtreeEnter(pCur->pBtree); |  | 
|  312   rc = sqlite3BtreeNext(pCur, &res); |  | 
|  313   sqlite3BtreeLeave(pCur->pBtree); |  | 
|  314   if( rc ){ |  | 
|  315     Tcl_AppendResult(interp, errorName(rc), 0); |  | 
|  316     return TCL_ERROR; |  | 
|  317   } |  | 
|  318   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); |  | 
|  319   Tcl_AppendResult(interp, zBuf, 0); |  | 
|  320   return SQLITE_OK; |  | 
|  321 } |  | 
|  322  |  | 
|  323 /* |  | 
|  324 ** Usage:   btree_first ID |  | 
|  325 ** |  | 
|  326 ** Move the cursor to the first entry in the table.  Return 0 if the |  | 
|  327 ** cursor was left point to something and 1 if the table is empty. |  | 
|  328 */ |  | 
|  329 static int btree_first( |  | 
|  330   void *NotUsed, |  | 
|  331   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */ |  | 
|  332   int argc,              /* Number of arguments */ |  | 
|  333   const char **argv      /* Text of each argument */ |  | 
|  334 ){ |  | 
|  335   BtCursor *pCur; |  | 
|  336   int rc; |  | 
|  337   int res = 0; |  | 
|  338   char zBuf[100]; |  | 
|  339  |  | 
|  340   if( argc!=2 ){ |  | 
|  341     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |  | 
|  342        " ID\"", 0); |  | 
|  343     return TCL_ERROR; |  | 
|  344   } |  | 
|  345   pCur = sqlite3TestTextToPtr(argv[1]); |  | 
|  346   sqlite3BtreeEnter(pCur->pBtree); |  | 
|  347   rc = sqlite3BtreeFirst(pCur, &res); |  | 
|  348   sqlite3BtreeLeave(pCur->pBtree); |  | 
|  349   if( rc ){ |  | 
|  350     Tcl_AppendResult(interp, errorName(rc), 0); |  | 
|  351     return TCL_ERROR; |  | 
|  352   } |  | 
|  353   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); |  | 
|  354   Tcl_AppendResult(interp, zBuf, 0); |  | 
|  355   return SQLITE_OK; |  | 
|  356 } |  | 
|  357  |  | 
|  358 /* |  | 
|  359 ** Usage:   btree_eof ID |  | 
|  360 ** |  | 
|  361 ** Return TRUE if the given cursor is not pointing at a valid entry. |  | 
|  362 ** Return FALSE if the cursor does point to a valid entry. |  | 
|  363 */ |  | 
|  364 static int btree_eof( |  | 
|  365   void *NotUsed, |  | 
|  366   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */ |  | 
|  367   int argc,              /* Number of arguments */ |  | 
|  368   const char **argv      /* Text of each argument */ |  | 
|  369 ){ |  | 
|  370   BtCursor *pCur; |  | 
|  371   int rc; |  | 
|  372   char zBuf[50]; |  | 
|  373  |  | 
|  374   if( argc!=2 ){ |  | 
|  375     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |  | 
|  376        " ID\"", 0); |  | 
|  377     return TCL_ERROR; |  | 
|  378   } |  | 
|  379   pCur = sqlite3TestTextToPtr(argv[1]); |  | 
|  380   sqlite3BtreeEnter(pCur->pBtree); |  | 
|  381   rc = sqlite3BtreeEof(pCur); |  | 
|  382   sqlite3BtreeLeave(pCur->pBtree); |  | 
|  383   sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); |  | 
|  384   Tcl_AppendResult(interp, zBuf, 0); |  | 
|  385   return SQLITE_OK; |  | 
|  386 } |  | 
|  387  |  | 
|  388 /* |  | 
|  389 ** Usage:   btree_payload_size ID |  | 
|  390 ** |  | 
|  391 ** Return the number of bytes of payload |  | 
|  392 */ |  | 
|  393 static int btree_payload_size( |  | 
|  394   void *NotUsed, |  | 
|  395   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */ |  | 
|  396   int argc,              /* Number of arguments */ |  | 
|  397   const char **argv      /* Text of each argument */ |  | 
|  398 ){ |  | 
|  399   BtCursor *pCur; |  | 
|  400   int n2; |  | 
|  401   u64 n1; |  | 
|  402   char zBuf[50]; |  | 
|  403  |  | 
|  404   if( argc!=2 ){ |  | 
|  405     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |  | 
|  406        " ID\"", 0); |  | 
|  407     return TCL_ERROR; |  | 
|  408   } |  | 
|  409   pCur = sqlite3TestTextToPtr(argv[1]); |  | 
|  410   sqlite3BtreeEnter(pCur->pBtree); |  | 
|  411  |  | 
|  412   /* The cursor may be in "require-seek" state. If this is the case, the |  | 
|  413   ** call to BtreeDataSize() will fix it. */ |  | 
|  414   sqlite3BtreeDataSize(pCur, (u32*)&n2); |  | 
|  415   if( pCur->apPage[pCur->iPage]->intKey ){ |  | 
|  416     n1 = 0; |  | 
|  417   }else{ |  | 
|  418     sqlite3BtreeKeySize(pCur, (i64*)&n1); |  | 
|  419   } |  | 
|  420   sqlite3BtreeLeave(pCur->pBtree); |  | 
|  421   sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); |  | 
|  422   Tcl_AppendResult(interp, zBuf, 0); |  | 
|  423   return SQLITE_OK; |  | 
|  424 } |  | 
|  425  |  | 
|  426 /* |  | 
|  427 ** usage:   varint_test  START  MULTIPLIER  COUNT  INCREMENT |  | 
|  428 ** |  | 
|  429 ** This command tests the putVarint() and getVarint() |  | 
|  430 ** routines, both for accuracy and for speed. |  | 
|  431 ** |  | 
|  432 ** An integer is written using putVarint() and read back with |  | 
|  433 ** getVarint() and varified to be unchanged.  This repeats COUNT |  | 
|  434 ** times.  The first integer is START*MULTIPLIER.  Each iteration |  | 
|  435 ** increases the integer by INCREMENT. |  | 
|  436 ** |  | 
|  437 ** This command returns nothing if it works.  It returns an error message |  | 
|  438 ** if something goes wrong. |  | 
|  439 */ |  | 
|  440 static int btree_varint_test( |  | 
|  441   void *NotUsed, |  | 
|  442   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */ |  | 
|  443   int argc,              /* Number of arguments */ |  | 
|  444   const char **argv      /* Text of each argument */ |  | 
|  445 ){ |  | 
|  446   u32 start, mult, count, incr; |  | 
|  447   u64 in, out; |  | 
|  448   int n1, n2, i, j; |  | 
|  449   unsigned char zBuf[100]; |  | 
|  450   if( argc!=5 ){ |  | 
|  451     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |  | 
|  452        " START MULTIPLIER COUNT INCREMENT\"", 0); |  | 
|  453     return TCL_ERROR; |  | 
|  454   } |  | 
|  455   if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR; |  | 
|  456   if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR; |  | 
|  457   if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR; |  | 
|  458   if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR; |  | 
|  459   in = start; |  | 
|  460   in *= mult; |  | 
|  461   for(i=0; i<count; i++){ |  | 
|  462     char zErr[200]; |  | 
|  463     n1 = putVarint(zBuf, in); |  | 
|  464     if( n1>9 || n1<1 ){ |  | 
|  465       sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1); |  | 
|  466       Tcl_AppendResult(interp, zErr, 0); |  | 
|  467       return TCL_ERROR; |  | 
|  468     } |  | 
|  469     n2 = getVarint(zBuf, &out); |  | 
|  470     if( n1!=n2 ){ |  | 
|  471       sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2); |  | 
|  472       Tcl_AppendResult(interp, zErr, 0); |  | 
|  473       return TCL_ERROR; |  | 
|  474     } |  | 
|  475     if( in!=out ){ |  | 
|  476       sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out); |  | 
|  477       Tcl_AppendResult(interp, zErr, 0); |  | 
|  478       return TCL_ERROR; |  | 
|  479     } |  | 
|  480     if( (in & 0xffffffff)==in ){ |  | 
|  481       u32 out32; |  | 
|  482       n2 = getVarint32(zBuf, out32); |  | 
|  483       out = out32; |  | 
|  484       if( n1!=n2 ){ |  | 
|  485         sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",  |  | 
|  486                   n1, n2); |  | 
|  487         Tcl_AppendResult(interp, zErr, 0); |  | 
|  488         return TCL_ERROR; |  | 
|  489       } |  | 
|  490       if( in!=out ){ |  | 
|  491         sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", |  | 
|  492             in, out); |  | 
|  493         Tcl_AppendResult(interp, zErr, 0); |  | 
|  494         return TCL_ERROR; |  | 
|  495       } |  | 
|  496     } |  | 
|  497  |  | 
|  498     /* In order to get realistic timings, run getVarint 19 more times. |  | 
|  499     ** This is because getVarint is called about 20 times more often |  | 
|  500     ** than putVarint. |  | 
|  501     */ |  | 
|  502     for(j=0; j<19; j++){ |  | 
|  503       getVarint(zBuf, &out); |  | 
|  504     } |  | 
|  505     in += incr; |  | 
|  506   } |  | 
|  507   return TCL_OK; |  | 
|  508 } |  | 
|  509  |  | 
|  510 /* |  | 
|  511 ** usage:   btree_from_db  DB-HANDLE |  | 
|  512 ** |  | 
|  513 ** This command returns the btree handle for the main database associated |  | 
|  514 ** with the database-handle passed as the argument. Example usage: |  | 
|  515 ** |  | 
|  516 ** sqlite3 db test.db |  | 
|  517 ** set bt [btree_from_db db] |  | 
|  518 */ |  | 
|  519 static int btree_from_db( |  | 
|  520   void *NotUsed, |  | 
|  521   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */ |  | 
|  522   int argc,              /* Number of arguments */ |  | 
|  523   const char **argv      /* Text of each argument */ |  | 
|  524 ){ |  | 
|  525   char zBuf[100]; |  | 
|  526   Tcl_CmdInfo info; |  | 
|  527   sqlite3 *db; |  | 
|  528   Btree *pBt; |  | 
|  529   int iDb = 0; |  | 
|  530  |  | 
|  531   if( argc!=2 && argc!=3 ){ |  | 
|  532     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |  | 
|  533        " DB-HANDLE ?N?\"", 0); |  | 
|  534     return TCL_ERROR; |  | 
|  535   } |  | 
|  536  |  | 
|  537   if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){ |  | 
|  538     Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0); |  | 
|  539     return TCL_ERROR; |  | 
|  540   } |  | 
|  541   if( argc==3 ){ |  | 
|  542     iDb = atoi(argv[2]); |  | 
|  543   } |  | 
|  544  |  | 
|  545   db = *((sqlite3 **)info.objClientData); |  | 
|  546   assert( db ); |  | 
|  547  |  | 
|  548   pBt = db->aDb[iDb].pBt; |  | 
|  549   sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); |  | 
|  550   Tcl_SetResult(interp, zBuf, TCL_VOLATILE); |  | 
|  551   return TCL_OK; |  | 
|  552 } |  | 
|  553  |  | 
|  554 /* |  | 
|  555 ** Usage:   btree_ismemdb ID |  | 
|  556 ** |  | 
|  557 ** Return true if the B-Tree is in-memory. |  | 
|  558 */ |  | 
|  559 static int btree_ismemdb( |  | 
|  560   void *NotUsed, |  | 
|  561   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */ |  | 
|  562   int argc,              /* Number of arguments */ |  | 
|  563   const char **argv      /* Text of each argument */ |  | 
|  564 ){ |  | 
|  565   Btree *pBt; |  | 
|  566   int res; |  | 
|  567  |  | 
|  568   if( argc!=2 ){ |  | 
|  569     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |  | 
|  570        " ID\"", 0); |  | 
|  571     return TCL_ERROR; |  | 
|  572   } |  | 
|  573   pBt = sqlite3TestTextToPtr(argv[1]); |  | 
|  574   sqlite3_mutex_enter(pBt->db->mutex); |  | 
|  575   sqlite3BtreeEnter(pBt); |  | 
|  576   res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt)); |  | 
|  577   sqlite3BtreeLeave(pBt); |  | 
|  578   sqlite3_mutex_leave(pBt->db->mutex); |  | 
|  579   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res)); |  | 
|  580   return SQLITE_OK; |  | 
|  581 } |  | 
|  582  |  | 
|  583 /* |  | 
|  584 ** usage:   btree_set_cache_size ID NCACHE |  | 
|  585 ** |  | 
|  586 ** Set the size of the cache used by btree $ID. |  | 
|  587 */ |  | 
|  588 static int btree_set_cache_size( |  | 
|  589   void *NotUsed, |  | 
|  590   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */ |  | 
|  591   int argc,              /* Number of arguments */ |  | 
|  592   const char **argv      /* Text of each argument */ |  | 
|  593 ){ |  | 
|  594   int nCache; |  | 
|  595   Btree *pBt; |  | 
|  596    |  | 
|  597   if( argc!=3 ){ |  | 
|  598     Tcl_AppendResult( |  | 
|  599         interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0); |  | 
|  600     return TCL_ERROR; |  | 
|  601   } |  | 
|  602   pBt = sqlite3TestTextToPtr(argv[1]); |  | 
|  603   if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; |  | 
|  604  |  | 
|  605   sqlite3_mutex_enter(pBt->db->mutex); |  | 
|  606   sqlite3BtreeEnter(pBt); |  | 
|  607   sqlite3BtreeSetCacheSize(pBt, nCache); |  | 
|  608   sqlite3BtreeLeave(pBt); |  | 
|  609   sqlite3_mutex_leave(pBt->db->mutex); |  | 
|  610   return TCL_OK; |  | 
|  611 }       |  | 
|  612  |  | 
|  613  |  | 
|  614  |  | 
|  615 /* |  | 
|  616 ** Register commands with the TCL interpreter. |  | 
|  617 */ |  | 
|  618 int Sqlitetest3_Init(Tcl_Interp *interp){ |  | 
|  619   static struct { |  | 
|  620      char *zName; |  | 
|  621      Tcl_CmdProc *xProc; |  | 
|  622   } aCmd[] = { |  | 
|  623      { "btree_open",               (Tcl_CmdProc*)btree_open               }, |  | 
|  624      { "btree_close",              (Tcl_CmdProc*)btree_close              }, |  | 
|  625      { "btree_begin_transaction",  (Tcl_CmdProc*)btree_begin_transaction  }, |  | 
|  626      { "btree_pager_stats",        (Tcl_CmdProc*)btree_pager_stats        }, |  | 
|  627      { "btree_cursor",             (Tcl_CmdProc*)btree_cursor             }, |  | 
|  628      { "btree_close_cursor",       (Tcl_CmdProc*)btree_close_cursor       }, |  | 
|  629      { "btree_next",               (Tcl_CmdProc*)btree_next               }, |  | 
|  630      { "btree_eof",                (Tcl_CmdProc*)btree_eof                }, |  | 
|  631      { "btree_payload_size",       (Tcl_CmdProc*)btree_payload_size       }, |  | 
|  632      { "btree_first",              (Tcl_CmdProc*)btree_first              }, |  | 
|  633      { "btree_varint_test",        (Tcl_CmdProc*)btree_varint_test        }, |  | 
|  634      { "btree_from_db",            (Tcl_CmdProc*)btree_from_db            }, |  | 
|  635      { "btree_ismemdb",            (Tcl_CmdProc*)btree_ismemdb            }, |  | 
|  636      { "btree_set_cache_size",     (Tcl_CmdProc*)btree_set_cache_size     } |  | 
|  637   }; |  | 
|  638   int i; |  | 
|  639  |  | 
|  640   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ |  | 
|  641     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); |  | 
|  642   } |  | 
|  643  |  | 
|  644   return TCL_OK; |  | 
|  645 } |  | 
| OLD | NEW |