📄 tcl_db.c
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1999-2002 * Sleepycat Software. All rights reserved. */#include "db_config.h"#ifndef lintstatic const char revid[] = "$Id: tcl_db.c,v 11.107 2002/08/06 06:20:31 bostic Exp $";#endif /* not lint */#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#include <stdlib.h>#include <string.h>#include <tcl.h>#endif#include "db_int.h"#include "dbinc/db_page.h"#include "dbinc/db_am.h"#include "dbinc/tcl_db.h"/* * Prototypes for procedures defined later in this file: */static int tcl_DbAssociate __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));static int tcl_DbClose __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *, DBTCL_INFO *));static int tcl_DbDelete __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));static int tcl_DbGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *, int));static int tcl_DbKeyRange __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));static int tcl_DbPut __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));static int tcl_DbStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));static int tcl_DbTruncate __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));static int tcl_DbCursor __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *, DBC **));static int tcl_DbJoin __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *, DBC **));static int tcl_DbGetjoin __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));static int tcl_DbCount __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));static int tcl_second_call __P((DB *, const DBT *, const DBT *, DBT *));/* * _DbInfoDelete -- * * PUBLIC: void _DbInfoDelete __P((Tcl_Interp *, DBTCL_INFO *)); */void_DbInfoDelete(interp, dbip) Tcl_Interp *interp; DBTCL_INFO *dbip;{ DBTCL_INFO *nextp, *p; /* * First we have to close any open cursors. Then we close * our db. */ for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) { nextp = LIST_NEXT(p, entries); /* * Check if this is a cursor info structure and if * it is, if it belongs to this DB. If so, remove * its commands and info structure. */ if (p->i_parent == dbip && p->i_type == I_DBC) { (void)Tcl_DeleteCommand(interp, p->i_name); _DeleteInfo(p); } } (void)Tcl_DeleteCommand(interp, dbip->i_name); _DeleteInfo(dbip);}/* * * PUBLIC: int db_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); * * db_Cmd -- * Implements the "db" widget. */intdb_Cmd(clientData, interp, objc, objv) ClientData clientData; /* DB handle */ Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */{ static char *dbcmds[] = {#if CONFIG_TEST "keyrange", "pget", "rpcid", "test",#endif "associate", "close", "count", "cursor", "del", "get", "get_join", "get_type", "is_byteswapped", "join", "put", "stat", "sync", "truncate", NULL }; enum dbcmds {#if CONFIG_TEST DBKEYRANGE, DBPGET, DBRPCID, DBTEST,#endif DBASSOCIATE, DBCLOSE, DBCOUNT, DBCURSOR, DBDELETE, DBGET, DBGETJOIN, DBGETTYPE, DBSWAPPED, DBJOIN, DBPUT, DBSTAT, DBSYNC, DBTRUNCATE }; DB *dbp; DBC *dbc; DBTCL_INFO *dbip; DBTCL_INFO *ip; DBTYPE type; Tcl_Obj *res; int cmdindex, isswapped, result, ret; char newname[MSG_SIZE]; Tcl_ResetResult(interp); dbp = (DB *)clientData; dbip = _PtrToInfo((void *)dbp); memset(newname, 0, MSG_SIZE); result = TCL_OK; if (objc <= 1) { Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs"); return (TCL_ERROR); } if (dbp == NULL) { Tcl_SetResult(interp, "NULL db pointer", TCL_STATIC); return (TCL_ERROR); } if (dbip == NULL) { Tcl_SetResult(interp, "NULL db info pointer", TCL_STATIC); return (TCL_ERROR); } /* * Get the command name index from the object based on the dbcmds * defined above. */ if (Tcl_GetIndexFromObj(interp, objv[1], dbcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) return (IS_HELP(objv[1])); res = NULL; switch ((enum dbcmds)cmdindex) {#if CONFIG_TEST case DBKEYRANGE: result = tcl_DbKeyRange(interp, objc, objv, dbp); break; case DBPGET: result = tcl_DbGet(interp, objc, objv, dbp, 1); break; case DBRPCID: /* * No args for this. Error if there are some. */ if (objc > 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return (TCL_ERROR); } /* * !!! Retrieve the client ID from the dbp handle directly. * This is for testing purposes only. It is dbp-private data. */ res = Tcl_NewLongObj(dbp->cl_id); break; case DBTEST: result = tcl_EnvTest(interp, objc, objv, dbp->dbenv); break;#endif case DBASSOCIATE: result = tcl_DbAssociate(interp, objc, objv, dbp); break; case DBCLOSE: result = tcl_DbClose(interp, objc, objv, dbp, dbip); break; case DBDELETE: result = tcl_DbDelete(interp, objc, objv, dbp); break; case DBGET: result = tcl_DbGet(interp, objc, objv, dbp, 0); break; case DBPUT: result = tcl_DbPut(interp, objc, objv, dbp); break; case DBCOUNT: result = tcl_DbCount(interp, objc, objv, dbp); break; case DBSWAPPED: /* * No args for this. Error if there are some. */ if (objc > 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return (TCL_ERROR); } _debug_check(); ret = dbp->get_byteswapped(dbp, &isswapped); res = Tcl_NewIntObj(isswapped); break; case DBGETTYPE: /* * No args for this. Error if there are some. */ if (objc > 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return (TCL_ERROR); } _debug_check(); ret = dbp->get_type(dbp, &type); if (type == DB_BTREE) res = Tcl_NewStringObj("btree", strlen("btree")); else if (type == DB_HASH) res = Tcl_NewStringObj("hash", strlen("hash")); else if (type == DB_RECNO) res = Tcl_NewStringObj("recno", strlen("recno")); else if (type == DB_QUEUE) res = Tcl_NewStringObj("queue", strlen("queue")); else { Tcl_SetResult(interp, "db gettype: Returned unknown type\n", TCL_STATIC); result = TCL_ERROR; } break; case DBSTAT: result = tcl_DbStat(interp, objc, objv, dbp); break; case DBSYNC: /* * No args for this. Error if there are some. */ if (objc > 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return (TCL_ERROR); } _debug_check(); ret = dbp->sync(dbp, 0); res = Tcl_NewIntObj(ret); if (ret != 0) { Tcl_SetObjResult(interp, res); result = TCL_ERROR; } break; case DBCURSOR: snprintf(newname, sizeof(newname), "%s.c%d", dbip->i_name, dbip->i_dbdbcid); ip = _NewInfo(interp, NULL, newname, I_DBC); if (ip != NULL) { result = tcl_DbCursor(interp, objc, objv, dbp, &dbc); if (result == TCL_OK) { dbip->i_dbdbcid++; ip->i_parent = dbip; Tcl_CreateObjCommand(interp, newname, (Tcl_ObjCmdProc *)dbc_Cmd, (ClientData)dbc, NULL); res = Tcl_NewStringObj(newname, strlen(newname)); _SetInfoData(ip, dbc); } else _DeleteInfo(ip); } else { Tcl_SetResult(interp, "Could not set up info", TCL_STATIC); result = TCL_ERROR; } break; case DBJOIN: snprintf(newname, sizeof(newname), "%s.c%d", dbip->i_name, dbip->i_dbdbcid); ip = _NewInfo(interp, NULL, newname, I_DBC); if (ip != NULL) { result = tcl_DbJoin(interp, objc, objv, dbp, &dbc); if (result == TCL_OK) { dbip->i_dbdbcid++; ip->i_parent = dbip; Tcl_CreateObjCommand(interp, newname, (Tcl_ObjCmdProc *)dbc_Cmd, (ClientData)dbc, NULL); res = Tcl_NewStringObj(newname, strlen(newname)); _SetInfoData(ip, dbc); } else _DeleteInfo(ip); } else { Tcl_SetResult(interp, "Could not set up info", TCL_STATIC); result = TCL_ERROR; } break; case DBGETJOIN: result = tcl_DbGetjoin(interp, objc, objv, dbp); break; case DBTRUNCATE: result = tcl_DbTruncate(interp, objc, objv, dbp); break; } /* * Only set result if we have a res. Otherwise, lower * functions have already done so. */ if (result == TCL_OK && res) Tcl_SetObjResult(interp, res); return (result);}/* * tcl_db_stat -- */static inttcl_DbStat(interp, objc, objv, dbp) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB *dbp; /* Database pointer */{ DB_BTREE_STAT *bsp; DB_HASH_STAT *hsp; DB_QUEUE_STAT *qsp; void *sp; Tcl_Obj *res, *flaglist, *myobjv[2]; DBTYPE type; u_int32_t flag; int result, ret; char *arg; result = TCL_OK; flag = 0; if (objc > 3) { Tcl_WrongNumArgs(interp, 2, objv, "?-faststat?"); return (TCL_ERROR); } if (objc == 3) { arg = Tcl_GetStringFromObj(objv[2], NULL); if (strcmp(arg, "-faststat") == 0) flag = DB_FAST_STAT; else { Tcl_SetResult(interp, "db stat: unknown arg", TCL_STATIC); return (TCL_ERROR); } } _debug_check(); ret = dbp->stat(dbp, &sp, flag); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db stat"); if (result == TCL_ERROR) return (result); (void)dbp->get_type(dbp, &type); /* * Have our stats, now construct the name value * list pairs and free up the memory. */ res = Tcl_NewObj(); /* * MAKE_STAT_LIST assumes 'res' and 'error' label. */ if (type == DB_HASH) { hsp = (DB_HASH_STAT *)sp; MAKE_STAT_LIST("Magic", hsp->hash_magic); MAKE_STAT_LIST("Version", hsp->hash_version); MAKE_STAT_LIST("Page size", hsp->hash_pagesize); MAKE_STAT_LIST("Number of keys", hsp->hash_nkeys); MAKE_STAT_LIST("Number of records", hsp->hash_ndata); MAKE_STAT_LIST("Fill factor", hsp->hash_ffactor); MAKE_STAT_LIST("Buckets", hsp->hash_buckets); if (flag != DB_FAST_STAT) { MAKE_STAT_LIST("Free pages", hsp->hash_free); MAKE_STAT_LIST("Bytes free", hsp->hash_bfree); MAKE_STAT_LIST("Number of big pages", hsp->hash_bigpages); MAKE_STAT_LIST("Big pages bytes free", hsp->hash_big_bfree); MAKE_STAT_LIST("Overflow pages", hsp->hash_overflows); MAKE_STAT_LIST("Overflow bytes free", hsp->hash_ovfl_free); MAKE_STAT_LIST("Duplicate pages", hsp->hash_dup); MAKE_STAT_LIST("Duplicate pages bytes free", hsp->hash_dup_free); } } else if (type == DB_QUEUE) { qsp = (DB_QUEUE_STAT *)sp; MAKE_STAT_LIST("Magic", qsp->qs_magic); MAKE_STAT_LIST("Version", qsp->qs_version); MAKE_STAT_LIST("Page size", qsp->qs_pagesize); MAKE_STAT_LIST("Extent size", qsp->qs_extentsize); MAKE_STAT_LIST("Number of records", qsp->qs_nkeys); MAKE_STAT_LIST("Record length", qsp->qs_re_len); MAKE_STAT_LIST("Record pad", qsp->qs_re_pad); MAKE_STAT_LIST("First record number", qsp->qs_first_recno); MAKE_STAT_LIST("Last record number", qsp->qs_cur_recno); if (flag != DB_FAST_STAT) { MAKE_STAT_LIST("Number of pages", qsp->qs_pages); MAKE_STAT_LIST("Bytes free", qsp->qs_pgfree); } } else { /* BTREE and RECNO are same stats */ bsp = (DB_BTREE_STAT *)sp; MAKE_STAT_LIST("Magic", bsp->bt_magic); MAKE_STAT_LIST("Version", bsp->bt_version); MAKE_STAT_LIST("Number of keys", bsp->bt_nkeys); MAKE_STAT_LIST("Number of records", bsp->bt_ndata); MAKE_STAT_LIST("Minimum keys per page", bsp->bt_minkey); MAKE_STAT_LIST("Fixed record length", bsp->bt_re_len); MAKE_STAT_LIST("Record pad", bsp->bt_re_pad); MAKE_STAT_LIST("Page size", bsp->bt_pagesize); if (flag != DB_FAST_STAT) { MAKE_STAT_LIST("Levels", bsp->bt_levels); MAKE_STAT_LIST("Internal pages", bsp->bt_int_pg); MAKE_STAT_LIST("Leaf pages", bsp->bt_leaf_pg); MAKE_STAT_LIST("Duplicate pages", bsp->bt_dup_pg); MAKE_STAT_LIST("Overflow pages", bsp->bt_over_pg); MAKE_STAT_LIST("Pages on freelist", bsp->bt_free); MAKE_STAT_LIST("Internal pages bytes free", bsp->bt_int_pgfree); MAKE_STAT_LIST("Leaf pages bytes free", bsp->bt_leaf_pgfree); MAKE_STAT_LIST("Duplicate pages bytes free", bsp->bt_dup_pgfree); MAKE_STAT_LIST("Bytes free in overflow pages", bsp->bt_over_pgfree); } } /* * Construct a {name {flag1 flag2 ... flagN}} list for the * dbp flags. These aren't access-method dependent, but they * include all the interesting flags, and the integer value * isn't useful from Tcl--return the strings instead. */ myobjv[0] = Tcl_NewStringObj("Flags", strlen("Flags")); myobjv[1] = _GetFlagsList(interp, dbp->flags, __db_inmemdbflags); flaglist = Tcl_NewListObj(2, myobjv); if (flaglist == NULL) { result = TCL_ERROR; goto error; } if ((result = Tcl_ListObjAppendElement(interp, res, flaglist)) != TCL_OK) goto error; Tcl_SetObjResult(interp, res);error: free(sp); return (result);}/* * tcl_db_close -- */static inttcl_DbClose(interp, objc, objv, dbp, dbip) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB *dbp; /* Database pointer */ DBTCL_INFO *dbip; /* Info pointer */{ static char *dbclose[] = { "-nosync", "--", NULL }; enum dbclose { TCL_DBCLOSE_NOSYNC, TCL_DBCLOSE_ENDARG }; u_int32_t flag; int endarg, i, optindex, result, ret; char *arg; result = TCL_OK; endarg = 0; flag = 0; if (objc > 4) { Tcl_WrongNumArgs(interp, 2, objv, "?-nosync?"); return (TCL_ERROR); } i = 2; while (i < objc) { if (Tcl_GetIndexFromObj(interp, objv[i], dbclose, "option", TCL_EXACT, &optindex) != TCL_OK) { arg = Tcl_GetStringFromObj(objv[i], NULL); if (arg[0] == '-') return (IS_HELP(objv[i])); else Tcl_ResetResult(interp); break; } i++; switch ((enum dbclose)optindex) { case TCL_DBCLOSE_NOSYNC: flag = DB_NOSYNC; break; case TCL_DBCLOSE_ENDARG: endarg = 1; break; } /* * If, at any time, parsing the args we get an error, * bail out and return. */ if (result != TCL_OK) return (result); if (endarg) break; } _DbInfoDelete(interp, dbip); _debug_check(); /* Paranoia. */ dbp->api_internal = NULL; ret = (dbp)->close(dbp, flag); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db close"); return (result);}/* * tcl_db_put -- */static inttcl_DbPut(interp, objc, objv, dbp) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB *dbp; /* Database pointer */{ static char *dbputopts[] = {#if CONFIG_TEST "-nodupdata",#endif "-append", "-auto_commit", "-nooverwrite", "-partial", "-txn", NULL }; enum dbputopts {#if CONFIG_TEST DBGET_NODUPDATA,#endif DBPUT_APPEND, DBPUT_AUTO_COMMIT, DBPUT_NOOVER, DBPUT_PART, DBPUT_TXN }; static char *dbputapp[] = { "-append", NULL }; enum dbputapp { DBPUT_APPEND0 }; DBT key, data; DBTYPE type; DB_TXN *txn; Tcl_Obj **elemv, *res; void *dtmp, *ktmp; db_recno_t recno; u_int32_t flag; int auto_commit, elemc, end, freekey, freedata; int i, optindex, result, ret; char *arg, msg[MSG_SIZE]; txn = NULL; result = TCL_OK; flag = 0; if (objc <= 3) { Tcl_WrongNumArgs(interp, 2, objv, "?-args? key data"); return (TCL_ERROR); } freekey = freedata = 0; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -