/*** 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_CACHErc = sqlite3BtreeLockTable(pBt, iTable, !!wrFlag);#endifif( 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);}#elserc = sqlite3BtreeCloseCursor(pCur);#endifckfree((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;}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。