| /* | |
| ** 2001 September 15 | |
| ** | |
| ** The author disclaims copyright to this source code. In place of | |
| ** a legal notice, here is a blessing: | |
| ** | |
| ** May you do good and not evil. | |
| ** May you find forgiveness for yourself and forgive others. | |
| ** May you share freely, never taking more than you give. | |
| ** | |
| ************************************************************************* | |
| ** Code for testing the btree.c module in SQLite. This code | |
| ** is not included in the SQLite library. It is used for automated | |
| ** testing of the SQLite library. | |
| */ | |
| #include "sqliteInt.h" | |
| #include "btreeInt.h" | |
| #if defined(INCLUDE_SQLITE_TCL_H) | |
| # include "sqlite_tcl.h" | |
| #else | |
| # include "tcl.h" | |
| #endif | |
| #include <stdlib.h> | |
| #include <string.h> | |
| extern const char *sqlite3ErrName(int); | |
| /* | |
| ** A bogus sqlite3 connection structure for use in the btree | |
| ** tests. | |
| */ | |
| static sqlite3 sDb; | |
| static int nRefSqlite3 = 0; | |
| /* | |
| ** Usage: btree_open FILENAME NCACHE | |
| ** | |
| ** Open a new database | |
| */ | |
| static int SQLITE_TCLAPI btree_open( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| Btree *pBt; | |
| int rc, nCache; | |
| char zBuf[100]; | |
| int n; | |
| char *zFilename; | |
| if( argc!=3 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " FILENAME NCACHE FLAGS\"", 0); | |
| return TCL_ERROR; | |
| } | |
| if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; | |
| nRefSqlite3++; | |
| if( nRefSqlite3==1 ){ | |
| sDb.pVfs = sqlite3_vfs_find(0); | |
| sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); | |
| sqlite3_mutex_enter(sDb.mutex); | |
| } | |
| n = (int)strlen(argv[1]); | |
| zFilename = sqlite3_malloc( n+2 ); | |
| if( zFilename==0 ) return TCL_ERROR; | |
| memcpy(zFilename, argv[1], n+1); | |
| zFilename[n+1] = 0; | |
| rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0, | |
| SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); | |
| sqlite3_free(zFilename); | |
| if( rc!=SQLITE_OK ){ | |
| Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
| return TCL_ERROR; | |
| } | |
| sqlite3BtreeSetCacheSize(pBt, nCache); | |
| sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt); | |
| Tcl_AppendResult(interp, zBuf, 0); | |
| return TCL_OK; | |
| } | |
| /* | |
| ** Usage: btree_close ID | |
| ** | |
| ** Close the given database. | |
| */ | |
| static int SQLITE_TCLAPI btree_close( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| Btree *pBt; | |
| int rc; | |
| if( argc!=2 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " ID\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pBt = sqlite3TestTextToPtr(argv[1]); | |
| rc = sqlite3BtreeClose(pBt); | |
| if( rc!=SQLITE_OK ){ | |
| Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
| return TCL_ERROR; | |
| } | |
| nRefSqlite3--; | |
| if( nRefSqlite3==0 ){ | |
| sqlite3_mutex_leave(sDb.mutex); | |
| sqlite3_mutex_free(sDb.mutex); | |
| sDb.mutex = 0; | |
| sDb.pVfs = 0; | |
| } | |
| return TCL_OK; | |
| } | |
| /* | |
| ** Usage: btree_begin_transaction ID | |
| ** | |
| ** Start a new transaction | |
| */ | |
| static int SQLITE_TCLAPI btree_begin_transaction( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| Btree *pBt; | |
| int rc; | |
| if( argc!=2 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " ID\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pBt = sqlite3TestTextToPtr(argv[1]); | |
| sqlite3BtreeEnter(pBt); | |
| rc = sqlite3BtreeBeginTrans(pBt, 1, 0); | |
| sqlite3BtreeLeave(pBt); | |
| if( rc!=SQLITE_OK ){ | |
| Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
| return TCL_ERROR; | |
| } | |
| return TCL_OK; | |
| } | |
| /* | |
| ** Usage: btree_pager_stats ID | |
| ** | |
| ** Returns pager statistics | |
| */ | |
| static int SQLITE_TCLAPI btree_pager_stats( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| Btree *pBt; | |
| int i; | |
| int *a; | |
| if( argc!=2 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " ID\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pBt = sqlite3TestTextToPtr(argv[1]); | |
| /* Normally in this file, with a b-tree handle opened using the | |
| ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly. | |
| ** But this function is sometimes called with a btree handle obtained | |
| ** from an open SQLite connection (using [btree_from_db]). In this case | |
| ** we need to obtain the mutex for the controlling SQLite handle before | |
| ** it is safe to call sqlite3BtreeEnter(). | |
| */ | |
| sqlite3_mutex_enter(pBt->db->mutex); | |
| sqlite3BtreeEnter(pBt); | |
| a = sqlite3PagerStats(sqlite3BtreePager(pBt)); | |
| for(i=0; i<11; i++){ | |
| static char *zName[] = { | |
| "ref", "page", "max", "size", "state", "err", | |
| "hit", "miss", "ovfl", "read", "write" | |
| }; | |
| char zBuf[100]; | |
| Tcl_AppendElement(interp, zName[i]); | |
| sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]); | |
| Tcl_AppendElement(interp, zBuf); | |
| } | |
| sqlite3BtreeLeave(pBt); | |
| /* Release the mutex on the SQLite handle that controls this b-tree */ | |
| sqlite3_mutex_leave(pBt->db->mutex); | |
| return TCL_OK; | |
| } | |
| /* | |
| ** Usage: btree_cursor ID TABLENUM WRITEABLE | |
| ** | |
| ** Create a new cursor. Return the ID for the cursor. | |
| */ | |
| static int SQLITE_TCLAPI btree_cursor( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| Btree *pBt; | |
| int iTable; | |
| BtCursor *pCur; | |
| int rc = SQLITE_OK; | |
| int wrFlag; | |
| char zBuf[30]; | |
| if( argc!=4 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " ID TABLENUM WRITEABLE\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pBt = sqlite3TestTextToPtr(argv[1]); | |
| if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; | |
| if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; | |
| if( wrFlag ) wrFlag = BTREE_WRCSR; | |
| pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize()); | |
| memset(pCur, 0, sqlite3BtreeCursorSize()); | |
| sqlite3_mutex_enter(pBt->db->mutex); | |
| sqlite3BtreeEnter(pBt); | |
| #ifndef SQLITE_OMIT_SHARED_CACHE | |
| rc = sqlite3BtreeLockTable(pBt, iTable, !!wrFlag); | |
| #endif | |
| if( rc==SQLITE_OK ){ | |
| rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); | |
| } | |
| sqlite3BtreeLeave(pBt); | |
| sqlite3_mutex_leave(pBt->db->mutex); | |
| if( rc ){ | |
| ckfree((char *)pCur); | |
| Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
| return TCL_ERROR; | |
| } | |
| sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); | |
| Tcl_AppendResult(interp, zBuf, 0); | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Usage: btree_close_cursor ID | |
| ** | |
| ** Close a cursor opened using btree_cursor. | |
| */ | |
| static int SQLITE_TCLAPI btree_close_cursor( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| BtCursor *pCur; | |
| int rc; | |
| if( argc!=2 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " ID\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pCur = sqlite3TestTextToPtr(argv[1]); | |
| #if SQLITE_THREADSAFE>0 | |
| { | |
| Btree *pBt = pCur->pBtree; | |
| sqlite3_mutex_enter(pBt->db->mutex); | |
| sqlite3BtreeEnter(pBt); | |
| rc = sqlite3BtreeCloseCursor(pCur); | |
| sqlite3BtreeLeave(pBt); | |
| sqlite3_mutex_leave(pBt->db->mutex); | |
| } | |
| #else | |
| rc = sqlite3BtreeCloseCursor(pCur); | |
| #endif | |
| ckfree((char *)pCur); | |
| if( rc ){ | |
| Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
| return TCL_ERROR; | |
| } | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Usage: btree_next ID | |
| ** | |
| ** Move the cursor to the next entry in the table. Return 0 on success | |
| ** or 1 if the cursor was already on the last entry in the table or if | |
| ** the table is empty. | |
| */ | |
| static int SQLITE_TCLAPI btree_next( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| BtCursor *pCur; | |
| int rc; | |
| int res = 0; | |
| char zBuf[100]; | |
| if( argc!=2 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " ID\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pCur = sqlite3TestTextToPtr(argv[1]); | |
| sqlite3BtreeEnter(pCur->pBtree); | |
| rc = sqlite3BtreeNext(pCur, 0); | |
| if( rc==SQLITE_DONE ){ | |
| res = 1; | |
| rc = SQLITE_OK; | |
| } | |
| sqlite3BtreeLeave(pCur->pBtree); | |
| if( rc ){ | |
| Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
| return TCL_ERROR; | |
| } | |
| sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); | |
| Tcl_AppendResult(interp, zBuf, 0); | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Usage: btree_first ID | |
| ** | |
| ** Move the cursor to the first entry in the table. Return 0 if the | |
| ** cursor was left point to something and 1 if the table is empty. | |
| */ | |
| static int SQLITE_TCLAPI btree_first( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| BtCursor *pCur; | |
| int rc; | |
| int res = 0; | |
| char zBuf[100]; | |
| if( argc!=2 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " ID\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pCur = sqlite3TestTextToPtr(argv[1]); | |
| sqlite3BtreeEnter(pCur->pBtree); | |
| rc = sqlite3BtreeFirst(pCur, &res); | |
| sqlite3BtreeLeave(pCur->pBtree); | |
| if( rc ){ | |
| Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
| return TCL_ERROR; | |
| } | |
| sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); | |
| Tcl_AppendResult(interp, zBuf, 0); | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Usage: btree_eof ID | |
| ** | |
| ** Return TRUE if the given cursor is not pointing at a valid entry. | |
| ** Return FALSE if the cursor does point to a valid entry. | |
| */ | |
| static int SQLITE_TCLAPI btree_eof( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| BtCursor *pCur; | |
| int rc; | |
| char zBuf[50]; | |
| if( argc!=2 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " ID\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pCur = sqlite3TestTextToPtr(argv[1]); | |
| sqlite3BtreeEnter(pCur->pBtree); | |
| rc = sqlite3BtreeEof(pCur); | |
| sqlite3BtreeLeave(pCur->pBtree); | |
| sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); | |
| Tcl_AppendResult(interp, zBuf, 0); | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Usage: btree_payload_size ID | |
| ** | |
| ** Return the number of bytes of payload | |
| */ | |
| static int SQLITE_TCLAPI btree_payload_size( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| BtCursor *pCur; | |
| u32 n; | |
| char zBuf[50]; | |
| if( argc!=2 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " ID\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pCur = sqlite3TestTextToPtr(argv[1]); | |
| sqlite3BtreeEnter(pCur->pBtree); | |
| n = sqlite3BtreePayloadSize(pCur); | |
| sqlite3BtreeLeave(pCur->pBtree); | |
| sqlite3_snprintf(sizeof(zBuf),zBuf, "%u", n); | |
| Tcl_AppendResult(interp, zBuf, 0); | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** usage: varint_test START MULTIPLIER COUNT INCREMENT | |
| ** | |
| ** This command tests the putVarint() and getVarint() | |
| ** routines, both for accuracy and for speed. | |
| ** | |
| ** An integer is written using putVarint() and read back with | |
| ** getVarint() and varified to be unchanged. This repeats COUNT | |
| ** times. The first integer is START*MULTIPLIER. Each iteration | |
| ** increases the integer by INCREMENT. | |
| ** | |
| ** This command returns nothing if it works. It returns an error message | |
| ** if something goes wrong. | |
| */ | |
| static int SQLITE_TCLAPI btree_varint_test( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| u32 start, mult, count, incr; | |
| u64 in, out; | |
| int n1, n2, i, j; | |
| unsigned char zBuf[100]; | |
| if( argc!=5 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " START MULTIPLIER COUNT INCREMENT\"", 0); | |
| return TCL_ERROR; | |
| } | |
| if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR; | |
| if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR; | |
| if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR; | |
| if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR; | |
| in = start; | |
| in *= mult; | |
| for(i=0; i<(int)count; i++){ | |
| char zErr[200]; | |
| n1 = putVarint(zBuf, in); | |
| if( n1>9 || n1<1 ){ | |
| sqlite3_snprintf(sizeof(zErr), zErr, | |
| "putVarint returned %d - should be between 1 and 9", n1); | |
| Tcl_AppendResult(interp, zErr, 0); | |
| return TCL_ERROR; | |
| } | |
| n2 = getVarint(zBuf, &out); | |
| if( n1!=n2 ){ | |
| sqlite3_snprintf(sizeof(zErr), zErr, | |
| "putVarint returned %d and getVarint returned %d", n1, n2); | |
| Tcl_AppendResult(interp, zErr, 0); | |
| return TCL_ERROR; | |
| } | |
| if( in!=out ){ | |
| sqlite3_snprintf(sizeof(zErr), zErr, | |
| "Wrote 0x%016llx and got back 0x%016llx", in, out); | |
| Tcl_AppendResult(interp, zErr, 0); | |
| return TCL_ERROR; | |
| } | |
| if( (in & 0xffffffff)==in ){ | |
| u32 out32; | |
| n2 = getVarint32(zBuf, out32); | |
| out = out32; | |
| if( n1!=n2 ){ | |
| sqlite3_snprintf(sizeof(zErr), zErr, | |
| "putVarint returned %d and GetVarint32 returned %d", | |
| n1, n2); | |
| Tcl_AppendResult(interp, zErr, 0); | |
| return TCL_ERROR; | |
| } | |
| if( in!=out ){ | |
| sqlite3_snprintf(sizeof(zErr), zErr, | |
| "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", | |
| in, out); | |
| Tcl_AppendResult(interp, zErr, 0); | |
| return TCL_ERROR; | |
| } | |
| } | |
| /* In order to get realistic timings, run getVarint 19 more times. | |
| ** This is because getVarint is called about 20 times more often | |
| ** than putVarint. | |
| */ | |
| for(j=0; j<19; j++){ | |
| getVarint(zBuf, &out); | |
| } | |
| in += incr; | |
| } | |
| return TCL_OK; | |
| } | |
| /* | |
| ** usage: btree_from_db DB-HANDLE | |
| ** | |
| ** This command returns the btree handle for the main database associated | |
| ** with the database-handle passed as the argument. Example usage: | |
| ** | |
| ** sqlite3 db test.db | |
| ** set bt [btree_from_db db] | |
| */ | |
| static int SQLITE_TCLAPI btree_from_db( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| char zBuf[100]; | |
| Tcl_CmdInfo info; | |
| sqlite3 *db; | |
| Btree *pBt; | |
| int iDb = 0; | |
| if( argc!=2 && argc!=3 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " DB-HANDLE ?N?\"", 0); | |
| return TCL_ERROR; | |
| } | |
| if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){ | |
| Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0); | |
| return TCL_ERROR; | |
| } | |
| if( argc==3 ){ | |
| iDb = atoi(argv[2]); | |
| } | |
| db = *((sqlite3 **)info.objClientData); | |
| assert( db ); | |
| pBt = db->aDb[iDb].pBt; | |
| sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); | |
| Tcl_SetResult(interp, zBuf, TCL_VOLATILE); | |
| return TCL_OK; | |
| } | |
| /* | |
| ** Usage: btree_ismemdb ID | |
| ** | |
| ** Return true if the B-Tree is currently stored entirely in memory. | |
| */ | |
| static int SQLITE_TCLAPI btree_ismemdb( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| Btree *pBt; | |
| int res; | |
| sqlite3_file *pFile; | |
| if( argc!=2 ){ | |
| Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
| " ID\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pBt = sqlite3TestTextToPtr(argv[1]); | |
| sqlite3_mutex_enter(pBt->db->mutex); | |
| sqlite3BtreeEnter(pBt); | |
| pFile = sqlite3PagerFile(sqlite3BtreePager(pBt)); | |
| res = (pFile->pMethods==0); | |
| sqlite3BtreeLeave(pBt); | |
| sqlite3_mutex_leave(pBt->db->mutex); | |
| Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res)); | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** usage: btree_set_cache_size ID NCACHE | |
| ** | |
| ** Set the size of the cache used by btree $ID. | |
| */ | |
| static int SQLITE_TCLAPI btree_set_cache_size( | |
| void *NotUsed, | |
| Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
| int argc, /* Number of arguments */ | |
| const char **argv /* Text of each argument */ | |
| ){ | |
| int nCache; | |
| Btree *pBt; | |
| if( argc!=3 ){ | |
| Tcl_AppendResult( | |
| interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0); | |
| return TCL_ERROR; | |
| } | |
| pBt = sqlite3TestTextToPtr(argv[1]); | |
| if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; | |
| sqlite3_mutex_enter(pBt->db->mutex); | |
| sqlite3BtreeEnter(pBt); | |
| sqlite3BtreeSetCacheSize(pBt, nCache); | |
| sqlite3BtreeLeave(pBt); | |
| sqlite3_mutex_leave(pBt->db->mutex); | |
| return TCL_OK; | |
| } | |
| /* | |
| ** usage: btree_insert CSR ?KEY? VALUE | |
| ** | |
| ** Set the size of the cache used by btree $ID. | |
| */ | |
| static int SQLITE_TCLAPI btree_insert( | |
| ClientData clientData, | |
| Tcl_Interp *interp, | |
| int objc, | |
| Tcl_Obj *const objv[] | |
| ){ | |
| BtCursor *pCur; | |
| int rc; | |
| BtreePayload x; | |
| if( objc!=4 && objc!=3 ){ | |
| Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE"); | |
| return TCL_ERROR; | |
| } | |
| memset(&x, 0, sizeof(x)); | |
| if( objc==4 ){ | |
| if( Tcl_GetIntFromObj(interp, objv[2], &rc) ) return TCL_ERROR; | |
| x.nKey = rc; | |
| x.pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &x.nData); | |
| }else{ | |
| x.pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &rc); | |
| x.nKey = rc; | |
| } | |
| pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); | |
| sqlite3_mutex_enter(pCur->pBtree->db->mutex); | |
| sqlite3BtreeEnter(pCur->pBtree); | |
| rc = sqlite3BtreeInsert(pCur, &x, 0, 0); | |
| sqlite3BtreeLeave(pCur->pBtree); | |
| sqlite3_mutex_leave(pCur->pBtree->db->mutex); | |
| Tcl_ResetResult(interp); | |
| if( rc ){ | |
| Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
| return TCL_ERROR; | |
| } | |
| return TCL_OK; | |
| } | |
| /* | |
| ** Register commands with the TCL interpreter. | |
| */ | |
| int Sqlitetest3_Init(Tcl_Interp *interp){ | |
| static struct { | |
| char *zName; | |
| Tcl_CmdProc *xProc; | |
| } aCmd[] = { | |
| { "btree_open", (Tcl_CmdProc*)btree_open }, | |
| { "btree_close", (Tcl_CmdProc*)btree_close }, | |
| { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, | |
| { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats }, | |
| { "btree_cursor", (Tcl_CmdProc*)btree_cursor }, | |
| { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor }, | |
| { "btree_next", (Tcl_CmdProc*)btree_next }, | |
| { "btree_eof", (Tcl_CmdProc*)btree_eof }, | |
| { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, | |
| { "btree_first", (Tcl_CmdProc*)btree_first }, | |
| { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test }, | |
| { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, | |
| { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb }, | |
| { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size } | |
| }; | |
| int i; | |
| for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ | |
| Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); | |
| } | |
| Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0); | |
| return TCL_OK; | |
| } |