xref: /sqlite-3.40.0/src/test3.c (revision bb2d9b1b)
15c4d9703Sdrh /*
2b19a2bc6Sdrh ** 2001 September 15
35c4d9703Sdrh **
4b19a2bc6Sdrh ** The author disclaims copyright to this source code.  In place of
5b19a2bc6Sdrh ** a legal notice, here is a blessing:
65c4d9703Sdrh **
7b19a2bc6Sdrh **    May you do good and not evil.
8b19a2bc6Sdrh **    May you find forgiveness for yourself and forgive others.
9b19a2bc6Sdrh **    May you share freely, never taking more than you give.
105c4d9703Sdrh **
115c4d9703Sdrh *************************************************************************
125c4d9703Sdrh ** Code for testing the btree.c module in SQLite.  This code
135c4d9703Sdrh ** is not included in the SQLite library.  It is used for automated
145c4d9703Sdrh ** testing of the SQLite library.
155c4d9703Sdrh */
165c4d9703Sdrh #include "sqliteInt.h"
17a1644fd8Sdanielk1977 #include "btreeInt.h"
1852b1dbb5Smistachkin #if defined(INCLUDE_SQLITE_TCL_H)
1952b1dbb5Smistachkin #  include "sqlite_tcl.h"
2052b1dbb5Smistachkin #else
215c4d9703Sdrh #  include "tcl.h"
2252b1dbb5Smistachkin #endif
235c4d9703Sdrh #include <stdlib.h>
245c4d9703Sdrh #include <string.h>
255c4d9703Sdrh 
26e84d8d32Smistachkin extern const char *sqlite3ErrName(int);
275c4d9703Sdrh 
285c4d9703Sdrh /*
29a2451e22Sdrh ** A bogus sqlite3 connection structure for use in the btree
30a2451e22Sdrh ** tests.
31a2451e22Sdrh */
32a2451e22Sdrh static sqlite3 sDb;
33a2451e22Sdrh static int nRefSqlite3 = 0;
34a2451e22Sdrh 
35a2451e22Sdrh /*
3675c014c3Sdrh ** Usage:   btree_open FILENAME NCACHE
375c4d9703Sdrh **
385c4d9703Sdrh ** Open a new database
395c4d9703Sdrh */
btree_open(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)407617e4a8Smistachkin static int SQLITE_TCLAPI btree_open(
415c4d9703Sdrh   void *NotUsed,
425c4d9703Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
435c4d9703Sdrh   int argc,              /* Number of arguments */
44c2eef3b3Sdrh   const char **argv      /* Text of each argument */
455c4d9703Sdrh ){
465c4d9703Sdrh   Btree *pBt;
4775c014c3Sdrh   int rc, nCache;
485c4d9703Sdrh   char zBuf[100];
49c02a43afSdrh   int n;
50c02a43afSdrh   char *zFilename;
5175c014c3Sdrh   if( argc!=3 ){
525c4d9703Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
5323e11cabSdrh        " FILENAME NCACHE FLAGS\"", 0);
545c4d9703Sdrh     return TCL_ERROR;
555c4d9703Sdrh   }
5623e11cabSdrh   if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
57a2451e22Sdrh   nRefSqlite3++;
58a2451e22Sdrh   if( nRefSqlite3==1 ){
59a2451e22Sdrh     sDb.pVfs = sqlite3_vfs_find(0);
6059f8c08eSdanielk1977     sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
6127641703Sdrh     sqlite3_mutex_enter(sDb.mutex);
62a2451e22Sdrh   }
6383cc1392Sdrh   n = (int)strlen(argv[1]);
64c02a43afSdrh   zFilename = sqlite3_malloc( n+2 );
65c02a43afSdrh   if( zFilename==0 ) return TCL_ERROR;
66c02a43afSdrh   memcpy(zFilename, argv[1], n+1);
67c02a43afSdrh   zFilename[n+1] = 0;
68c02a43afSdrh   rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0,
6933f4e02aSdrh      SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
70c02a43afSdrh   sqlite3_free(zFilename);
715c4d9703Sdrh   if( rc!=SQLITE_OK ){
72e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
735c4d9703Sdrh     return TCL_ERROR;
745c4d9703Sdrh   }
7590f5ecb3Sdrh   sqlite3BtreeSetCacheSize(pBt, nCache);
76fe63d1c9Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
775c4d9703Sdrh   Tcl_AppendResult(interp, zBuf, 0);
785c4d9703Sdrh   return TCL_OK;
795c4d9703Sdrh }
805c4d9703Sdrh 
815c4d9703Sdrh /*
825c4d9703Sdrh ** Usage:   btree_close ID
835c4d9703Sdrh **
845c4d9703Sdrh ** Close the given database.
855c4d9703Sdrh */
btree_close(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)867617e4a8Smistachkin static int SQLITE_TCLAPI btree_close(
875c4d9703Sdrh   void *NotUsed,
885c4d9703Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
895c4d9703Sdrh   int argc,              /* Number of arguments */
90c2eef3b3Sdrh   const char **argv      /* Text of each argument */
915c4d9703Sdrh ){
925c4d9703Sdrh   Btree *pBt;
935c4d9703Sdrh   int rc;
945c4d9703Sdrh   if( argc!=2 ){
955c4d9703Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
965c4d9703Sdrh        " ID\"", 0);
975c4d9703Sdrh     return TCL_ERROR;
985c4d9703Sdrh   }
99e8f52c50Sdrh   pBt = sqlite3TestTextToPtr(argv[1]);
10023e11cabSdrh   rc = sqlite3BtreeClose(pBt);
1015c4d9703Sdrh   if( rc!=SQLITE_OK ){
102e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
1035c4d9703Sdrh     return TCL_ERROR;
1045c4d9703Sdrh   }
105a2451e22Sdrh   nRefSqlite3--;
106a2451e22Sdrh   if( nRefSqlite3==0 ){
10727641703Sdrh     sqlite3_mutex_leave(sDb.mutex);
108a2451e22Sdrh     sqlite3_mutex_free(sDb.mutex);
109a2451e22Sdrh     sDb.mutex = 0;
110a2451e22Sdrh     sDb.pVfs = 0;
111a2451e22Sdrh   }
1125c4d9703Sdrh   return TCL_OK;
1135c4d9703Sdrh }
1145c4d9703Sdrh 
11527641703Sdrh 
1165c4d9703Sdrh /*
1175c4d9703Sdrh ** Usage:   btree_begin_transaction ID
1185c4d9703Sdrh **
1195c4d9703Sdrh ** Start a new transaction
1205c4d9703Sdrh */
btree_begin_transaction(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)1217617e4a8Smistachkin static int SQLITE_TCLAPI btree_begin_transaction(
1225c4d9703Sdrh   void *NotUsed,
1235c4d9703Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1245c4d9703Sdrh   int argc,              /* Number of arguments */
125c2eef3b3Sdrh   const char **argv      /* Text of each argument */
1265c4d9703Sdrh ){
1275c4d9703Sdrh   Btree *pBt;
1285c4d9703Sdrh   int rc;
1295c4d9703Sdrh   if( argc!=2 ){
1305c4d9703Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1315c4d9703Sdrh        " ID\"", 0);
1325c4d9703Sdrh     return TCL_ERROR;
1335c4d9703Sdrh   }
134e8f52c50Sdrh   pBt = sqlite3TestTextToPtr(argv[1]);
135ff0587c6Sdrh   sqlite3BtreeEnter(pBt);
136*bb2d9b1bSdrh   rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
137ff0587c6Sdrh   sqlite3BtreeLeave(pBt);
1385c4d9703Sdrh   if( rc!=SQLITE_OK ){
139e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
1405c4d9703Sdrh     return TCL_ERROR;
1415c4d9703Sdrh   }
1425c4d9703Sdrh   return TCL_OK;
1435c4d9703Sdrh }
1445c4d9703Sdrh 
1455c4d9703Sdrh /*
1465c4d9703Sdrh ** Usage:   btree_pager_stats ID
1475c4d9703Sdrh **
1485c4d9703Sdrh ** Returns pager statistics
1495c4d9703Sdrh */
btree_pager_stats(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)1507617e4a8Smistachkin static int SQLITE_TCLAPI btree_pager_stats(
1515c4d9703Sdrh   void *NotUsed,
1525c4d9703Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1535c4d9703Sdrh   int argc,              /* Number of arguments */
154c2eef3b3Sdrh   const char **argv      /* Text of each argument */
1555c4d9703Sdrh ){
1565c4d9703Sdrh   Btree *pBt;
1575c4d9703Sdrh   int i;
1585c4d9703Sdrh   int *a;
1595c4d9703Sdrh 
1605c4d9703Sdrh   if( argc!=2 ){
1615c4d9703Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1625c4d9703Sdrh        " ID\"", 0);
1635c4d9703Sdrh     return TCL_ERROR;
1645c4d9703Sdrh   }
165e8f52c50Sdrh   pBt = sqlite3TestTextToPtr(argv[1]);
166f3c62659Sdanielk1977 
167f3c62659Sdanielk1977   /* Normally in this file, with a b-tree handle opened using the
168f3c62659Sdanielk1977   ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
169f3c62659Sdanielk1977   ** But this function is sometimes called with a btree handle obtained
170f3c62659Sdanielk1977   ** from an open SQLite connection (using [btree_from_db]). In this case
171f3c62659Sdanielk1977   ** we need to obtain the mutex for the controlling SQLite handle before
172f3c62659Sdanielk1977   ** it is safe to call sqlite3BtreeEnter().
173f3c62659Sdanielk1977   */
174e5fe690dSdrh   sqlite3_mutex_enter(pBt->db->mutex);
175f3c62659Sdanielk1977 
17627641703Sdrh   sqlite3BtreeEnter(pBt);
1773b8a05f6Sdanielk1977   a = sqlite3PagerStats(sqlite3BtreePager(pBt));
17842741be9Sdanielk1977   for(i=0; i<11; i++){
1795c4d9703Sdrh     static char *zName[] = {
1805c4d9703Sdrh       "ref", "page", "max", "size", "state", "err",
18142741be9Sdanielk1977       "hit", "miss", "ovfl", "read", "write"
1825c4d9703Sdrh     };
1835c4d9703Sdrh     char zBuf[100];
1845c4d9703Sdrh     Tcl_AppendElement(interp, zName[i]);
185fe63d1c9Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
1865c4d9703Sdrh     Tcl_AppendElement(interp, zBuf);
1875c4d9703Sdrh   }
18827641703Sdrh   sqlite3BtreeLeave(pBt);
189f3c62659Sdanielk1977 
190f3c62659Sdanielk1977   /* Release the mutex on the SQLite handle that controls this b-tree */
191e5fe690dSdrh   sqlite3_mutex_leave(pBt->db->mutex);
1925c4d9703Sdrh   return TCL_OK;
1935c4d9703Sdrh }
1945c4d9703Sdrh 
1955c4d9703Sdrh /*
196ecdc7530Sdrh ** Usage:   btree_cursor ID TABLENUM WRITEABLE
1975c4d9703Sdrh **
1985c4d9703Sdrh ** Create a new cursor.  Return the ID for the cursor.
1995c4d9703Sdrh */
btree_cursor(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)2007617e4a8Smistachkin static int SQLITE_TCLAPI btree_cursor(
2015c4d9703Sdrh   void *NotUsed,
2025c4d9703Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
2035c4d9703Sdrh   int argc,              /* Number of arguments */
204c2eef3b3Sdrh   const char **argv      /* Text of each argument */
2055c4d9703Sdrh ){
2065c4d9703Sdrh   Btree *pBt;
2075c4d9703Sdrh   int iTable;
2085c4d9703Sdrh   BtCursor *pCur;
20993a696f6Sdan   int rc = SQLITE_OK;
210ecdc7530Sdrh   int wrFlag;
2115c4d9703Sdrh   char zBuf[30];
2125c4d9703Sdrh 
213ecdc7530Sdrh   if( argc!=4 ){
2145c4d9703Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
215ecdc7530Sdrh        " ID TABLENUM WRITEABLE\"", 0);
2165c4d9703Sdrh     return TCL_ERROR;
2175c4d9703Sdrh   }
218e8f52c50Sdrh   pBt = sqlite3TestTextToPtr(argv[1]);
2195c4d9703Sdrh   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
220ecdc7530Sdrh   if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
221fd261ec6Sdan   if( wrFlag ) wrFlag = BTREE_WRCSR;
222cd3e8f7cSdanielk1977   pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
223cd3e8f7cSdanielk1977   memset(pCur, 0, sqlite3BtreeCursorSize());
2246a75c8adSdan   sqlite3_mutex_enter(pBt->db->mutex);
225ff0587c6Sdrh   sqlite3BtreeEnter(pBt);
22693a696f6Sdan #ifndef SQLITE_OMIT_SHARED_CACHE
2276b513640Sdan   rc = sqlite3BtreeLockTable(pBt, iTable, !!wrFlag);
22893a696f6Sdan #endif
22996d48e96Sdanielk1977   if( rc==SQLITE_OK ){
230cd3e8f7cSdanielk1977     rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
23196d48e96Sdanielk1977   }
232ff0587c6Sdrh   sqlite3BtreeLeave(pBt);
2336a75c8adSdan   sqlite3_mutex_leave(pBt->db->mutex);
2345c4d9703Sdrh   if( rc ){
235cd3e8f7cSdanielk1977     ckfree((char *)pCur);
236e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
2375c4d9703Sdrh     return TCL_ERROR;
2385c4d9703Sdrh   }
239fe63d1c9Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
2405c4d9703Sdrh   Tcl_AppendResult(interp, zBuf, 0);
2415c4d9703Sdrh   return SQLITE_OK;
2425c4d9703Sdrh }
2435c4d9703Sdrh 
2445c4d9703Sdrh /*
2455c4d9703Sdrh ** Usage:   btree_close_cursor ID
2465c4d9703Sdrh **
2475c4d9703Sdrh ** Close a cursor opened using btree_cursor.
2485c4d9703Sdrh */
btree_close_cursor(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)2497617e4a8Smistachkin static int SQLITE_TCLAPI btree_close_cursor(
2505c4d9703Sdrh   void *NotUsed,
2515c4d9703Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
2525c4d9703Sdrh   int argc,              /* Number of arguments */
253c2eef3b3Sdrh   const char **argv      /* Text of each argument */
2545c4d9703Sdrh ){
2555c4d9703Sdrh   BtCursor *pCur;
2565c4d9703Sdrh   int rc;
2575c4d9703Sdrh 
2585c4d9703Sdrh   if( argc!=2 ){
2595c4d9703Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2605c4d9703Sdrh        " ID\"", 0);
2615c4d9703Sdrh     return TCL_ERROR;
2625c4d9703Sdrh   }
263e8f52c50Sdrh   pCur = sqlite3TestTextToPtr(argv[1]);
2642eb22af0Sdrh #if SQLITE_THREADSAFE>0
2652eb22af0Sdrh   {
2662eb22af0Sdrh     Btree *pBt = pCur->pBtree;
2676a75c8adSdan     sqlite3_mutex_enter(pBt->db->mutex);
268ff0587c6Sdrh     sqlite3BtreeEnter(pBt);
26923e11cabSdrh     rc = sqlite3BtreeCloseCursor(pCur);
270ff0587c6Sdrh     sqlite3BtreeLeave(pBt);
2716a75c8adSdan     sqlite3_mutex_leave(pBt->db->mutex);
2722eb22af0Sdrh   }
2732eb22af0Sdrh #else
2742eb22af0Sdrh   rc = sqlite3BtreeCloseCursor(pCur);
2752eb22af0Sdrh #endif
276cd3e8f7cSdanielk1977   ckfree((char *)pCur);
2775c4d9703Sdrh   if( rc ){
278e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
2795c4d9703Sdrh     return TCL_ERROR;
2805c4d9703Sdrh   }
2815c4d9703Sdrh   return SQLITE_OK;
2825c4d9703Sdrh }
2835c4d9703Sdrh 
2845c4d9703Sdrh /*
2855c4d9703Sdrh ** Usage:   btree_next ID
2865c4d9703Sdrh **
2872dcc9aa2Sdrh ** Move the cursor to the next entry in the table.  Return 0 on success
2882dcc9aa2Sdrh ** or 1 if the cursor was already on the last entry in the table or if
2892dcc9aa2Sdrh ** the table is empty.
2905c4d9703Sdrh */
btree_next(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)2917617e4a8Smistachkin static int SQLITE_TCLAPI btree_next(
2925c4d9703Sdrh   void *NotUsed,
2935c4d9703Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
2945c4d9703Sdrh   int argc,              /* Number of arguments */
295c2eef3b3Sdrh   const char **argv      /* Text of each argument */
2965c4d9703Sdrh ){
2975c4d9703Sdrh   BtCursor *pCur;
2985c4d9703Sdrh   int rc;
2990de8c112Sdrh   int res = 0;
3000de8c112Sdrh   char zBuf[100];
3015c4d9703Sdrh 
3025c4d9703Sdrh   if( argc!=2 ){
3035c4d9703Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
3045c4d9703Sdrh        " ID\"", 0);
3055c4d9703Sdrh     return TCL_ERROR;
3065c4d9703Sdrh   }
307e8f52c50Sdrh   pCur = sqlite3TestTextToPtr(argv[1]);
308ff0587c6Sdrh   sqlite3BtreeEnter(pCur->pBtree);
3092ab792e4Sdrh   rc = sqlite3BtreeNext(pCur, 0);
3102ab792e4Sdrh   if( rc==SQLITE_DONE ){
3112ab792e4Sdrh     res = 1;
3122ab792e4Sdrh     rc = SQLITE_OK;
3132ab792e4Sdrh   }
314ff0587c6Sdrh   sqlite3BtreeLeave(pCur->pBtree);
3155c4d9703Sdrh   if( rc ){
316e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
3175c4d9703Sdrh     return TCL_ERROR;
3185c4d9703Sdrh   }
319fe63d1c9Sdrh   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
3200de8c112Sdrh   Tcl_AppendResult(interp, zBuf, 0);
3210de8c112Sdrh   return SQLITE_OK;
3220de8c112Sdrh }
3230de8c112Sdrh 
3240de8c112Sdrh /*
3250de8c112Sdrh ** Usage:   btree_first ID
3260de8c112Sdrh **
3272dcc9aa2Sdrh ** Move the cursor to the first entry in the table.  Return 0 if the
3282dcc9aa2Sdrh ** cursor was left point to something and 1 if the table is empty.
3290de8c112Sdrh */
btree_first(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)3307617e4a8Smistachkin static int SQLITE_TCLAPI btree_first(
3310de8c112Sdrh   void *NotUsed,
3320de8c112Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
3330de8c112Sdrh   int argc,              /* Number of arguments */
334c2eef3b3Sdrh   const char **argv      /* Text of each argument */
3350de8c112Sdrh ){
3360de8c112Sdrh   BtCursor *pCur;
3370de8c112Sdrh   int rc;
3380de8c112Sdrh   int res = 0;
3390de8c112Sdrh   char zBuf[100];
3400de8c112Sdrh 
3410de8c112Sdrh   if( argc!=2 ){
3420de8c112Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
3430de8c112Sdrh        " ID\"", 0);
3440de8c112Sdrh     return TCL_ERROR;
3450de8c112Sdrh   }
346e8f52c50Sdrh   pCur = sqlite3TestTextToPtr(argv[1]);
347ff0587c6Sdrh   sqlite3BtreeEnter(pCur->pBtree);
3484fc0fb43Sdrh   rc = sqlite3BtreeFirst(pCur, &res);
349ff0587c6Sdrh   sqlite3BtreeLeave(pCur->pBtree);
3500de8c112Sdrh   if( rc ){
351e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
3520de8c112Sdrh     return TCL_ERROR;
3530de8c112Sdrh   }
354fe63d1c9Sdrh   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
3550de8c112Sdrh   Tcl_AppendResult(interp, zBuf, 0);
3565c4d9703Sdrh   return SQLITE_OK;
3575c4d9703Sdrh }
3585c4d9703Sdrh 
3595c4d9703Sdrh /*
360c39e000bSdrh ** Usage:   btree_eof ID
361c39e000bSdrh **
362c39e000bSdrh ** Return TRUE if the given cursor is not pointing at a valid entry.
363c39e000bSdrh ** Return FALSE if the cursor does point to a valid entry.
364c39e000bSdrh */
btree_eof(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)3657617e4a8Smistachkin static int SQLITE_TCLAPI btree_eof(
366c39e000bSdrh   void *NotUsed,
367c39e000bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
368c39e000bSdrh   int argc,              /* Number of arguments */
369c39e000bSdrh   const char **argv      /* Text of each argument */
370c39e000bSdrh ){
371c39e000bSdrh   BtCursor *pCur;
372ff0587c6Sdrh   int rc;
373c39e000bSdrh   char zBuf[50];
374c39e000bSdrh 
375c39e000bSdrh   if( argc!=2 ){
376c39e000bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
377c39e000bSdrh        " ID\"", 0);
378c39e000bSdrh     return TCL_ERROR;
379c39e000bSdrh   }
380e8f52c50Sdrh   pCur = sqlite3TestTextToPtr(argv[1]);
381ff0587c6Sdrh   sqlite3BtreeEnter(pCur->pBtree);
382ff0587c6Sdrh   rc = sqlite3BtreeEof(pCur);
383ff0587c6Sdrh   sqlite3BtreeLeave(pCur->pBtree);
384ff0587c6Sdrh   sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
385c39e000bSdrh   Tcl_AppendResult(interp, zBuf, 0);
386c39e000bSdrh   return SQLITE_OK;
387c39e000bSdrh }
388c39e000bSdrh 
389c39e000bSdrh /*
3900de8c112Sdrh ** Usage:   btree_payload_size ID
3910de8c112Sdrh **
3920de8c112Sdrh ** Return the number of bytes of payload
3930de8c112Sdrh */
btree_payload_size(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)3947617e4a8Smistachkin static int SQLITE_TCLAPI btree_payload_size(
3950de8c112Sdrh   void *NotUsed,
3960de8c112Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
3970de8c112Sdrh   int argc,              /* Number of arguments */
398c2eef3b3Sdrh   const char **argv      /* Text of each argument */
3990de8c112Sdrh ){
4000de8c112Sdrh   BtCursor *pCur;
401a7c90c42Sdrh   u32 n;
4020de8c112Sdrh   char zBuf[50];
4030de8c112Sdrh 
4040de8c112Sdrh   if( argc!=2 ){
4050de8c112Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
4060de8c112Sdrh        " ID\"", 0);
4070de8c112Sdrh     return TCL_ERROR;
4080de8c112Sdrh   }
409e8f52c50Sdrh   pCur = sqlite3TestTextToPtr(argv[1]);
410ff0587c6Sdrh   sqlite3BtreeEnter(pCur->pBtree);
411a7c90c42Sdrh   n = sqlite3BtreePayloadSize(pCur);
412ff0587c6Sdrh   sqlite3BtreeLeave(pCur->pBtree);
413a7c90c42Sdrh   sqlite3_snprintf(sizeof(zBuf),zBuf, "%u", n);
4140de8c112Sdrh   Tcl_AppendResult(interp, zBuf, 0);
4150de8c112Sdrh   return SQLITE_OK;
4160de8c112Sdrh }
4170de8c112Sdrh 
4180de8c112Sdrh /*
4196d2fb154Sdrh ** usage:   varint_test  START  MULTIPLIER  COUNT  INCREMENT
4206d2fb154Sdrh **
4213f8d5cfcSshane ** This command tests the putVarint() and getVarint()
4226d2fb154Sdrh ** routines, both for accuracy and for speed.
4236d2fb154Sdrh **
4243f8d5cfcSshane ** An integer is written using putVarint() and read back with
4253f8d5cfcSshane ** getVarint() and varified to be unchanged.  This repeats COUNT
4266d2fb154Sdrh ** times.  The first integer is START*MULTIPLIER.  Each iteration
4276d2fb154Sdrh ** increases the integer by INCREMENT.
4286d2fb154Sdrh **
4296d2fb154Sdrh ** This command returns nothing if it works.  It returns an error message
4306d2fb154Sdrh ** if something goes wrong.
4316d2fb154Sdrh */
btree_varint_test(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)4327617e4a8Smistachkin static int SQLITE_TCLAPI btree_varint_test(
4336d2fb154Sdrh   void *NotUsed,
4346d2fb154Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
4356d2fb154Sdrh   int argc,              /* Number of arguments */
4366d2fb154Sdrh   const char **argv      /* Text of each argument */
4376d2fb154Sdrh ){
4386d2fb154Sdrh   u32 start, mult, count, incr;
4396d2fb154Sdrh   u64 in, out;
440d8820e80Sdrh   int n1, n2, i, j;
4416d2fb154Sdrh   unsigned char zBuf[100];
4426d2fb154Sdrh   if( argc!=5 ){
4436d2fb154Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
4446d2fb154Sdrh        " START MULTIPLIER COUNT INCREMENT\"", 0);
4456d2fb154Sdrh     return TCL_ERROR;
4466d2fb154Sdrh   }
4476d2fb154Sdrh   if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
4486d2fb154Sdrh   if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
4496d2fb154Sdrh   if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
4506d2fb154Sdrh   if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
4516d2fb154Sdrh   in = start;
4526d2fb154Sdrh   in *= mult;
4537da5fcb0Sdrh   for(i=0; i<(int)count; i++){
454d8820e80Sdrh     char zErr[200];
4553f8d5cfcSshane     n1 = putVarint(zBuf, in);
4566d2fb154Sdrh     if( n1>9 || n1<1 ){
45765545b59Sdrh       sqlite3_snprintf(sizeof(zErr), zErr,
45865545b59Sdrh          "putVarint returned %d - should be between 1 and 9", n1);
459d8820e80Sdrh       Tcl_AppendResult(interp, zErr, 0);
4606d2fb154Sdrh       return TCL_ERROR;
4616d2fb154Sdrh     }
4623f8d5cfcSshane     n2 = getVarint(zBuf, &out);
4636d2fb154Sdrh     if( n1!=n2 ){
46465545b59Sdrh       sqlite3_snprintf(sizeof(zErr), zErr,
46565545b59Sdrh           "putVarint returned %d and getVarint returned %d", n1, n2);
466d8820e80Sdrh       Tcl_AppendResult(interp, zErr, 0);
4676d2fb154Sdrh       return TCL_ERROR;
4686d2fb154Sdrh     }
4696d2fb154Sdrh     if( in!=out ){
47065545b59Sdrh       sqlite3_snprintf(sizeof(zErr), zErr,
47165545b59Sdrh           "Wrote 0x%016llx and got back 0x%016llx", in, out);
472d8820e80Sdrh       Tcl_AppendResult(interp, zErr, 0);
4736d2fb154Sdrh       return TCL_ERROR;
4746d2fb154Sdrh     }
4759d213ef0Sdrh     if( (in & 0xffffffff)==in ){
4769d213ef0Sdrh       u32 out32;
4773f8d5cfcSshane       n2 = getVarint32(zBuf, out32);
4789d213ef0Sdrh       out = out32;
4799d213ef0Sdrh       if( n1!=n2 ){
48065545b59Sdrh         sqlite3_snprintf(sizeof(zErr), zErr,
48165545b59Sdrh           "putVarint returned %d and GetVarint32 returned %d",
4829d213ef0Sdrh                   n1, n2);
4839d213ef0Sdrh         Tcl_AppendResult(interp, zErr, 0);
4849d213ef0Sdrh         return TCL_ERROR;
4859d213ef0Sdrh       }
4869d213ef0Sdrh       if( in!=out ){
48765545b59Sdrh         sqlite3_snprintf(sizeof(zErr), zErr,
48865545b59Sdrh           "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
4899d213ef0Sdrh             in, out);
4909d213ef0Sdrh         Tcl_AppendResult(interp, zErr, 0);
4919d213ef0Sdrh         return TCL_ERROR;
4929d213ef0Sdrh       }
4939d213ef0Sdrh     }
494d8820e80Sdrh 
495d8820e80Sdrh     /* In order to get realistic timings, run getVarint 19 more times.
496d8820e80Sdrh     ** This is because getVarint is called about 20 times more often
497d8820e80Sdrh     ** than putVarint.
498d8820e80Sdrh     */
499d8820e80Sdrh     for(j=0; j<19; j++){
5003f8d5cfcSshane       getVarint(zBuf, &out);
501d8820e80Sdrh     }
5026d2fb154Sdrh     in += incr;
5036d2fb154Sdrh   }
5046d2fb154Sdrh   return TCL_OK;
5056d2fb154Sdrh }
5069b171277Sdrh 
5079b171277Sdrh /*
50842741be9Sdanielk1977 ** usage:   btree_from_db  DB-HANDLE
50942741be9Sdanielk1977 **
51042741be9Sdanielk1977 ** This command returns the btree handle for the main database associated
51142741be9Sdanielk1977 ** with the database-handle passed as the argument. Example usage:
51242741be9Sdanielk1977 **
51342741be9Sdanielk1977 ** sqlite3 db test.db
51442741be9Sdanielk1977 ** set bt [btree_from_db db]
51542741be9Sdanielk1977 */
btree_from_db(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)5167617e4a8Smistachkin static int SQLITE_TCLAPI btree_from_db(
51742741be9Sdanielk1977   void *NotUsed,
51842741be9Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
51942741be9Sdanielk1977   int argc,              /* Number of arguments */
52042741be9Sdanielk1977   const char **argv      /* Text of each argument */
52142741be9Sdanielk1977 ){
52242741be9Sdanielk1977   char zBuf[100];
52342741be9Sdanielk1977   Tcl_CmdInfo info;
52442741be9Sdanielk1977   sqlite3 *db;
52542741be9Sdanielk1977   Btree *pBt;
52663c64f3bSdanielk1977   int iDb = 0;
52742741be9Sdanielk1977 
52863c64f3bSdanielk1977   if( argc!=2 && argc!=3 ){
52942741be9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
53063c64f3bSdanielk1977        " DB-HANDLE ?N?\"", 0);
53142741be9Sdanielk1977     return TCL_ERROR;
53242741be9Sdanielk1977   }
53342741be9Sdanielk1977 
53442741be9Sdanielk1977   if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
53542741be9Sdanielk1977     Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
53642741be9Sdanielk1977     return TCL_ERROR;
53742741be9Sdanielk1977   }
53863c64f3bSdanielk1977   if( argc==3 ){
53963c64f3bSdanielk1977     iDb = atoi(argv[2]);
54063c64f3bSdanielk1977   }
54163c64f3bSdanielk1977 
54242741be9Sdanielk1977   db = *((sqlite3 **)info.objClientData);
54342741be9Sdanielk1977   assert( db );
54442741be9Sdanielk1977 
54563c64f3bSdanielk1977   pBt = db->aDb[iDb].pBt;
54642741be9Sdanielk1977   sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
54742741be9Sdanielk1977   Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
54842741be9Sdanielk1977   return TCL_OK;
54942741be9Sdanielk1977 }
55042741be9Sdanielk1977 
55117b90b53Sdanielk1977 /*
55217b90b53Sdanielk1977 ** Usage:   btree_ismemdb ID
55317b90b53Sdanielk1977 **
5549131ab93Sdan ** Return true if the B-Tree is currently stored entirely in memory.
55517b90b53Sdanielk1977 */
btree_ismemdb(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)5567617e4a8Smistachkin static int SQLITE_TCLAPI btree_ismemdb(
55717b90b53Sdanielk1977   void *NotUsed,
55817b90b53Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
55917b90b53Sdanielk1977   int argc,              /* Number of arguments */
56017b90b53Sdanielk1977   const char **argv      /* Text of each argument */
56117b90b53Sdanielk1977 ){
56217b90b53Sdanielk1977   Btree *pBt;
56317b90b53Sdanielk1977   int res;
5649131ab93Sdan   sqlite3_file *pFile;
56517b90b53Sdanielk1977 
56617b90b53Sdanielk1977   if( argc!=2 ){
56717b90b53Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
56817b90b53Sdanielk1977        " ID\"", 0);
56917b90b53Sdanielk1977     return TCL_ERROR;
57017b90b53Sdanielk1977   }
571e8f52c50Sdrh   pBt = sqlite3TestTextToPtr(argv[1]);
57217b90b53Sdanielk1977   sqlite3_mutex_enter(pBt->db->mutex);
57317b90b53Sdanielk1977   sqlite3BtreeEnter(pBt);
5749131ab93Sdan   pFile = sqlite3PagerFile(sqlite3BtreePager(pBt));
5759131ab93Sdan   res = (pFile->pMethods==0);
57617b90b53Sdanielk1977   sqlite3BtreeLeave(pBt);
57717b90b53Sdanielk1977   sqlite3_mutex_leave(pBt->db->mutex);
57817b90b53Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
57917b90b53Sdanielk1977   return SQLITE_OK;
58017b90b53Sdanielk1977 }
58117b90b53Sdanielk1977 
5823054866cSdanielk1977 /*
5833054866cSdanielk1977 ** usage:   btree_set_cache_size ID NCACHE
5843054866cSdanielk1977 **
5853054866cSdanielk1977 ** Set the size of the cache used by btree $ID.
5863054866cSdanielk1977 */
btree_set_cache_size(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)5877617e4a8Smistachkin static int SQLITE_TCLAPI btree_set_cache_size(
5883054866cSdanielk1977   void *NotUsed,
5893054866cSdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5903054866cSdanielk1977   int argc,              /* Number of arguments */
5913054866cSdanielk1977   const char **argv      /* Text of each argument */
5923054866cSdanielk1977 ){
5933054866cSdanielk1977   int nCache;
5943054866cSdanielk1977   Btree *pBt;
5953054866cSdanielk1977 
5963054866cSdanielk1977   if( argc!=3 ){
5973054866cSdanielk1977     Tcl_AppendResult(
5983054866cSdanielk1977         interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0);
5993054866cSdanielk1977     return TCL_ERROR;
6003054866cSdanielk1977   }
6013054866cSdanielk1977   pBt = sqlite3TestTextToPtr(argv[1]);
6023054866cSdanielk1977   if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
6033054866cSdanielk1977 
6043054866cSdanielk1977   sqlite3_mutex_enter(pBt->db->mutex);
6053054866cSdanielk1977   sqlite3BtreeEnter(pBt);
6063054866cSdanielk1977   sqlite3BtreeSetCacheSize(pBt, nCache);
6073054866cSdanielk1977   sqlite3BtreeLeave(pBt);
6083054866cSdanielk1977   sqlite3_mutex_leave(pBt->db->mutex);
6093054866cSdanielk1977   return TCL_OK;
6103054866cSdanielk1977 }
6113054866cSdanielk1977 
6126b513640Sdan /*
6136b513640Sdan ** usage:   btree_insert CSR ?KEY? VALUE
6146b513640Sdan **
6156b513640Sdan ** Set the size of the cache used by btree $ID.
6166b513640Sdan */
btree_insert(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])6177617e4a8Smistachkin static int SQLITE_TCLAPI btree_insert(
6186b513640Sdan   ClientData clientData,
6196b513640Sdan   Tcl_Interp *interp,
6206b513640Sdan   int objc,
6216b513640Sdan   Tcl_Obj *const objv[]
6226b513640Sdan ){
6236b513640Sdan   BtCursor *pCur;
6246b513640Sdan   int rc;
6258eeb4463Sdrh   BtreePayload x;
6266b513640Sdan 
6276b513640Sdan   if( objc!=4 && objc!=3 ){
6286b513640Sdan     Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE");
6296b513640Sdan     return TCL_ERROR;
6306b513640Sdan   }
6316b513640Sdan 
6328eeb4463Sdrh   memset(&x, 0, sizeof(x));
6336b513640Sdan   if( objc==4 ){
6348eeb4463Sdrh     if( Tcl_GetIntFromObj(interp, objv[2], &rc) ) return TCL_ERROR;
6358eeb4463Sdrh     x.nKey = rc;
6368eeb4463Sdrh     x.pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &x.nData);
6376b513640Sdan   }else{
6388eeb4463Sdrh     x.pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &rc);
6398eeb4463Sdrh     x.nKey = rc;
6406b513640Sdan   }
6416b513640Sdan   pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
6426b513640Sdan 
6436a75c8adSdan   sqlite3_mutex_enter(pCur->pBtree->db->mutex);
6446b513640Sdan   sqlite3BtreeEnter(pCur->pBtree);
6458eeb4463Sdrh   rc = sqlite3BtreeInsert(pCur, &x, 0, 0);
6466b513640Sdan   sqlite3BtreeLeave(pCur->pBtree);
6476a75c8adSdan   sqlite3_mutex_leave(pCur->pBtree->db->mutex);
6486b513640Sdan 
6496b513640Sdan   Tcl_ResetResult(interp);
6506b513640Sdan   if( rc ){
6516b513640Sdan     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
6526b513640Sdan     return TCL_ERROR;
6536b513640Sdan   }
6546b513640Sdan   return TCL_OK;
6556b513640Sdan }
6563054866cSdanielk1977 
6571ad7f64aSdanielk1977 
65842741be9Sdanielk1977 /*
6595c4d9703Sdrh ** Register commands with the TCL interpreter.
6605c4d9703Sdrh */
Sqlitetest3_Init(Tcl_Interp * interp)6615c4d9703Sdrh int Sqlitetest3_Init(Tcl_Interp *interp){
662c2eef3b3Sdrh   static struct {
663c2eef3b3Sdrh      char *zName;
664c2eef3b3Sdrh      Tcl_CmdProc *xProc;
665c2eef3b3Sdrh   } aCmd[] = {
666c2eef3b3Sdrh      { "btree_open",               (Tcl_CmdProc*)btree_open               },
667c2eef3b3Sdrh      { "btree_close",              (Tcl_CmdProc*)btree_close              },
668c2eef3b3Sdrh      { "btree_begin_transaction",  (Tcl_CmdProc*)btree_begin_transaction  },
669c2eef3b3Sdrh      { "btree_pager_stats",        (Tcl_CmdProc*)btree_pager_stats        },
670c2eef3b3Sdrh      { "btree_cursor",             (Tcl_CmdProc*)btree_cursor             },
671c2eef3b3Sdrh      { "btree_close_cursor",       (Tcl_CmdProc*)btree_close_cursor       },
672c2eef3b3Sdrh      { "btree_next",               (Tcl_CmdProc*)btree_next               },
673c39e000bSdrh      { "btree_eof",                (Tcl_CmdProc*)btree_eof                },
674c2eef3b3Sdrh      { "btree_payload_size",       (Tcl_CmdProc*)btree_payload_size       },
675c2eef3b3Sdrh      { "btree_first",              (Tcl_CmdProc*)btree_first              },
6766d2fb154Sdrh      { "btree_varint_test",        (Tcl_CmdProc*)btree_varint_test        },
67742741be9Sdanielk1977      { "btree_from_db",            (Tcl_CmdProc*)btree_from_db            },
6783054866cSdanielk1977      { "btree_ismemdb",            (Tcl_CmdProc*)btree_ismemdb            },
6793054866cSdanielk1977      { "btree_set_cache_size",     (Tcl_CmdProc*)btree_set_cache_size     }
680c2eef3b3Sdrh   };
681c2eef3b3Sdrh   int i;
682c2eef3b3Sdrh 
683c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
684c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
685c2eef3b3Sdrh   }
686312d6b36Sdanielk1977 
6876b513640Sdan   Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0);
6886b513640Sdan 
6895c4d9703Sdrh   return TCL_OK;
6905c4d9703Sdrh }
691