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