1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1999,2008 Oracle. All rights reserved. 5 * 6 * $Id: tcl_db.h,v 12.13 2008/02/01 18:27:16 sue Exp $ 7 */ 8 9#ifndef _DB_TCL_DB_H_ 10#define _DB_TCL_DB_H_ 11 12#if defined(__cplusplus) 13extern "C" { 14#endif 15 16#define MSG_SIZE 100 /* Message size */ 17 18enum INFOTYPE { 19 I_ENV, I_DB, I_DBC, I_TXN, I_MP, I_PG, I_LOCK, I_LOGC, I_NDBM, I_SEQ}; 20 21#define MAX_ID 8 /* Maximum number of sub-id's we need */ 22#define DBTCL_PREP 64 /* Size of txn_recover preplist */ 23 24#define DBTCL_DBM 1 25#define DBTCL_NDBM 2 26 27#define DBTCL_GETCLOCK 0 28#define DBTCL_GETLIMIT 1 29#define DBTCL_GETREQ 2 30 31/* 32 * Why use a home grown package over the Tcl_Hash functions? 33 * 34 * We could have implemented the stuff below without maintaining our 35 * own list manipulation, efficiently hashing it with the available 36 * Tcl functions (Tcl_CreateHashEntry, Tcl_GetHashValue, etc). I chose 37 * not to do so for these reasons: 38 * 39 * We still need the information below. Using the hashing only removes 40 * us from needing the next/prev pointers. We still need the structure 41 * itself because we need more than one value associated with a widget. 42 * We need to keep track of parent pointers for sub-widgets (like cursors) 43 * so we can correctly close. We need to keep track of individual widget's 44 * id counters for any sub-widgets they may have. We need to be able to 45 * associate the name/client data outside the scope of the widget. 46 * 47 * So, is it better to use the hashing rather than 48 * the linear list we have now? I decided against it for the simple reason 49 * that to access the structure would require two calls. The first is 50 * Tcl_FindHashEntry(table, key) and then, once we have the entry, we'd 51 * have to do Tcl_GetHashValue(entry) to get the pointer of the structure. 52 * 53 * I believe the number of simultaneous DB widgets in existence at one time 54 * is not going to be that large (more than several dozen) such that 55 * linearly searching the list is not going to impact performance in a 56 * noticeable way. Should performance be impacted due to the size of the 57 * info list, then perhaps it is time to revisit this decision. 58 */ 59typedef struct dbtcl_info { 60 LIST_ENTRY(dbtcl_info) entries; 61 Tcl_Interp *i_interp; 62 char *i_name; 63 enum INFOTYPE i_type; 64 union infop { 65 DB *dbp; 66 DBC *dbcp; 67 DB_ENV *envp; 68 DB_LOCK *lock; 69 DB_LOGC *logc; 70 DB_MPOOLFILE *mp; 71 DB_TXN *txnp; 72 void *anyp; 73 } un; 74 union data { 75 int anydata; 76 db_pgno_t pgno; 77 u_int32_t lockid; 78 } und; 79 union data2 { 80 int anydata; 81 int pagesz; 82 DB_COMPACT *c_data; 83 } und2; 84 DBT i_lockobj; 85 FILE *i_err; 86 char *i_errpfx; 87 88 /* Callbacks--Tcl_Objs containing proc names */ 89 Tcl_Obj *i_compare; 90 Tcl_Obj *i_dupcompare; 91 Tcl_Obj *i_event; 92 Tcl_Obj *i_hashproc; 93 Tcl_Obj *i_rep_send; 94 Tcl_Obj *i_second_call; 95 96 /* Environment ID for the i_rep_send callback. */ 97 Tcl_Obj *i_rep_eid; 98 99 struct dbtcl_info *i_parent; 100 int i_otherid[MAX_ID]; 101} DBTCL_INFO; 102 103#define i_anyp un.anyp 104#define i_pagep un.anyp 105#define i_envp un.envp 106#define i_dbp un.dbp 107#define i_dbcp un.dbcp 108#define i_txnp un.txnp 109#define i_mp un.mp 110#define i_lock un.lock 111#define i_logc un.logc 112 113#define i_data und.anydata 114#define i_pgno und.pgno 115#define i_locker und.lockid 116#define i_data2 und2.anydata 117#define i_pgsz und2.pagesz 118#define i_cdata und2.c_data 119 120#define i_envtxnid i_otherid[0] 121#define i_envmpid i_otherid[1] 122#define i_envlockid i_otherid[2] 123#define i_envlogcid i_otherid[3] 124 125#define i_mppgid i_otherid[0] 126 127#define i_dbdbcid i_otherid[0] 128 129extern int __debug_on, __debug_print, __debug_stop, __debug_test; 130 131typedef struct dbtcl_global { 132 LIST_HEAD(infohead, dbtcl_info) g_infohead; 133} DBTCL_GLOBAL; 134#define __db_infohead __dbtcl_global.g_infohead 135 136extern DBTCL_GLOBAL __dbtcl_global; 137 138/* 139 * Tcl_NewStringObj takes an "int" length argument, when the typical use is to 140 * call it with a size_t length (for example, returned by strlen). Tcl is in 141 * the wrong, but that doesn't help us much -- cast the argument. 142 */ 143#define NewStringObj(a, b) \ 144 Tcl_NewStringObj(a, (int)b) 145 146#define NAME_TO_DB(name) (DB *)_NameToPtr((name)) 147#define NAME_TO_DBC(name) (DBC *)_NameToPtr((name)) 148#define NAME_TO_ENV(name) (DB_ENV *)_NameToPtr((name)) 149#define NAME_TO_LOCK(name) (DB_LOCK *)_NameToPtr((name)) 150#define NAME_TO_MP(name) (DB_MPOOLFILE *)_NameToPtr((name)) 151#define NAME_TO_TXN(name) (DB_TXN *)_NameToPtr((name)) 152#define NAME_TO_SEQUENCE(name) (DB_SEQUENCE *)_NameToPtr((name)) 153 154/* 155 * MAKE_STAT_LIST appends a {name value} pair to a result list that MUST be 156 * called 'res' that is a Tcl_Obj * in the local function. This macro also 157 * assumes a label "error" to go to in the event of a Tcl error. For stat 158 * functions this will typically go before the "free" function to free the 159 * stat structure returned by DB. 160 */ 161#define MAKE_STAT_LIST(s, v) do { \ 162 result = _SetListElemInt(interp, res, (s), (long)(v)); \ 163 if (result != TCL_OK) \ 164 goto error; \ 165} while (0) 166 167#define MAKE_WSTAT_LIST(s, v) do { \ 168 result = _SetListElemWideInt(interp, res, (s), (int64_t)(v)); \ 169 if (result != TCL_OK) \ 170 goto error; \ 171} while (0) 172 173/* 174 * MAKE_STAT_LSN appends a {name {LSNfile LSNoffset}} pair to a result list 175 * that MUST be called 'res' that is a Tcl_Obj * in the local 176 * function. This macro also assumes a label "error" to go to 177 * in the even of a Tcl error. For stat functions this will 178 * typically go before the "free" function to free the stat structure 179 * returned by DB. 180 */ 181#define MAKE_STAT_LSN(s, lsn) do { \ 182 myobjc = 2; \ 183 myobjv[0] = Tcl_NewLongObj((long)(lsn)->file); \ 184 myobjv[1] = Tcl_NewLongObj((long)(lsn)->offset); \ 185 lsnlist = Tcl_NewListObj(myobjc, myobjv); \ 186 myobjc = 2; \ 187 myobjv[0] = Tcl_NewStringObj((s), (int)strlen(s)); \ 188 myobjv[1] = lsnlist; \ 189 thislist = Tcl_NewListObj(myobjc, myobjv); \ 190 result = Tcl_ListObjAppendElement(interp, res, thislist); \ 191 if (result != TCL_OK) \ 192 goto error; \ 193} while (0) 194 195/* 196 * MAKE_STAT_STRLIST appends a {name string} pair to a result list 197 * that MUST be called 'res' that is a Tcl_Obj * in the local 198 * function. This macro also assumes a label "error" to go to 199 * in the even of a Tcl error. For stat functions this will 200 * typically go before the "free" function to free the stat structure 201 * returned by DB. 202 */ 203#define MAKE_STAT_STRLIST(s,s1) do { \ 204 result = _SetListElem(interp, res, (s), strlen(s), \ 205 (s1), strlen(s1)); \ 206 if (result != TCL_OK) \ 207 goto error; \ 208} while (0) 209 210/* 211 * FLAG_CHECK checks that the given flag is not set yet. 212 * If it is, it sets up an error message. 213 */ 214#define FLAG_CHECK(flag) do { \ 215 if ((flag) != 0) { \ 216 Tcl_SetResult(interp, \ 217 " Only 1 policy can be specified.\n", \ 218 TCL_STATIC); \ 219 result = TCL_ERROR; \ 220 break; \ 221 } \ 222} while (0) 223 224/* 225 * FLAG_CHECK2 checks that the given flag is not set yet or is 226 * only set to the given allowed value. 227 * If it is, it sets up an error message. 228 */ 229#define FLAG_CHECK2(flag, val) do { \ 230 if (((flag) & ~(val)) != 0) { \ 231 Tcl_SetResult(interp, \ 232 " Only 1 policy can be specified.\n", \ 233 TCL_STATIC); \ 234 result = TCL_ERROR; \ 235 break; \ 236 } \ 237} while (0) 238 239/* 240 * IS_HELP checks whether the arg we bombed on is -?, which is a help option. 241 * If it is, we return TCL_OK (but leave the result set to whatever 242 * Tcl_GetIndexFromObj says, which lists all the valid options. Otherwise 243 * return TCL_ERROR. 244 */ 245#define IS_HELP(s) \ 246 (strcmp(Tcl_GetStringFromObj(s,NULL), "-?") == 0) ? TCL_OK : TCL_ERROR 247 248#if defined(__cplusplus) 249} 250#endif 251 252#include "dbinc_auto/tcl_ext.h" 253#endif /* !_DB_TCL_DB_H_ */ 254