diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 23 | ||||
-rw-r--r-- | src/btree.h | 7 | ||||
-rw-r--r-- | src/dbbemem.c | 8 | ||||
-rw-r--r-- | src/tclsqlite.c | 6 | ||||
-rw-r--r-- | src/test2.c | 416 | ||||
-rw-r--r-- | src/test3.c | 844 |
6 files changed, 1287 insertions, 17 deletions
diff --git a/src/btree.c b/src/btree.c index 46d2332a1..98410be63 100644 --- a/src/btree.c +++ b/src/btree.c @@ -21,7 +21,7 @@ ** http://www.hwaci.com/drh/ ** ************************************************************************* -** $Id: btree.c,v 1.20 2001/07/02 17:51:46 drh Exp $ +** $Id: btree.c,v 1.21 2001/08/20 00:33:58 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -1026,7 +1026,12 @@ int sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){ ** pages, then some other value might be returned to indicate the ** reason for the error. */ -static int compareKey(BtCursor *pCur, char *pKey, int nKeyOrig, int *pResult){ +static int compareKey( + BtCursor *pCur, /* Points to the entry against which we are comparing */ + const char *pKey, /* The comparison key */ + int nKeyOrig, /* Number of bytes in the comparison key */ + int *pResult /* Write the comparison results here */ +){ Pgno nextPage; int nKey = nKeyOrig; int n, c, rc; @@ -1178,7 +1183,7 @@ static int moveToLeftmost(BtCursor *pCur){ ** *pRes>0 The cursor is left pointing at an entry that ** is larger than pKey. */ -int sqliteBtreeMoveto(BtCursor *pCur, void *pKey, int nKey, int *pRes){ +int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){ int rc; pCur->bSkipNext = 0; rc = moveToRoot(pCur); @@ -1382,15 +1387,15 @@ static int clearCell(Btree *pBt, Cell *pCell){ static int fillInCell( Btree *pBt, /* The whole Btree. Needed to allocate pages */ Cell *pCell, /* Populate this Cell structure */ - void *pKey, int nKey, /* The key */ - void *pData,int nData /* The data */ + const void *pKey, int nKey, /* The key */ + const void *pData,int nData /* The data */ ){ OverflowPage *pOvfl, *pPrior; Pgno *pNext; int spaceLeft; int n, rc; int nPayload; - char *pPayload; + const char *pPayload; char *pSpace; pCell->h.leftChild = 0; @@ -1965,9 +1970,9 @@ balance_cleanup: ** is left pointing at the new record. */ int sqliteBtreeInsert( - BtCursor *pCur, /* Insert data into the table of this cursor */ - void *pKey, int nKey, /* The key of the new record */ - void *pData, int nData /* The data of the new record */ + BtCursor *pCur, /* Insert data into the table of this cursor */ + const void *pKey, int nKey, /* The key of the new record */ + const void *pData, int nData /* The data of the new record */ ){ Cell newCell; int rc; diff --git a/src/btree.h b/src/btree.h index 6c54b6708..2e98f4213 100644 --- a/src/btree.h +++ b/src/btree.h @@ -24,7 +24,7 @@ ** This header file defines the interface that the sqlite B-Tree file ** subsystem. ** -** @(#) $Id: btree.h,v 1.9 2001/07/02 17:51:46 drh Exp $ +** @(#) $Id: btree.h,v 1.10 2001/08/20 00:33:58 drh Exp $ */ typedef struct Btree Btree; @@ -42,9 +42,10 @@ int sqliteBtreeDropTable(Btree*, int); int sqliteBtreeClearTable(Btree*, int); int sqliteBtreeCursor(Btree*, int iTable, BtCursor **ppCur); -int sqliteBtreeMoveto(BtCursor*, void *pKey, int nKey, int *pRes); +int sqliteBtreeMoveto(BtCursor*, const void *pKey, int nKey, int *pRes); int sqliteBtreeDelete(BtCursor*); -int sqliteBtreeInsert(BtCursor*, void *pKey, int nKey, void *pData, int nData); +int sqliteBtreeInsert(BtCursor*, const void *pKey, int nKey, + const void *pData, int nData); int sqliteBtreeNext(BtCursor*, int *pRes); int sqliteBtreeKeySize(BtCursor*, int *pSize); int sqliteBtreeKey(BtCursor*, int offset, int amt, char *zBuf); diff --git a/src/dbbemem.c b/src/dbbemem.c index 54f18b228..95d731960 100644 --- a/src/dbbemem.c +++ b/src/dbbemem.c @@ -30,7 +30,7 @@ ** Nothing is ever written to disk using this backend. All information ** is forgotten when the program exits. ** -** $Id: dbbemem.c,v 1.16 2001/08/19 18:19:46 drh Exp $ +** $Id: dbbemem.c,v 1.17 2001/08/20 00:33:58 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -867,9 +867,9 @@ static struct DbbeMethods memoryMethods = { }; /* -** This routine opens a new database. For the GDBM driver -** implemented here, the database name is the name of the directory -** containing all the files of the database. +** This routine opens a new database. For the MEMORY driver +** implemented here, the database name is ignored. Every MEMORY database +** is unique and is erased when the database is closed. ** ** If successful, a pointer to the Dbbe structure is returned. ** If there are errors, an appropriate error message is left diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 95ae3c5c8..ade3ddb61 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -23,7 +23,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.21 2001/07/23 14:33:04 drh Exp $ +** $Id: tclsqlite.c,v 1.22 2001/08/20 00:33:58 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -510,8 +510,12 @@ int TCLSH_MAIN(int argc, char **argv){ #ifdef SQLITE_TEST { extern int Sqlitetest1_Init(Tcl_Interp*); + extern int Sqlitetest2_Init(Tcl_Interp*); + extern int Sqlitetest3_Init(Tcl_Interp*); extern int Md5_Init(Tcl_Interp*); Sqlitetest1_Init(interp); + Sqlitetest2_Init(interp); + Sqlitetest3_Init(interp); Md5_Init(interp); } #endif diff --git a/src/test2.c b/src/test2.c new file mode 100644 index 000000000..70e06eb97 --- /dev/null +++ b/src/test2.c @@ -0,0 +1,416 @@ +/* +** Copyright (c) 2001 D. Richard Hipp +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** +** You should have received a copy of the GNU General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +** +** Author contact information: +** drh@hwaci.com +** http://www.hwaci.com/drh/ +** +************************************************************************* +** Code for testing the pager.c module in SQLite. This code +** is not included in the SQLite library. It is used for automated +** testing of the SQLite library. +** +** $Id: test2.c,v 1.4 2001/08/20 00:33:58 drh Exp $ +*/ +#include "sqliteInt.h" +#include "pager.h" +#include "tcl.h" +#include <stdlib.h> +#include <string.h> + +/* +** Interpret an SQLite error number +*/ +static char *errorName(int rc){ + char *zName; + switch( rc ){ + case SQLITE_OK: zName = "SQLITE_OK"; break; + case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; + case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; + case SQLITE_PERM: zName = "SQLITE_PERM"; break; + case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; + case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; + case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; + case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; + case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; + case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; + case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; + case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; + case SQLITE_FULL: zName = "SQLITE_FULL"; break; + case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; + case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; + default: zName = "SQLITE_Unknown"; break; + } + return zName; +} + +/* +** Usage: pager_open FILENAME N-PAGE +** +** Open a new pager +*/ +static int pager_open( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Pager *pPager; + int nPage; + int rc; + char zBuf[100]; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " FILENAME N-PAGE\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR; + rc = sqlitepager_open(&pPager, argv[1], nPage, 0); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + sprintf(zBuf,"0x%x",(int)pPager); + Tcl_AppendResult(interp, zBuf, 0); + return TCL_OK; +} + +/* +** Usage: pager_close ID +** +** Close the given pager. +*/ +static int pager_close( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Pager *pPager; + int rc; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR; + rc = sqlitepager_close(pPager); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: pager_rollback ID +** +** Rollback changes +*/ +static int pager_rollback( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Pager *pPager; + int rc; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR; + rc = sqlitepager_rollback(pPager); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: pager_commit ID +** +** Commit all changes +*/ +static int pager_commit( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Pager *pPager; + int rc; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR; + rc = sqlitepager_commit(pPager); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: pager_stats ID +** +** Return pager statistics. +*/ +static int pager_stats( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Pager *pPager; + int i, *a; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR; + a = sqlitepager_stats(pPager); + for(i=0; i<9; i++){ + static char *zName[] = { + "ref", "page", "max", "size", "state", "err", + "hit", "miss", "ovfl", + }; + char zBuf[100]; + Tcl_AppendElement(interp, zName[i]); + sprintf(zBuf,"%d",a[i]); + Tcl_AppendElement(interp, zBuf); + } + return TCL_OK; +} + +/* +** Usage: pager_pagecount ID +** +** Return the size of the database file. +*/ +static int pager_pagecount( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Pager *pPager; + char zBuf[100]; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR; + sprintf(zBuf,"%d",sqlitepager_pagecount(pPager)); + Tcl_AppendResult(interp, zBuf, 0); + return TCL_OK; +} + +/* +** Usage: page_get ID PGNO +** +** Return a pointer to a page from the database. +*/ +static int page_get( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Pager *pPager; + char zBuf[100]; + void *pPage; + int pgno; + int rc; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID PGNO\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR; + if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; + rc = sqlitepager_get(pPager, pgno, &pPage); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + sprintf(zBuf,"0x%x",(int)pPage); + Tcl_AppendResult(interp, zBuf, 0); + return TCL_OK; +} + +/* +** Usage: page_lookup ID PGNO +** +** Return a pointer to a page if the page is already in cache. +** If not in cache, return an empty string. +*/ +static int page_lookup( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Pager *pPager; + char zBuf[100]; + void *pPage; + int pgno; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID PGNO\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR; + if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; + pPage = sqlitepager_lookup(pPager, pgno); + if( pPage ){ + sprintf(zBuf,"0x%x",(int)pPage); + Tcl_AppendResult(interp, zBuf, 0); + } + return TCL_OK; +} + +/* +** Usage: page_unref PAGE +** +** Drop a pointer to a page. +*/ +static int page_unref( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + void *pPage; + int rc; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " PAGE\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPage) ) return TCL_ERROR; + rc = sqlitepager_unref(pPage); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: page_read PAGE +** +** Return the content of a page +*/ +static int page_read( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + char zBuf[100]; + void *pPage; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " PAGE\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPage) ) return TCL_ERROR; + memcpy(zBuf, pPage, sizeof(zBuf)); + Tcl_AppendResult(interp, zBuf, 0); + return TCL_OK; +} + +/* +** Usage: page_number PAGE +** +** Return the page number for a page. +*/ +static int page_number( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + char zBuf[100]; + void *pPage; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " PAGE\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPage) ) return TCL_ERROR; + sprintf(zBuf, "%d", sqlitepager_pagenumber(pPage)); + Tcl_AppendResult(interp, zBuf, 0); + return TCL_OK; +} + +/* +** Usage: page_write PAGE DATA +** +** Write something into a page. +*/ +static int page_write( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + void *pPage; + int rc; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " PAGE DATA\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pPage) ) return TCL_ERROR; + rc = sqlitepager_write(pPage); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + strncpy((char*)pPage, argv[2], SQLITE_PAGE_SIZE-1); + ((char*)pPage)[SQLITE_PAGE_SIZE-1] = 0; + return TCL_OK; +} + +/* +** Register commands with the TCL interpreter. +*/ +int Sqlitetest2_Init(Tcl_Interp *interp){ + Tcl_CreateCommand(interp, "pager_open", pager_open, 0, 0); + Tcl_CreateCommand(interp, "pager_close", pager_close, 0, 0); + Tcl_CreateCommand(interp, "pager_commit", pager_commit, 0, 0); + Tcl_CreateCommand(interp, "pager_rollback", pager_rollback, 0, 0); + Tcl_CreateCommand(interp, "pager_stats", pager_stats, 0, 0); + Tcl_CreateCommand(interp, "pager_pagecount", pager_pagecount, 0, 0); + Tcl_CreateCommand(interp, "page_get", page_get, 0, 0); + Tcl_CreateCommand(interp, "page_lookup", page_lookup, 0, 0); + Tcl_CreateCommand(interp, "page_unref", page_unref, 0, 0); + Tcl_CreateCommand(interp, "page_read", page_read, 0, 0); + Tcl_CreateCommand(interp, "page_write", page_write, 0, 0); + Tcl_CreateCommand(interp, "page_number", page_number, 0, 0); + return TCL_OK; +} diff --git a/src/test3.c b/src/test3.c new file mode 100644 index 000000000..289c45e52 --- /dev/null +++ b/src/test3.c @@ -0,0 +1,844 @@ +/* +** Copyright (c) 2001 D. Richard Hipp +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public +** License as published by the Free Software Foundation; either +** version 2 of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** +** You should have received a copy of the GNU General Public +** License along with this library; if not, write to the +** Free Software Foundation, Inc., 59 Temple Place - Suite 330, +** Boston, MA 02111-1307, USA. +** +** Author contact information: +** drh@hwaci.com +** http://www.hwaci.com/drh/ +** +************************************************************************* +** 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. +** +** $Id: test3.c,v 1.9 2001/08/20 00:33:58 drh Exp $ +*/ +#include "sqliteInt.h" +#include "pager.h" +#include "btree.h" +#include "tcl.h" +#include <stdlib.h> +#include <string.h> + +/* +** Interpret an SQLite error number +*/ +static char *errorName(int rc){ + char *zName; + switch( rc ){ + case SQLITE_OK: zName = "SQLITE_OK"; break; + case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; + case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; + case SQLITE_PERM: zName = "SQLITE_PERM"; break; + case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; + case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; + case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; + case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; + case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; + case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; + case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; + case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; + case SQLITE_FULL: zName = "SQLITE_FULL"; break; + case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; + case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; + default: zName = "SQLITE_Unknown"; break; + } + return zName; +} + +/* +** Usage: btree_open FILENAME +** +** Open a new database +*/ +static int btree_open( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + int rc; + char zBuf[100]; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " FILENAME\"", 0); + return TCL_ERROR; + } + rc = sqliteBtreeOpen(argv[1], 0666, 10, &pBt); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + sprintf(zBuf,"0x%x",(int)pBt); + Tcl_AppendResult(interp, zBuf, 0); + return TCL_OK; +} + +/* +** Usage: btree_close ID +** +** Close the given database. +*/ +static int btree_close( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + 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; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + rc = sqliteBtreeClose(pBt); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: btree_begin_transaction ID +** +** Start a new transaction +*/ +static int btree_begin_transaction( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + 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; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + rc = sqliteBtreeBeginTrans(pBt); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: btree_rollback ID +** +** Rollback changes +*/ +static int btree_rollback( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + 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; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + rc = sqliteBtreeRollback(pBt); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: btree_commit ID +** +** Commit all changes +*/ +static int btree_commit( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + 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; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + rc = sqliteBtreeCommit(pBt); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: btree_create_table ID +** +** Create a new table in the database +*/ +static int btree_create_table( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + int rc, iTable; + char zBuf[30]; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + rc = sqliteBtreeCreateTable(pBt, &iTable); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + sprintf(zBuf, "%d", iTable); + Tcl_AppendResult(interp, zBuf, 0); + return TCL_OK; +} + +/* +** Usage: btree_drop_table ID TABLENUM +** +** Delete an entire table from the database +*/ +static int btree_drop_table( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + int iTable; + int rc; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID TABLENUM\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; + rc = sqliteBtreeDropTable(pBt, iTable); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: btree_clear_table ID TABLENUM +** +** Remove all entries from the given table but keep the table around. +*/ +static int btree_clear_table( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + int iTable; + int rc; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID TABLENUM\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; + rc = sqliteBtreeClearTable(pBt, iTable); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: btree_get_meta ID +** +** Return meta data +*/ +static int btree_get_meta( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + int rc; + int i; + int aMeta[SQLITE_N_BTREE_META]; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + rc = sqliteBtreeGetMeta(pBt, aMeta); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + for(i=0; i<SQLITE_N_BTREE_META; i++){ + char zBuf[30]; + sprintf(zBuf,"%d",aMeta[i]); + Tcl_AppendElement(interp, zBuf); + } + return TCL_OK; +} + +/* +** Usage: btree_update_meta ID METADATA... +** +** Return meta data +*/ +static int btree_update_meta( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + int rc; + int i; + int aMeta[SQLITE_N_BTREE_META]; + + if( argc!=2+SQLITE_N_BTREE_META ){ + char zBuf[30]; + sprintf(zBuf,"%d",SQLITE_N_BTREE_META); + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + for(i=0; i<SQLITE_N_BTREE_META; i++){ + if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR; + } + rc = sqliteBtreeUpdateMeta(pBt, aMeta); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: btree_page_dump ID PAGENUM +** +** Print a disassembly of a page on standard output +*/ +static int btree_page_dump( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + int iPage; + int rc; + + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; + rc = sqliteBtreePageDump(pBt, iPage, 0); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: btree_tree_dump ID PAGENUM +** +** Print a disassembly of a page and all its child pages on standard output +*/ +static int btree_tree_dump( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + int iPage; + int rc; + + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; + rc = sqliteBtreePageDump(pBt, iPage, 1); + if( rc!=SQLITE_OK ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} + +/* +** Usage: btree_pager_stats ID +** +** Returns pager statistics +*/ +static int btree_pager_stats( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + 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; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + a = sqlitepager_stats(sqliteBtreePager(pBt)); + for(i=0; i<9; i++){ + static char *zName[] = { + "ref", "page", "max", "size", "state", "err", + "hit", "miss", "ovfl", + }; + char zBuf[100]; + Tcl_AppendElement(interp, zName[i]); + sprintf(zBuf,"%d",a[i]); + Tcl_AppendElement(interp, zBuf); + } + return TCL_OK; +} + +/* +** Usage: btree_pager_ref_dump ID +** +** Print out all outstanding pages. +*/ +static int btree_pager_ref_dump( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + sqlitepager_refdump(sqliteBtreePager(pBt)); + return TCL_OK; +} + +/* +** Usage: btree_sanity_check ID ROOT ... +** +** Look through every page of the given BTree file to verify correct +** formatting and linkage. Return a line of text for each problem found. +** Return an empty string if everything worked. +*/ +static int btree_sanity_check( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + char *zResult; + int nRoot; + int *aRoot; + int i; + + if( argc<3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID ROOT ...\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + nRoot = argc-2; + aRoot = malloc( sizeof(int)*(argc-2) ); + for(i=0; i<argc-2; i++){ + if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR; + } + zResult = sqliteBtreeSanityCheck(pBt, aRoot, nRoot); + if( zResult ){ + Tcl_AppendResult(interp, zResult, 0); + free(zResult); + } + return TCL_OK; +} + +/* +** Usage: btree_cursor ID TABLENUM +** +** Create a new cursor. Return the ID for the cursor. +*/ +static int btree_cursor( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + Btree *pBt; + int iTable; + BtCursor *pCur; + int rc; + char zBuf[30]; + + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID TABLENUM\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; + if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; + rc = sqliteBtreeCursor(pBt, iTable, &pCur); + if( rc ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + sprintf(zBuf,"0x%x", (int)pCur); + Tcl_AppendResult(interp, zBuf, 0); + return SQLITE_OK; +} + +/* +** Usage: btree_close_cursor ID +** +** Close a cursor opened using btree_cursor. +*/ +static int btree_close_cursor( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + 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; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; + rc = sqliteBtreeCloseCursor(pCur); + if( rc ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return SQLITE_OK; +} + +/* +** Usage: btree_move_to ID KEY +** +** Move the cursor to the entry with the given key. +*/ +static int btree_move_to( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + BtCursor *pCur; + int rc; + int res; + char zBuf[20]; + + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID KEY\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; + rc = sqliteBtreeMoveto(pCur, argv[2], strlen(argv[2]), &res); + if( rc ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + sprintf(zBuf,"%d",res); + Tcl_AppendResult(interp, zBuf, 0); + return SQLITE_OK; +} + +/* +** Usage: btree_delete ID +** +** Delete the entry that the cursor is pointing to +*/ +static int btree_delete( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + 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; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; + rc = sqliteBtreeDelete(pCur); + if( rc ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return SQLITE_OK; +} + +/* +** Usage: btree_insert ID KEY DATA +** +** Create a new entry with the given key and data. If an entry already +** exists with the same key the old entry is overwritten. +*/ +static int btree_insert( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + BtCursor *pCur; + int rc; + + if( argc!=4 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID KEY DATA\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; + rc = sqliteBtreeInsert(pCur, argv[2], strlen(argv[2]), + argv[3], strlen(argv[3])); + if( rc ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return SQLITE_OK; +} + +/* +** Usage: btree_next ID +** +** Move the cursor to the next entry in the table. +*/ +static int btree_next( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + 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; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; + rc = sqliteBtreeNext(pCur, 0); + if( rc ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + return SQLITE_OK; +} + +/* +** Usage: btree_key ID +** +** Return the key for the entry at which the cursor is pointing. +*/ +static int btree_key( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + BtCursor *pCur; + int rc; + int n; + char *zBuf; + + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; + sqliteBtreeKeySize(pCur, &n); + zBuf = malloc( n+1 ); + rc = sqliteBtreeKey(pCur, 0, n, zBuf); + if( rc ){ + free(zBuf); + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + zBuf[n] = 0; + Tcl_AppendResult(interp, zBuf, 0); + free(zBuf); + return SQLITE_OK; +} + +/* +** Usage: btree_data ID +** +** Return the data for the entry at which the cursor is pointing. +*/ +static int btree_data( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + BtCursor *pCur; + int rc; + int n; + char *zBuf; + + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; + sqliteBtreeDataSize(pCur, &n); + zBuf = malloc( n+1 ); + rc = sqliteBtreeData(pCur, 0, n, zBuf); + if( rc ){ + free(zBuf); + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + zBuf[n] = 0; + Tcl_AppendResult(interp, zBuf, 0); + free(zBuf); + return SQLITE_OK; +} + +/* +** Usage: btree_cursor_dump ID +** +** Return eight integers containing information about the entry the +** cursor is pointing to: +** +** aResult[0] = The page number +** aResult[1] = The entry number +** aResult[2] = Total number of entries on this page +** aResult[3] = Size of this entry +** aResult[4] = Number of free bytes on this page +** aResult[5] = Number of free blocks on the page +** aResult[6] = Page number of the left child of this entry +** aResult[7] = Page number of the right child for the whole page +*/ +static int btree_cursor_dump( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + BtCursor *pCur; + int rc; + int i, j; + int aResult[8]; + char zBuf[400]; + + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " ID\"", 0); + return TCL_ERROR; + } + if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR; + rc = sqliteBtreeCursorDump(pCur, aResult); + if( rc ){ + Tcl_AppendResult(interp, errorName(rc), 0); + return TCL_ERROR; + } + j = 0; + for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){ + sprintf(&zBuf[j]," %d", aResult[i]); + j += strlen(&zBuf[j]); + } + Tcl_AppendResult(interp, &zBuf[1], 0); + return SQLITE_OK; +} + +/* +** Register commands with the TCL interpreter. +*/ +int Sqlitetest3_Init(Tcl_Interp *interp){ + Tcl_CreateCommand(interp, "btree_open", btree_open, 0, 0); + Tcl_CreateCommand(interp, "btree_close", btree_close, 0, 0); + Tcl_CreateCommand(interp, "btree_begin_transaction", + btree_begin_transaction, 0, 0); + Tcl_CreateCommand(interp, "btree_commit", btree_commit, 0, 0); + Tcl_CreateCommand(interp, "btree_rollback", btree_rollback, 0, 0); + Tcl_CreateCommand(interp, "btree_create_table", btree_create_table, 0, 0); + Tcl_CreateCommand(interp, "btree_drop_table", btree_drop_table, 0, 0); + Tcl_CreateCommand(interp, "btree_clear_table", btree_clear_table, 0, 0); + Tcl_CreateCommand(interp, "btree_get_meta", btree_get_meta, 0, 0); + Tcl_CreateCommand(interp, "btree_update_meta", btree_update_meta, 0, 0); + Tcl_CreateCommand(interp, "btree_page_dump", btree_page_dump, 0, 0); + Tcl_CreateCommand(interp, "btree_tree_dump", btree_tree_dump, 0, 0); + Tcl_CreateCommand(interp, "btree_pager_stats", btree_pager_stats, 0, 0); + Tcl_CreateCommand(interp, "btree_pager_ref_dump", btree_pager_ref_dump, 0, 0); + Tcl_CreateCommand(interp, "btree_cursor", btree_cursor, 0, 0); + Tcl_CreateCommand(interp, "btree_close_cursor", btree_close_cursor, 0, 0); + Tcl_CreateCommand(interp, "btree_move_to", btree_move_to, 0, 0); + Tcl_CreateCommand(interp, "btree_delete", btree_delete, 0, 0); + Tcl_CreateCommand(interp, "btree_insert", btree_insert, 0, 0); + Tcl_CreateCommand(interp, "btree_next", btree_next, 0, 0); + Tcl_CreateCommand(interp, "btree_key", btree_key, 0, 0); + Tcl_CreateCommand(interp, "btree_data", btree_data, 0, 0); + Tcl_CreateCommand(interp, "btree_cursor_dump", btree_cursor_dump, 0, 0); + Tcl_CreateCommand(interp, "btree_sanity_check", btree_sanity_check, 0, 0); + Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager_refinfo_enable, + TCL_LINK_INT); + return TCL_OK; +} |