2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A** 2001 September 15
2N/A**
2N/A** The author disclaims copyright to this source code. In place of
2N/A** a legal notice, here is a blessing:
2N/A**
2N/A** May you do good and not evil.
2N/A** May you find forgiveness for yourself and forgive others.
2N/A** May you share freely, never taking more than you give.
2N/A**
2N/A*************************************************************************
2N/A** Code for testing the btree.c module in SQLite. This code
2N/A** is not included in the SQLite library. It is used for automated
2N/A** testing of the SQLite library.
2N/A**
2N/A** $Id: test3.c,v 1.23 2003/04/13 18:26:52 paul Exp $
2N/A*/
2N/A#include "sqliteInt.h"
2N/A#include "pager.h"
2N/A#include "btree.h"
2N/A#include "tcl.h"
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A
2N/A/*
2N/A** Interpret an SQLite error number
2N/A*/
2N/Astatic char *errorName(int rc){
2N/A char *zName;
2N/A switch( rc ){
2N/A case SQLITE_OK: zName = "SQLITE_OK"; break;
2N/A case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
2N/A case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
2N/A case SQLITE_PERM: zName = "SQLITE_PERM"; break;
2N/A case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
2N/A case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
2N/A case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
2N/A case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
2N/A case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
2N/A case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
2N/A case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
2N/A case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
2N/A case SQLITE_FULL: zName = "SQLITE_FULL"; break;
2N/A case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
2N/A case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
2N/A default: zName = "SQLITE_Unknown"; break;
2N/A }
2N/A return zName;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_open FILENAME
2N/A**
2N/A** Open a new database
2N/A*/
2N/Astatic int btree_open(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int rc;
2N/A char zBuf[100];
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " FILENAME\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A rc = sqliteBtreeFactory(0, argv[1], 0, 1000, &pBt);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A sprintf(zBuf,"%p", pBt);
2N/A if( strncmp(zBuf,"0x",2) ){
2N/A sprintf(zBuf, "0x%p", pBt);
2N/A }
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_close ID
2N/A**
2N/A** Close the given database.
2N/A*/
2N/Astatic int btree_close(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int rc;
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A rc = sqliteBtreeClose(pBt);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_begin_transaction ID
2N/A**
2N/A** Start a new transaction
2N/A*/
2N/Astatic int btree_begin_transaction(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int rc;
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A rc = sqliteBtreeBeginTrans(pBt);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_rollback ID
2N/A**
2N/A** Rollback changes
2N/A*/
2N/Astatic int btree_rollback(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int rc;
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A rc = sqliteBtreeRollback(pBt);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_commit ID
2N/A**
2N/A** Commit all changes
2N/A*/
2N/Astatic int btree_commit(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int rc;
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A rc = sqliteBtreeCommit(pBt);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_create_table ID
2N/A**
2N/A** Create a new table in the database
2N/A*/
2N/Astatic int btree_create_table(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int rc, iTable;
2N/A char zBuf[30];
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A rc = sqliteBtreeCreateTable(pBt, &iTable);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A sprintf(zBuf, "%d", iTable);
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_drop_table ID TABLENUM
2N/A**
2N/A** Delete an entire table from the database
2N/A*/
2N/Astatic int btree_drop_table(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int iTable;
2N/A int rc;
2N/A if( argc!=3 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID TABLENUM\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
2N/A rc = sqliteBtreeDropTable(pBt, iTable);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_clear_table ID TABLENUM
2N/A**
2N/A** Remove all entries from the given table but keep the table around.
2N/A*/
2N/Astatic int btree_clear_table(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int iTable;
2N/A int rc;
2N/A if( argc!=3 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID TABLENUM\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
2N/A rc = sqliteBtreeClearTable(pBt, iTable);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_get_meta ID
2N/A**
2N/A** Return meta data
2N/A*/
2N/Astatic int btree_get_meta(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int rc;
2N/A int i;
2N/A int aMeta[SQLITE_N_BTREE_META];
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A rc = sqliteBtreeGetMeta(pBt, aMeta);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A for(i=0; i<SQLITE_N_BTREE_META; i++){
2N/A char zBuf[30];
2N/A sprintf(zBuf,"%d",aMeta[i]);
2N/A Tcl_AppendElement(interp, zBuf);
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_update_meta ID METADATA...
2N/A**
2N/A** Return meta data
2N/A*/
2N/Astatic int btree_update_meta(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int rc;
2N/A int i;
2N/A int aMeta[SQLITE_N_BTREE_META];
2N/A
2N/A if( argc!=2+SQLITE_N_BTREE_META ){
2N/A char zBuf[30];
2N/A sprintf(zBuf,"%d",SQLITE_N_BTREE_META);
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A for(i=0; i<SQLITE_N_BTREE_META; i++){
2N/A if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR;
2N/A }
2N/A rc = sqliteBtreeUpdateMeta(pBt, aMeta);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_page_dump ID PAGENUM
2N/A**
2N/A** Print a disassembly of a page on standard output
2N/A*/
2N/Astatic int btree_page_dump(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int iPage;
2N/A int rc;
2N/A
2N/A if( argc!=3 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR;
2N/A rc = sqliteBtreePageDump(pBt, iPage, 0);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_tree_dump ID PAGENUM
2N/A**
2N/A** Print a disassembly of a page and all its child pages on standard output
2N/A*/
2N/Astatic int btree_tree_dump(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int iPage;
2N/A int rc;
2N/A
2N/A if( argc!=3 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR;
2N/A rc = sqliteBtreePageDump(pBt, iPage, 1);
2N/A if( rc!=SQLITE_OK ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_pager_stats ID
2N/A**
2N/A** Returns pager statistics
2N/A*/
2N/Astatic int btree_pager_stats(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int i;
2N/A int *a;
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A a = sqlitepager_stats(sqliteBtreePager(pBt));
2N/A for(i=0; i<9; i++){
2N/A static char *zName[] = {
2N/A "ref", "page", "max", "size", "state", "err",
2N/A "hit", "miss", "ovfl",
2N/A };
2N/A char zBuf[100];
2N/A Tcl_AppendElement(interp, zName[i]);
2N/A sprintf(zBuf,"%d",a[i]);
2N/A Tcl_AppendElement(interp, zBuf);
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_pager_ref_dump ID
2N/A**
2N/A** Print out all outstanding pages.
2N/A*/
2N/Astatic int btree_pager_ref_dump(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A sqlitepager_refdump(sqliteBtreePager(pBt));
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_integrity_check ID ROOT ...
2N/A**
2N/A** Look through every page of the given BTree file to verify correct
2N/A** formatting and linkage. Return a line of text for each problem found.
2N/A** Return an empty string if everything worked.
2N/A*/
2N/Astatic int btree_integrity_check(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A char *zResult;
2N/A int nRoot;
2N/A int *aRoot;
2N/A int i;
2N/A
2N/A if( argc<3 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID ROOT ...\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A nRoot = argc-2;
2N/A aRoot = malloc( sizeof(int)*(argc-2) );
2N/A for(i=0; i<argc-2; i++){
2N/A if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
2N/A }
2N/A zResult = sqliteBtreeIntegrityCheck(pBt, aRoot, nRoot);
2N/A if( zResult ){
2N/A Tcl_AppendResult(interp, zResult, 0);
2N/A sqliteFree(zResult);
2N/A }
2N/A return TCL_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_cursor ID TABLENUM WRITEABLE
2N/A**
2N/A** Create a new cursor. Return the ID for the cursor.
2N/A*/
2N/Astatic int btree_cursor(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A Btree *pBt;
2N/A int iTable;
2N/A BtCursor *pCur;
2N/A int rc;
2N/A int wrFlag;
2N/A char zBuf[30];
2N/A
2N/A if( argc!=4 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID TABLENUM WRITEABLE\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
2N/A if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
2N/A if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
2N/A rc = sqliteBtreeCursor(pBt, iTable, wrFlag, &pCur);
2N/A if( rc ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A sprintf(zBuf,"0x%x", (int)pCur);
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_close_cursor ID
2N/A**
2N/A** Close a cursor opened using btree_cursor.
2N/A*/
2N/Astatic int btree_close_cursor(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A rc = sqliteBtreeCloseCursor(pCur);
2N/A if( rc ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_move_to ID KEY
2N/A**
2N/A** Move the cursor to the entry with the given key.
2N/A*/
2N/Astatic int btree_move_to(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A int res;
2N/A char zBuf[20];
2N/A
2N/A if( argc!=3 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID KEY\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A rc = sqliteBtreeMoveto(pCur, argv[2], strlen(argv[2]), &res);
2N/A if( rc ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( res<0 ) res = -1;
2N/A if( res>0 ) res = 1;
2N/A sprintf(zBuf,"%d",res);
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_delete ID
2N/A**
2N/A** Delete the entry that the cursor is pointing to
2N/A*/
2N/Astatic int btree_delete(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A rc = sqliteBtreeDelete(pCur);
2N/A if( rc ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_insert ID KEY DATA
2N/A**
2N/A** Create a new entry with the given key and data. If an entry already
2N/A** exists with the same key the old entry is overwritten.
2N/A*/
2N/Astatic int btree_insert(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A
2N/A if( argc!=4 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID KEY DATA\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A rc = sqliteBtreeInsert(pCur, argv[2], strlen(argv[2]),
2N/A argv[3], strlen(argv[3]));
2N/A if( rc ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_next ID
2N/A**
2N/A** Move the cursor to the next entry in the table. Return 0 on success
2N/A** or 1 if the cursor was already on the last entry in the table or if
2N/A** the table is empty.
2N/A*/
2N/Astatic int btree_next(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A int res = 0;
2N/A char zBuf[100];
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A rc = sqliteBtreeNext(pCur, &res);
2N/A if( rc ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A sprintf(zBuf,"%d",res);
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_prev ID
2N/A**
2N/A** Move the cursor to the previous entry in the table. Return 0 on
2N/A** success and 1 if the cursor was already on the first entry in
2N/A** the table or if the table was empty.
2N/A*/
2N/Astatic int btree_prev(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A int res = 0;
2N/A char zBuf[100];
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A rc = sqliteBtreePrevious(pCur, &res);
2N/A if( rc ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A sprintf(zBuf,"%d",res);
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_first ID
2N/A**
2N/A** Move the cursor to the first entry in the table. Return 0 if the
2N/A** cursor was left point to something and 1 if the table is empty.
2N/A*/
2N/Astatic int btree_first(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A int res = 0;
2N/A char zBuf[100];
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A rc = sqliteBtreeFirst(pCur, &res);
2N/A if( rc ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A sprintf(zBuf,"%d",res);
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_last ID
2N/A**
2N/A** Move the cursor to the last entry in the table. Return 0 if the
2N/A** cursor was left point to something and 1 if the table is empty.
2N/A*/
2N/Astatic int btree_last(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A int res = 0;
2N/A char zBuf[100];
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A rc = sqliteBtreeLast(pCur, &res);
2N/A if( rc ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A sprintf(zBuf,"%d",res);
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_key ID
2N/A**
2N/A** Return the key for the entry at which the cursor is pointing.
2N/A*/
2N/Astatic int btree_key(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A int n;
2N/A char *zBuf;
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A sqliteBtreeKeySize(pCur, &n);
2N/A zBuf = malloc( n+1 );
2N/A rc = sqliteBtreeKey(pCur, 0, n, zBuf);
2N/A if( rc!=n ){
2N/A char zMsg[100];
2N/A free(zBuf);
2N/A sprintf(zMsg, "truncated key: got %d of %d bytes", rc, n);
2N/A Tcl_AppendResult(interp, zMsg, 0);
2N/A return TCL_ERROR;
2N/A }
2N/A zBuf[n] = 0;
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A free(zBuf);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_data ID
2N/A**
2N/A** Return the data for the entry at which the cursor is pointing.
2N/A*/
2N/Astatic int btree_data(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A int n;
2N/A char *zBuf;
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A sqliteBtreeDataSize(pCur, &n);
2N/A zBuf = malloc( n+1 );
2N/A rc = sqliteBtreeData(pCur, 0, n, zBuf);
2N/A if( rc!=n ){
2N/A char zMsg[100];
2N/A free(zBuf);
2N/A sprintf(zMsg, "truncated data: got %d of %d bytes", rc, n);
2N/A Tcl_AppendResult(interp, zMsg, 0);
2N/A return TCL_ERROR;
2N/A }
2N/A zBuf[n] = 0;
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A free(zBuf);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_payload_size ID
2N/A**
2N/A** Return the number of bytes of payload
2N/A*/
2N/Astatic int btree_payload_size(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int n1, n2;
2N/A char zBuf[50];
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A sqliteBtreeKeySize(pCur, &n1);
2N/A sqliteBtreeDataSize(pCur, &n2);
2N/A sprintf(zBuf, "%d", n1+n2);
2N/A Tcl_AppendResult(interp, zBuf, 0);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Usage: btree_cursor_dump ID
2N/A**
2N/A** Return eight integers containing information about the entry the
2N/A** cursor is pointing to:
2N/A**
2N/A** aResult[0] = The page number
2N/A** aResult[1] = The entry number
2N/A** aResult[2] = Total number of entries on this page
2N/A** aResult[3] = Size of this entry
2N/A** aResult[4] = Number of free bytes on this page
2N/A** aResult[5] = Number of free blocks on the page
2N/A** aResult[6] = Page number of the left child of this entry
2N/A** aResult[7] = Page number of the right child for the whole page
2N/A*/
2N/Astatic int btree_cursor_dump(
2N/A void *NotUsed,
2N/A Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
2N/A int argc, /* Number of arguments */
2N/A const char **argv /* Text of each argument */
2N/A){
2N/A BtCursor *pCur;
2N/A int rc;
2N/A int i, j;
2N/A int aResult[8];
2N/A char zBuf[400];
2N/A
2N/A if( argc!=2 ){
2N/A Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2N/A " ID\"", 0);
2N/A return TCL_ERROR;
2N/A }
2N/A if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
2N/A rc = sqliteBtreeCursorDump(pCur, aResult);
2N/A if( rc ){
2N/A Tcl_AppendResult(interp, errorName(rc), 0);
2N/A return TCL_ERROR;
2N/A }
2N/A j = 0;
2N/A for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){
2N/A sprintf(&zBuf[j]," %d", aResult[i]);
2N/A j += strlen(&zBuf[j]);
2N/A }
2N/A Tcl_AppendResult(interp, &zBuf[1], 0);
2N/A return SQLITE_OK;
2N/A}
2N/A
2N/A/*
2N/A** Register commands with the TCL interpreter.
2N/A*/
2N/Aint Sqlitetest3_Init(Tcl_Interp *interp){
2N/A static struct {
2N/A char *zName;
2N/A Tcl_CmdProc *xProc;
2N/A } aCmd[] = {
2N/A { "btree_open", (Tcl_CmdProc*)btree_open },
2N/A { "btree_close", (Tcl_CmdProc*)btree_close },
2N/A { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction },
2N/A { "btree_commit", (Tcl_CmdProc*)btree_commit },
2N/A { "btree_rollback", (Tcl_CmdProc*)btree_rollback },
2N/A { "btree_create_table", (Tcl_CmdProc*)btree_create_table },
2N/A { "btree_drop_table", (Tcl_CmdProc*)btree_drop_table },
2N/A { "btree_clear_table", (Tcl_CmdProc*)btree_clear_table },
2N/A { "btree_get_meta", (Tcl_CmdProc*)btree_get_meta },
2N/A { "btree_update_meta", (Tcl_CmdProc*)btree_update_meta },
2N/A { "btree_page_dump", (Tcl_CmdProc*)btree_page_dump },
2N/A { "btree_tree_dump", (Tcl_CmdProc*)btree_tree_dump },
2N/A { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats },
2N/A { "btree_pager_ref_dump", (Tcl_CmdProc*)btree_pager_ref_dump },
2N/A { "btree_cursor", (Tcl_CmdProc*)btree_cursor },
2N/A { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor },
2N/A { "btree_move_to", (Tcl_CmdProc*)btree_move_to },
2N/A { "btree_delete", (Tcl_CmdProc*)btree_delete },
2N/A { "btree_insert", (Tcl_CmdProc*)btree_insert },
2N/A { "btree_next", (Tcl_CmdProc*)btree_next },
2N/A { "btree_prev", (Tcl_CmdProc*)btree_prev },
2N/A { "btree_key", (Tcl_CmdProc*)btree_key },
2N/A { "btree_data", (Tcl_CmdProc*)btree_data },
2N/A { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
2N/A { "btree_first", (Tcl_CmdProc*)btree_first },
2N/A { "btree_last", (Tcl_CmdProc*)btree_last },
2N/A { "btree_cursor_dump", (Tcl_CmdProc*)btree_cursor_dump },
2N/A { "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
2N/A };
2N/A int i;
2N/A
2N/A for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
2N/A Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
2N/A }
2N/A Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager_refinfo_enable,
2N/A TCL_LINK_INT);
2N/A Tcl_LinkVar(interp, "btree_native_byte_order",(char*)&btree_native_byte_order,
2N/A TCL_LINK_INT);
2N/A return TCL_OK;
2N/A}