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