blob: 578cf3df069196890b071913782c424627bc486d [file] [log] [blame]
Guido van Rossum1100dca1995-08-30 23:43:03 +00001/* Berkeley DB interface.
2 Author: Michael McLay
3 Hacked: Guido van Rossum
4 Btree and Recno additions plus sequence methods: David Ely
Fred Drakeed5e8232001-02-27 18:56:46 +00005 Hacked by Gustavo Niemeyer <niemeyer@conectiva.com> fixing recno
6 support.
Guido van Rossum1100dca1995-08-30 23:43:03 +00007
8 XXX To do:
Guido van Rossum1100dca1995-08-30 23:43:03 +00009 - provide a way to access the various hash functions
10 - support more open flags
Guido van Rossum675e9941999-09-20 13:28:18 +000011
12 The windows port of the Berkeley DB code is hard to find on the web:
13 www.nightmare.com/software.html
14*/
Guido van Rossum1100dca1995-08-30 23:43:03 +000015
Guido van Rossumdfe8ad91996-07-24 00:51:20 +000016#include "Python.h"
Guido van Rossum4f199ea1998-04-09 20:56:35 +000017#ifdef WITH_THREAD
Guido van Rossum49b56061998-10-01 20:42:43 +000018#include "pythread.h"
Guido van Rossum4f199ea1998-04-09 20:56:35 +000019#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +000020
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
Fred Drakec9cb8472000-08-31 16:11:07 +000024#ifdef HAVE_DB_185_H
25#include <db_185.h>
26#else
Guido van Rossum1100dca1995-08-30 23:43:03 +000027#include <db.h>
Fred Drakec9cb8472000-08-31 16:11:07 +000028#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +000029/* Please don't include internal header files of the Berkeley db package
30 (it messes up the info required in the Setup file) */
31
32typedef struct {
Antoine Pitrouc83ea132010-05-09 14:46:46 +000033 PyObject_HEAD
34 DB *di_bsddb;
35 int di_size; /* -1 means recompute */
36 int di_type;
Guido van Rossum4f199ea1998-04-09 20:56:35 +000037#ifdef WITH_THREAD
Antoine Pitrouc83ea132010-05-09 14:46:46 +000038 PyThread_type_lock di_lock;
Guido van Rossum4f199ea1998-04-09 20:56:35 +000039#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +000040} bsddbobject;
41
Jeremy Hylton938ace62002-07-17 16:30:39 +000042static PyTypeObject Bsddbtype;
Guido van Rossum1100dca1995-08-30 23:43:03 +000043
44#define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
Fred Drakeed5e8232001-02-27 18:56:46 +000045#define check_bsddbobject_open(v, r) if ((v)->di_bsddb == NULL) \
Fred Drakec9f7c262001-02-19 21:16:00 +000046 { PyErr_SetString(BsddbError, \
Antoine Pitrouc83ea132010-05-09 14:46:46 +000047 "BSDDB object has already been closed"); \
Fred Drakeed5e8232001-02-27 18:56:46 +000048 return r; }
Guido van Rossum1100dca1995-08-30 23:43:03 +000049
Guido van Rossumdfe8ad91996-07-24 00:51:20 +000050static PyObject *BsddbError;
Guido van Rossum1100dca1995-08-30 23:43:03 +000051
Guido van Rossumdfe8ad91996-07-24 00:51:20 +000052static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000053newdbhashobject(char *file, int flags, int mode,
Antoine Pitrouc83ea132010-05-09 14:46:46 +000054 int bsize, int ffactor, int nelem, int cachesize,
55 int hash, int lorder)
Guido van Rossum1100dca1995-08-30 23:43:03 +000056{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000057 bsddbobject *dp;
58 HASHINFO info;
Guido van Rossum1100dca1995-08-30 23:43:03 +000059
Antoine Pitrouc83ea132010-05-09 14:46:46 +000060 if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
61 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +000062
Antoine Pitrouc83ea132010-05-09 14:46:46 +000063 info.bsize = bsize;
64 info.ffactor = ffactor;
65 info.nelem = nelem;
66 info.cachesize = cachesize;
67 info.hash = NULL; /* XXX should derive from hash argument */
68 info.lorder = lorder;
Guido van Rossum1100dca1995-08-30 23:43:03 +000069
Guido van Rossum6beb4791996-09-11 23:22:25 +000070#ifdef O_BINARY
Antoine Pitrouc83ea132010-05-09 14:46:46 +000071 flags |= O_BINARY;
Guido van Rossum6beb4791996-09-11 23:22:25 +000072#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +000073 Py_BEGIN_ALLOW_THREADS
74 dp->di_bsddb = dbopen(file, flags, mode, DB_HASH, &info);
75 Py_END_ALLOW_THREADS
76 if (dp->di_bsddb == NULL) {
77 PyErr_SetFromErrno(BsddbError);
Guido van Rossum4f199ea1998-04-09 20:56:35 +000078#ifdef WITH_THREAD
Antoine Pitrouc83ea132010-05-09 14:46:46 +000079 dp->di_lock = NULL;
Guido van Rossum4f199ea1998-04-09 20:56:35 +000080#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +000081 Py_DECREF(dp);
82 return NULL;
83 }
Guido van Rossum1100dca1995-08-30 23:43:03 +000084
Antoine Pitrouc83ea132010-05-09 14:46:46 +000085 dp->di_size = -1;
86 dp->di_type = DB_HASH;
Fred Drakeed5e8232001-02-27 18:56:46 +000087
Guido van Rossum4f199ea1998-04-09 20:56:35 +000088#ifdef WITH_THREAD
Antoine Pitrouc83ea132010-05-09 14:46:46 +000089 dp->di_lock = PyThread_allocate_lock();
90 if (dp->di_lock == NULL) {
91 PyErr_SetString(BsddbError, "can't allocate lock");
92 Py_DECREF(dp);
93 return NULL;
94 }
Guido van Rossum4f199ea1998-04-09 20:56:35 +000095#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +000096
Antoine Pitrouc83ea132010-05-09 14:46:46 +000097 return (PyObject *)dp;
Guido van Rossum1100dca1995-08-30 23:43:03 +000098}
99
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000100static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000101newdbbtobject(char *file, int flags, int mode,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000102 int btflags, int cachesize, int maxkeypage,
103 int minkeypage, int psize, int lorder)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000104{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000105 bsddbobject *dp;
106 BTREEINFO info;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000107
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000108 if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
109 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000110
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000111 info.flags = btflags;
112 info.cachesize = cachesize;
113 info.maxkeypage = maxkeypage;
114 info.minkeypage = minkeypage;
115 info.psize = psize;
116 info.lorder = lorder;
117 info.compare = 0; /* Use default comparison functions, for now..*/
118 info.prefix = 0;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000119
Guido van Rossum6beb4791996-09-11 23:22:25 +0000120#ifdef O_BINARY
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000121 flags |= O_BINARY;
Guido van Rossum6beb4791996-09-11 23:22:25 +0000122#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000123 Py_BEGIN_ALLOW_THREADS
124 dp->di_bsddb = dbopen(file, flags, mode, DB_BTREE, &info);
125 Py_END_ALLOW_THREADS
126 if (dp->di_bsddb == NULL) {
127 PyErr_SetFromErrno(BsddbError);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000128#ifdef WITH_THREAD
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000129 dp->di_lock = NULL;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000130#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000131 Py_DECREF(dp);
132 return NULL;
133 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000134
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000135 dp->di_size = -1;
136 dp->di_type = DB_BTREE;
Fred Drakeed5e8232001-02-27 18:56:46 +0000137
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000138#ifdef WITH_THREAD
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000139 dp->di_lock = PyThread_allocate_lock();
140 if (dp->di_lock == NULL) {
141 PyErr_SetString(BsddbError, "can't allocate lock");
142 Py_DECREF(dp);
143 return NULL;
144 }
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000145#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +0000146
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000147 return (PyObject *)dp;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000148}
149
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000150static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000151newdbrnobject(char *file, int flags, int mode,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000152 int rnflags, int cachesize, int psize, int lorder,
153 size_t reclen, u_char bval, char *bfname)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000154{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000155 bsddbobject *dp;
156 RECNOINFO info;
157 int fd;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000158
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000159 if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
160 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000161
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000162 info.flags = rnflags;
163 info.cachesize = cachesize;
164 info.psize = psize;
165 info.lorder = lorder;
166 info.reclen = reclen;
167 info.bval = bval;
168 info.bfname = bfname;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000169
Guido van Rossum6beb4791996-09-11 23:22:25 +0000170#ifdef O_BINARY
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000171 flags |= O_BINARY;
Guido van Rossum6beb4791996-09-11 23:22:25 +0000172#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000173 /* This is a hack to avoid a dbopen() bug that happens when
174 * it fails. */
175 fd = open(file, flags);
176 if (fd == -1) {
177 dp->di_bsddb = NULL;
178 }
179 else {
180 close(fd);
181 Py_BEGIN_ALLOW_THREADS
182 dp->di_bsddb = dbopen(file, flags, mode, DB_RECNO, &info);
183 Py_END_ALLOW_THREADS
184 }
185 if (dp->di_bsddb == NULL) {
186 PyErr_SetFromErrno(BsddbError);
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000187#ifdef WITH_THREAD
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000188 dp->di_lock = NULL;
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000189#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000190 Py_DECREF(dp);
191 return NULL;
192 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000193
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000194 dp->di_size = -1;
195 dp->di_type = DB_RECNO;
Fred Drakeed5e8232001-02-27 18:56:46 +0000196
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000197#ifdef WITH_THREAD
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000198 dp->di_lock = PyThread_allocate_lock();
199 if (dp->di_lock == NULL) {
200 PyErr_SetString(BsddbError, "can't allocate lock");
201 Py_DECREF(dp);
202 return NULL;
203 }
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000204#endif
Guido van Rossum1100dca1995-08-30 23:43:03 +0000205
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000206 return (PyObject *)dp;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000207}
208
Guido van Rossum1100dca1995-08-30 23:43:03 +0000209static void
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000210bsddb_dealloc(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000211{
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000212#ifdef WITH_THREAD
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000213 if (dp->di_lock) {
214 PyThread_acquire_lock(dp->di_lock, 0);
215 PyThread_release_lock(dp->di_lock);
216 PyThread_free_lock(dp->di_lock);
217 dp->di_lock = NULL;
218 }
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000219#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000220 if (dp->di_bsddb != NULL) {
221 int status;
222 Py_BEGIN_ALLOW_THREADS
223 status = (dp->di_bsddb->close)(dp->di_bsddb);
224 Py_END_ALLOW_THREADS
225 if (status != 0)
226 fprintf(stderr,
227 "Python bsddb: close errno %d in dealloc\n",
228 errno);
229 }
230 PyObject_Del(dp);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000231}
232
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000233#ifdef WITH_THREAD
Fred Drakec9f7c262001-02-19 21:16:00 +0000234#define BSDDB_BGN_SAVE(_dp) \
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000235 Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(_dp->di_lock,1);
Fred Drakec9f7c262001-02-19 21:16:00 +0000236#define BSDDB_END_SAVE(_dp) \
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000237 PyThread_release_lock(_dp->di_lock); Py_END_ALLOW_THREADS
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000238#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000239#define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS
Guido van Rossum4f199ea1998-04-09 20:56:35 +0000240#define BSDDB_END_SAVE(_dp) Py_END_ALLOW_THREADS
241#endif
242
Martin v. Löwis18e16552006-02-15 17:27:45 +0000243static Py_ssize_t
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000244bsddb_length(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000245{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000246 check_bsddbobject_open(dp, -1);
247 if (dp->di_size < 0) {
248 DBT krec, drec;
249 int status;
250 int size = 0;
251 BSDDB_BGN_SAVE(dp)
252 for (status = (dp->di_bsddb->seq)(dp->di_bsddb,
253 &krec, &drec,R_FIRST);
254 status == 0;
255 status = (dp->di_bsddb->seq)(dp->di_bsddb,
256 &krec, &drec, R_NEXT))
257 size++;
258 BSDDB_END_SAVE(dp)
259 if (status < 0) {
260 PyErr_SetFromErrno(BsddbError);
261 return -1;
262 }
263 dp->di_size = size;
264 }
265 return dp->di_size;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000266}
267
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000268static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000269bsddb_subscript(bsddbobject *dp, PyObject *key)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000270{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000271 int status;
272 DBT krec, drec;
273 char *data = NULL;
274 char buf[4096];
275 int size;
276 PyObject *result;
277 recno_t recno;
Brett Cannon79832842010-05-03 23:57:15 +0000278
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000279 if (dp->di_type == DB_RECNO) {
280 if (!PyArg_Parse(key, "i", &recno)) {
281 PyErr_SetString(PyExc_TypeError,
282 "key type must be integer");
283 return NULL;
284 }
285 krec.data = &recno;
286 krec.size = sizeof(recno);
287 }
288 else {
289 if (!PyArg_Parse(key, "s#", &data, &size)) {
290 PyErr_SetString(PyExc_TypeError,
291 "key type must be string");
292 return NULL;
293 }
294 krec.data = data;
295 krec.size = size;
296 }
297 check_bsddbobject_open(dp, NULL);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000298
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000299 BSDDB_BGN_SAVE(dp)
300 status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
301 if (status == 0) {
302 if (drec.size > sizeof(buf)) data = malloc(drec.size);
303 else data = buf;
304 if (data!=NULL) memcpy(data,drec.data,drec.size);
305 }
306 BSDDB_END_SAVE(dp)
307 if (data==NULL) return PyErr_NoMemory();
308 if (status != 0) {
309 if (status < 0)
310 PyErr_SetFromErrno(BsddbError);
311 else
312 PyErr_SetObject(PyExc_KeyError, key);
313 return NULL;
314 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000315
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000316 result = PyString_FromStringAndSize(data, (int)drec.size);
317 if (data != buf) free(data);
318 return result;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000319}
320
321static int
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000322bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000323{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000324 int status;
325 DBT krec, drec;
326 char *data;
327 int size;
328 recno_t recno;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000329
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000330 if (dp->di_type == DB_RECNO) {
331 if (!PyArg_Parse(key, "i", &recno)) {
332 PyErr_SetString(PyExc_TypeError,
333 "bsddb key type must be integer");
334 return -1;
335 }
336 krec.data = &recno;
337 krec.size = sizeof(recno);
338 }
339 else {
340 if (!PyArg_Parse(key, "s#", &data, &size)) {
341 PyErr_SetString(PyExc_TypeError,
342 "bsddb key type must be string");
343 return -1;
344 }
345 krec.data = data;
346 krec.size = size;
347 }
348 check_bsddbobject_open(dp, -1);
349 dp->di_size = -1;
350 if (value == NULL) {
351 BSDDB_BGN_SAVE(dp)
352 status = (dp->di_bsddb->del)(dp->di_bsddb, &krec, 0);
353 BSDDB_END_SAVE(dp)
354 }
355 else {
356 if (!PyArg_Parse(value, "s#", &data, &size)) {
357 PyErr_SetString(PyExc_TypeError,
358 "bsddb value type must be string");
359 return -1;
360 }
361 drec.data = data;
362 drec.size = size;
363 BSDDB_BGN_SAVE(dp)
364 status = (dp->di_bsddb->put)(dp->di_bsddb, &krec, &drec, 0);
365 BSDDB_END_SAVE(dp)
366 }
367 if (status != 0) {
368 if (status < 0)
369 PyErr_SetFromErrno(BsddbError);
370 else
371 PyErr_SetObject(PyExc_KeyError, key);
372 return -1;
373 }
374 return 0;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000375}
376
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000377static PyMappingMethods bsddb_as_mapping = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000378 (lenfunc)bsddb_length, /*mp_length*/
379 (binaryfunc)bsddb_subscript, /*mp_subscript*/
380 (objobjargproc)bsddb_ass_sub, /*mp_ass_subscript*/
Guido van Rossum1100dca1995-08-30 23:43:03 +0000381};
382
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000383static PyObject *
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000384bsddb_close(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000385{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000386 if (dp->di_bsddb != NULL) {
387 int status;
388 BSDDB_BGN_SAVE(dp)
389 status = (dp->di_bsddb->close)(dp->di_bsddb);
390 BSDDB_END_SAVE(dp)
391 if (status != 0) {
392 dp->di_bsddb = NULL;
393 PyErr_SetFromErrno(BsddbError);
394 return NULL;
395 }
396 }
397 dp->di_bsddb = NULL;
398 Py_INCREF(Py_None);
399 return Py_None;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000400}
401
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000402static PyObject *
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000403bsddb_keys(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000404{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000405 PyObject *list, *item=NULL;
406 DBT krec, drec;
407 char *data=NULL,buf[4096];
408 int status;
409 int err;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000410
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000411 check_bsddbobject_open(dp, NULL);
412 list = PyList_New(0);
413 if (list == NULL)
414 return NULL;
415 BSDDB_BGN_SAVE(dp)
416 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_FIRST);
417 if (status == 0) {
418 if (krec.size > sizeof(buf)) data = malloc(krec.size);
419 else data = buf;
420 if (data != NULL) memcpy(data,krec.data,krec.size);
421 }
422 BSDDB_END_SAVE(dp)
423 if (status == 0 && data==NULL) return PyErr_NoMemory();
424 while (status == 0) {
425 if (dp->di_type == DB_RECNO)
426 item = PyInt_FromLong(*((int*)data));
427 else
428 item = PyString_FromStringAndSize(data,
429 (int)krec.size);
430 if (data != buf) free(data);
431 if (item == NULL) {
432 Py_DECREF(list);
433 return NULL;
434 }
435 err = PyList_Append(list, item);
436 Py_DECREF(item);
437 if (err != 0) {
438 Py_DECREF(list);
439 return NULL;
440 }
441 BSDDB_BGN_SAVE(dp)
442 status = (dp->di_bsddb->seq)
443 (dp->di_bsddb, &krec, &drec, R_NEXT);
444 if (status == 0) {
445 if (krec.size > sizeof(buf))
446 data = malloc(krec.size);
447 else data = buf;
448 if (data != NULL)
449 memcpy(data,krec.data,krec.size);
450 }
451 BSDDB_END_SAVE(dp)
452 if (data == NULL) return PyErr_NoMemory();
453 }
454 if (status < 0) {
455 PyErr_SetFromErrno(BsddbError);
456 Py_DECREF(list);
457 return NULL;
458 }
459 if (dp->di_size < 0)
460 dp->di_size = PyList_Size(list); /* We just did the work */
461 return list;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000462}
463
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000464static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000465bsddb_has_key(bsddbobject *dp, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000466{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000467 DBT krec, drec;
468 int status;
469 char *data;
470 int size;
471 recno_t recno;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000472
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000473 if (dp->di_type == DB_RECNO) {
474 if (!PyArg_ParseTuple(args, "i;key type must be integer",
475 &recno)) {
476 return NULL;
477 }
478 krec.data = &recno;
479 krec.size = sizeof(recno);
480 }
481 else {
482 if (!PyArg_ParseTuple(args, "s#;key type must be string",
483 &data, &size)) {
484 return NULL;
485 }
486 krec.data = data;
487 krec.size = size;
488 }
489 check_bsddbobject_open(dp, NULL);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000490
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000491 BSDDB_BGN_SAVE(dp)
492 status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
493 BSDDB_END_SAVE(dp)
494 if (status < 0) {
495 PyErr_SetFromErrno(BsddbError);
496 return NULL;
497 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000498
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000499 return PyInt_FromLong(status == 0);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000500}
501
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000502static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000503bsddb_set_location(bsddbobject *dp, PyObject *key)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000504{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000505 int status;
506 DBT krec, drec;
507 char *data = NULL;
508 char buf[4096];
509 int size;
510 PyObject *result;
511 recno_t recno;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000512
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000513 if (dp->di_type == DB_RECNO) {
514 if (!PyArg_ParseTuple(key, "i;key type must be integer",
515 &recno)) {
516 return NULL;
517 }
518 krec.data = &recno;
519 krec.size = sizeof(recno);
520 }
521 else {
522 if (!PyArg_ParseTuple(key, "s#;key type must be string",
523 &data, &size)) {
524 return NULL;
525 }
526 krec.data = data;
527 krec.size = size;
528 }
529 check_bsddbobject_open(dp, NULL);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000530
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000531 BSDDB_BGN_SAVE(dp)
532 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_CURSOR);
533 if (status == 0) {
534 if (drec.size > sizeof(buf)) data = malloc(drec.size);
535 else data = buf;
536 if (data!=NULL) memcpy(data,drec.data,drec.size);
537 }
538 BSDDB_END_SAVE(dp)
539 if (data==NULL) return PyErr_NoMemory();
540 if (status != 0) {
541 if (status < 0)
542 PyErr_SetFromErrno(BsddbError);
543 else
544 PyErr_SetObject(PyExc_KeyError, key);
545 return NULL;
546 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000547
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000548 if (dp->di_type == DB_RECNO)
549 result = Py_BuildValue("is#", *((int*)krec.data),
550 data, drec.size);
551 else
552 result = Py_BuildValue("s#s#", krec.data, krec.size,
553 data, drec.size);
554 if (data != buf) free(data);
555 return result;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000556}
557
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000558static PyObject *
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000559bsddb_seq(bsddbobject *dp, int sequence_request)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000560{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000561 int status;
562 DBT krec, drec;
563 char *kdata=NULL,kbuf[4096];
564 char *ddata=NULL,dbuf[4096];
565 PyObject *result;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000566
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000567 check_bsddbobject_open(dp, NULL);
568 krec.data = 0;
569 krec.size = 0;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000570
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000571 BSDDB_BGN_SAVE(dp)
572 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec,
573 &drec, sequence_request);
574 if (status == 0) {
575 if (krec.size > sizeof(kbuf)) kdata = malloc(krec.size);
576 else kdata = kbuf;
577 if (kdata != NULL) memcpy(kdata,krec.data,krec.size);
578 if (drec.size > sizeof(dbuf)) ddata = malloc(drec.size);
579 else ddata = dbuf;
580 if (ddata != NULL) memcpy(ddata,drec.data,drec.size);
581 }
582 BSDDB_END_SAVE(dp)
583 if (status == 0) {
584 if ((kdata == NULL) || (ddata == NULL))
585 return PyErr_NoMemory();
586 }
587 else {
588 /* (status != 0) */
589 if (status < 0)
590 PyErr_SetFromErrno(BsddbError);
591 else
592 PyErr_SetString(PyExc_KeyError, "no key/data pairs");
593 return NULL;
594 }
Guido van Rossum1100dca1995-08-30 23:43:03 +0000595
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000596 if (dp->di_type == DB_RECNO)
597 result = Py_BuildValue("is#", *((int*)kdata),
598 ddata, drec.size);
599 else
600 result = Py_BuildValue("s#s#", kdata, krec.size,
601 ddata, drec.size);
602 if (kdata != kbuf) free(kdata);
603 if (ddata != dbuf) free(ddata);
604 return result;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000605}
606
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000607static PyObject *
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000608bsddb_next(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000609{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000610 return bsddb_seq(dp, R_NEXT);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000611}
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000612static PyObject *
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000613bsddb_previous(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000614{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000615 return bsddb_seq(dp, R_PREV);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000616}
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000617static PyObject *
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000618bsddb_first(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000619{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000620 return bsddb_seq(dp, R_FIRST);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000621}
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000622static PyObject *
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000623bsddb_last(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000624{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000625 return bsddb_seq(dp, R_LAST);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000626}
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000627static PyObject *
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000628bsddb_sync(bsddbobject *dp)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000629{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000630 int status;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000631
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000632 check_bsddbobject_open(dp, NULL);
633 BSDDB_BGN_SAVE(dp)
634 status = (dp->di_bsddb->sync)(dp->di_bsddb, 0);
635 BSDDB_END_SAVE(dp)
636 if (status != 0) {
637 PyErr_SetFromErrno(BsddbError);
638 return NULL;
639 }
640 return PyInt_FromLong(0);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000641}
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000642static PyMethodDef bsddb_methods[] = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000643 {"close", (PyCFunction)bsddb_close, METH_NOARGS},
644 {"keys", (PyCFunction)bsddb_keys, METH_NOARGS},
645 {"has_key", (PyCFunction)bsddb_has_key, METH_VARARGS},
646 {"set_location", (PyCFunction)bsddb_set_location, METH_VARARGS},
647 {"next", (PyCFunction)bsddb_next, METH_NOARGS},
648 {"previous", (PyCFunction)bsddb_previous, METH_NOARGS},
649 {"first", (PyCFunction)bsddb_first, METH_NOARGS},
650 {"last", (PyCFunction)bsddb_last, METH_NOARGS},
651 {"sync", (PyCFunction)bsddb_sync, METH_NOARGS},
652 {NULL, NULL} /* sentinel */
Guido van Rossum1100dca1995-08-30 23:43:03 +0000653};
654
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000655static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000656bsddb_getattr(PyObject *dp, char *name)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000657{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000658 return Py_FindMethod(bsddb_methods, dp, name);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000659}
660
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000661static PyTypeObject Bsddbtype = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000662 PyObject_HEAD_INIT(NULL)
663 0,
664 "bsddb.bsddb",
665 sizeof(bsddbobject),
666 0,
667 (destructor)bsddb_dealloc, /*tp_dealloc*/
668 0, /*tp_print*/
669 (getattrfunc)bsddb_getattr, /*tp_getattr*/
670 0, /*tp_setattr*/
671 0, /*tp_compare*/
672 0, /*tp_repr*/
673 0, /*tp_as_number*/
674 0, /*tp_as_sequence*/
675 &bsddb_as_mapping, /*tp_as_mapping*/
Guido van Rossum1100dca1995-08-30 23:43:03 +0000676};
677
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000678static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000679bsdhashopen(PyObject *self, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000680{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000681 char *file;
682 char *flag = NULL;
683 int flags = O_RDONLY;
684 int mode = 0666;
685 int bsize = 0;
686 int ffactor = 0;
687 int nelem = 0;
688 int cachesize = 0;
689 int hash = 0; /* XXX currently ignored */
690 int lorder = 0;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000691
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000692 if (!PyArg_ParseTuple(args, "z|siiiiiii:hashopen",
693 &file, &flag, &mode,
694 &bsize, &ffactor, &nelem, &cachesize,
695 &hash, &lorder))
696 return NULL;
697 if (flag != NULL) {
698 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
699 if (flag[0] == 'r')
700 flags = O_RDONLY;
701 else if (flag[0] == 'w')
702 flags = O_RDWR;
703 else if (flag[0] == 'c')
704 flags = O_RDWR|O_CREAT;
705 else if (flag[0] == 'n')
706 flags = O_RDWR|O_CREAT|O_TRUNC;
707 else {
708 PyErr_SetString(BsddbError,
709 "Flag should begin with 'r', 'w', 'c' or 'n'");
710 return NULL;
711 }
712 if (flag[1] == 'l') {
Guido van Rossum1100dca1995-08-30 23:43:03 +0000713#if defined(O_EXLOCK) && defined(O_SHLOCK)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000714 if (flag[0] == 'r')
715 flags |= O_SHLOCK;
716 else
717 flags |= O_EXLOCK;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000718#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000719 PyErr_SetString(BsddbError,
720 "locking not supported on this platform");
721 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000722#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000723 }
724 }
725 return newdbhashobject(file, flags, mode,
726 bsize, ffactor, nelem, cachesize, hash, lorder);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000727}
728
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000729static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000730bsdbtopen(PyObject *self, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000731{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000732 char *file;
733 char *flag = NULL;
734 int flags = O_RDONLY;
735 int mode = 0666;
736 int cachesize = 0;
737 int maxkeypage = 0;
738 int minkeypage = 0;
739 int btflags = 0;
740 unsigned int psize = 0;
741 int lorder = 0;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000742
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000743 if (!PyArg_ParseTuple(args, "z|siiiiiii:btopen",
744 &file, &flag, &mode,
745 &btflags, &cachesize, &maxkeypage, &minkeypage,
746 &psize, &lorder))
747 return NULL;
748 if (flag != NULL) {
749 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
750 if (flag[0] == 'r')
751 flags = O_RDONLY;
752 else if (flag[0] == 'w')
753 flags = O_RDWR;
754 else if (flag[0] == 'c')
755 flags = O_RDWR|O_CREAT;
756 else if (flag[0] == 'n')
757 flags = O_RDWR|O_CREAT|O_TRUNC;
758 else {
759 PyErr_SetString(BsddbError,
760 "Flag should begin with 'r', 'w', 'c' or 'n'");
761 return NULL;
762 }
763 if (flag[1] == 'l') {
Guido van Rossum1100dca1995-08-30 23:43:03 +0000764#if defined(O_EXLOCK) && defined(O_SHLOCK)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000765 if (flag[0] == 'r')
766 flags |= O_SHLOCK;
767 else
768 flags |= O_EXLOCK;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000769#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000770 PyErr_SetString(BsddbError,
771 "locking not supported on this platform");
772 return NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000773#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000774 }
775 }
776 return newdbbtobject(file, flags, mode,
777 btflags, cachesize, maxkeypage, minkeypage,
778 psize, lorder);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000779}
Guido van Rossumdd96ca71996-05-23 22:57:54 +0000780
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000781static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000782bsdrnopen(PyObject *self, PyObject *args)
Guido van Rossum1100dca1995-08-30 23:43:03 +0000783{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000784 char *file;
785 char *flag = NULL;
786 int flags = O_RDONLY;
787 int mode = 0666;
788 int cachesize = 0;
789 int rnflags = 0;
790 unsigned int psize = 0;
791 int lorder = 0;
792 size_t reclen = 0;
793 char *bval = "";
794 char *bfname = NULL;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000795
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000796 if (!PyArg_ParseTuple(args, "z|siiiiiiss:rnopen",
797 &file, &flag, &mode,
798 &rnflags, &cachesize, &psize, &lorder,
799 &reclen, &bval, &bfname))
800 return NULL;
Roger E. Massed9240d11997-01-16 22:05:33 +0000801
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000802 if (flag != NULL) {
803 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
804 if (flag[0] == 'r')
805 flags = O_RDONLY;
806 else if (flag[0] == 'w')
807 flags = O_RDWR;
808 else if (flag[0] == 'c')
809 flags = O_RDWR|O_CREAT;
810 else if (flag[0] == 'n')
811 flags = O_RDWR|O_CREAT|O_TRUNC;
812 else {
813 PyErr_SetString(BsddbError,
814 "Flag should begin with 'r', 'w', 'c' or 'n'");
815 return NULL;
816 }
817 if (flag[1] == 'l') {
Roger E. Massed9240d11997-01-16 22:05:33 +0000818#if defined(O_EXLOCK) && defined(O_SHLOCK)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000819 if (flag[0] == 'r')
820 flags |= O_SHLOCK;
821 else
822 flags |= O_EXLOCK;
Roger E. Massed9240d11997-01-16 22:05:33 +0000823#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000824 PyErr_SetString(BsddbError,
825 "locking not supported on this platform");
826 return NULL;
Roger E. Massed9240d11997-01-16 22:05:33 +0000827#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000828 }
829 else if (flag[1] != '\0') {
830 PyErr_SetString(BsddbError,
831 "Flag char 2 should be 'l' or absent");
832 return NULL;
833 }
834 }
835 return newdbrnobject(file, flags, mode, rnflags, cachesize,
836 psize, lorder, reclen, bval[0], bfname);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000837}
838
Guido van Rossumdfe8ad91996-07-24 00:51:20 +0000839static PyMethodDef bsddbmodule_methods[] = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000840 {"hashopen", (PyCFunction)bsdhashopen, METH_VARARGS},
841 {"btopen", (PyCFunction)bsdbtopen, METH_VARARGS},
842 {"rnopen", (PyCFunction)bsdrnopen, METH_VARARGS},
843 /* strictly for use by dbhhash!!! */
844 {"open", (PyCFunction)bsdhashopen, METH_VARARGS},
845 {0, 0},
Guido van Rossum1100dca1995-08-30 23:43:03 +0000846};
847
Mark Hammond62b1ab12002-07-23 06:31:15 +0000848PyMODINIT_FUNC
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000849initbsddb185(void) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000850 PyObject *m, *d;
Guido van Rossum1100dca1995-08-30 23:43:03 +0000851
Brett Cannon768d44f2008-05-10 02:47:54 +0000852 if (PyErr_WarnPy3k("the bsddb185 module has been removed in "
853 "Python 3.0", 2) < 0)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000854 return;
Brett Cannon768d44f2008-05-10 02:47:54 +0000855
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000856 Bsddbtype.ob_type = &PyType_Type;
857 m = Py_InitModule("bsddb185", bsddbmodule_methods);
858 if (m == NULL)
859 return;
860 d = PyModule_GetDict(m);
861 BsddbError = PyErr_NewException("bsddb.error", NULL, NULL);
862 if (BsddbError != NULL)
863 PyDict_SetItemString(d, "error", BsddbError);
Guido van Rossum1100dca1995-08-30 23:43:03 +0000864}