Commit ef9764f1 authored by Jesus Cea's avatar Jesus Cea

bsddb module updated to version 4.6.4

parent bbb09375
......@@ -25,6 +25,8 @@ Extension Modules
- Support for Windows9x has been removed from the winsound module.
- bsddb module updated to version 4.6.4.
Library
-------
......
......@@ -36,7 +36,7 @@
/*
* Handwritten code to wrap version 3.x of the Berkeley DB library,
* written to replace a SWIG-generated file. It has since been updated
* to compile with BerkeleyDB versions 3.2 through 4.2.
* to compile with Berkeley DB versions 3.2 through 4.2.
*
* This module was started by Andrew Kuchling to remove the dependency
* on SWIG in a package by Gregory P. Smith who based his work on a
......@@ -48,7 +48,10 @@
* the DB 3.x API and to build a solid unit test suite. Robin has
* since gone onto other projects (wxPython).
*
* Gregory P. Smith <greg@krypto.org> is once again the maintainer.
* Gregory P. Smith <greg@krypto.org> was once again the maintainer.
*
* Since January 2008, new maintainer is Jesus Cea <jcea@argo.es>.
* Jesus Cea licenses this code to PSF under a Contributor Agreement.
*
* Use the pybsddb-users@lists.sf.net mailing list for all questions.
* Things can change faster than the header of this file is updated. This
......@@ -183,6 +186,10 @@ static PyObject* DBFileExistsError; /* EEXIST */
static PyObject* DBNoSuchFileError; /* ENOENT */
static PyObject* DBPermissionsError; /* EPERM */
#if (DBVER >= 42)
static PyObject* DBRepHandleDeadError; /* DB_REP_HANDLE_DEAD */
#endif
#if (DBVER < 43)
#define DB_BUFFER_SMALL ENOMEM
#endif
......@@ -202,6 +209,9 @@ static PyObject* DBPermissionsError; /* EPERM */
staticforward PyTypeObject DB_Type, DBCursor_Type, DBEnv_Type, DBTxn_Type, DBLock_Type;
#if (DBVER >= 43)
staticforward PyTypeObject DBSequence_Type;
#endif
#ifndef Py_TYPE
/* for compatibility with Python 2.5 and earlier */
......@@ -217,10 +227,77 @@ staticforward PyTypeObject DB_Type, DBCursor_Type, DBEnv_Type, DBTxn_Type, DBLoc
#define DBSequenceObject_Check(v) (Py_TYPE(v) == &DBSequence_Type)
#endif
#if (DBVER < 46)
#define _DBC_close(dbc) dbc->c_close(dbc)
#define _DBC_count(dbc,a,b) dbc->c_count(dbc,a,b)
#define _DBC_del(dbc,a) dbc->c_del(dbc,a)
#define _DBC_dup(dbc,a,b) dbc->c_dup(dbc,a,b)
#define _DBC_get(dbc,a,b,c) dbc->c_get(dbc,a,b,c)
#define _DBC_pget(dbc,a,b,c,d) dbc->c_pget(dbc,a,b,c,d)
#define _DBC_put(dbc,a,b,c) dbc->c_put(dbc,a,b,c)
#else
#define _DBC_close(dbc) dbc->close(dbc)
#define _DBC_count(dbc,a,b) dbc->count(dbc,a,b)
#define _DBC_del(dbc,a) dbc->del(dbc,a)
#define _DBC_dup(dbc,a,b) dbc->dup(dbc,a,b)
#define _DBC_get(dbc,a,b,c) dbc->get(dbc,a,b,c)
#define _DBC_pget(dbc,a,b,c,d) dbc->pget(dbc,a,b,c,d)
#define _DBC_put(dbc,a,b,c) dbc->put(dbc,a,b,c)
#endif
/* --------------------------------------------------------------------- */
/* Utility macros and functions */
#define INSERT_IN_DOUBLE_LINKED_LIST(backlink,object) \
{ \
object->sibling_next=backlink; \
object->sibling_prev_p=&(backlink); \
backlink=object; \
if (object->sibling_next) { \
object->sibling_next->sibling_prev_p=&(object->sibling_next); \
} \
}
#define EXTRACT_FROM_DOUBLE_LINKED_LIST(object) \
{ \
if (object->sibling_next) { \
object->sibling_next->sibling_prev_p=object->sibling_prev_p; \
} \
*(object->sibling_prev_p)=object->sibling_next; \
}
#define EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(object) \
{ \
if (object->sibling_next) { \
object->sibling_next->sibling_prev_p=object->sibling_prev_p; \
} \
if (object->sibling_prev_p) { \
*(object->sibling_prev_p)=object->sibling_next; \
} \
}
#define INSERT_IN_DOUBLE_LINKED_LIST_TXN(backlink,object) \
{ \
object->sibling_next_txn=backlink; \
object->sibling_prev_p_txn=&(backlink); \
backlink=object; \
if (object->sibling_next_txn) { \
object->sibling_next_txn->sibling_prev_p_txn= \
&(object->sibling_next_txn); \
} \
}
#define EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(object) \
{ \
if (object->sibling_next_txn) { \
object->sibling_next_txn->sibling_prev_p_txn= \
object->sibling_prev_p_txn; \
} \
*(object->sibling_prev_p_txn)=object->sibling_next_txn; \
}
#define RETURN_IF_ERR() \
if (makeDBError(err)) { \
return NULL; \
......@@ -443,6 +520,66 @@ static void _db_errorCallback(const DB_ENV *db_env,
}
/*
** We need these functions because some results
** are undefined if pointer is NULL. Some other
** give None instead of "".
**
** This functions are static and will be
** -I hope- inlined.
*/
static const char *DummyString = "This string is a simple placeholder";
static PyObject *Build_PyString(const char *p,int s)
{
if (!p) {
p=DummyString;
assert(s==0);
}
return PyString_FromStringAndSize(p,s);
}
static PyObject *BuildValue_S(const void *p,int s)
{
if (!p) {
p=DummyString;
assert(s==0);
}
return Py_BuildValue("s#",p,s);
}
static PyObject *BuildValue_SS(const void *p1,int s1,const void *p2,int s2)
{
if (!p1) {
p1=DummyString;
assert(s1==0);
}
if (!p2) {
p2=DummyString;
assert(s2==0);
}
return Py_BuildValue("s#s#",p1,s1,p2,s2);
}
static PyObject *BuildValue_IS(int i,const void *p,int s)
{
if (!p) {
p=DummyString;
assert(s==0);
}
return Py_BuildValue("is#",i,p,s);
}
static PyObject *BuildValue_LS(long i,const void *p,int s)
{
if (!p) {
p=DummyString;
assert(s==0);
}
return Py_BuildValue("ls#",i,p,s);
}
/* make a nice exception object to raise for errors. */
static int makeDBError(int err)
{
......@@ -505,6 +642,10 @@ static int makeDBError(int err)
case ENOENT: errObj = DBNoSuchFileError; break;
case EPERM : errObj = DBPermissionsError; break;
#if (DBVER >= 42)
case DB_REP_HANDLE_DEAD : errObj = DBRepHandleDeadError; break;
#endif
default: errObj = DBError; break;
}
......@@ -608,16 +749,11 @@ static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags,
flags |= extra_flags;
CLEAR_DBT(key);
CLEAR_DBT(data);
if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
data.flags = DB_DBT_MALLOC;
key.flags = DB_DBT_MALLOC;
}
if (!add_partial_dbt(&data, dlen, doff))
return NULL;
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags);
err = _DBC_get(self->dbc, &key, &data, flags);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
......@@ -638,21 +774,15 @@ static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags,
case DB_RECNO:
case DB_QUEUE:
retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
data.data, data.size);
retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
break;
case DB_HASH:
case DB_BTREE:
default:
retval = Py_BuildValue("s#s#", key.data, key.size,
data.data, data.size);
retval = BuildValue_SS(key.data, key.size, data.data, data.size);
break;
}
}
if (!err) {
FREE_DBT(key);
FREE_DBT(data);
}
return retval;
}
......@@ -672,7 +802,7 @@ static void _addTimeTToDict(PyObject* dict, char *name, time_t value)
{
PyObject* v;
/* if the value fits in regular int, use that. */
#ifdef HAVE_LONG_LONG
#ifdef PY_LONG_LONG
if (sizeof(time_t) > sizeof(long))
v = PyLong_FromLongLong((PY_LONG_LONG) value);
else
......@@ -696,7 +826,16 @@ static void _addDb_seq_tToDict(PyObject* dict, char *name, db_seq_t value)
}
#endif
#if (DBVER >= 40)
static void _addDB_lsnToDict(PyObject* dict, char *name, DB_LSN value)
{
PyObject *v = Py_BuildValue("(ll)",value.file,value.offset);
if (!v || PyDict_SetItemString(dict, name, v))
PyErr_Clear();
Py_XDECREF(v);
}
#endif
/* --------------------------------------------------------------------- */
/* Allocators and deallocators */
......@@ -716,6 +855,10 @@ newDBObject(DBEnvObject* arg, int flags)
self->flags = 0;
self->setflags = 0;
self->myenvobj = NULL;
self->children_cursors = NULL;
#if (DBVER >=43)
self->children_sequences = NULL;
#endif
#if (DBVER >= 33)
self->associateCallback = NULL;
self->btCompareCallback = NULL;
......@@ -728,7 +871,14 @@ newDBObject(DBEnvObject* arg, int flags)
Py_INCREF(arg);
self->myenvobj = arg;
db_env = arg->db_env;
INSERT_IN_DOUBLE_LINKED_LIST(self->myenvobj->children_dbs,self);
} else {
self->sibling_prev_p=NULL;
self->sibling_next=NULL;
}
self->txn=NULL;
self->sibling_prev_p_txn=NULL;
self->sibling_next_txn=NULL;
if (self->myenvobj)
self->moduleFlags = self->myenvobj->moduleFlags;
......@@ -760,23 +910,17 @@ newDBObject(DBEnvObject* arg, int flags)
}
/* Forward declaration */
static PyObject *DB_close_internal(DBObject* self, int flags);
static void
DB_dealloc(DBObject* self)
{
PyObject *dummy;
if (self->db != NULL) {
/* avoid closing a DB when its DBEnv has been closed out from under
* it */
if (!self->myenvobj ||
(self->myenvobj && self->myenvobj->db_env))
{
MYDB_BEGIN_ALLOW_THREADS;
self->db->close(self->db, 0);
MYDB_END_ALLOW_THREADS;
} else {
PyErr_Warn(PyExc_RuntimeWarning,
"DB could not be closed in destructor: DBEnv already closed");
}
self->db = NULL;
dummy=DB_close_internal(self,0);
Py_XDECREF(dummy);
}
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
......@@ -798,9 +942,8 @@ DB_dealloc(DBObject* self)
PyObject_Del(self);
}
static DBCursorObject*
newDBCursorObject(DBC* dbc, DBObject* db)
newDBCursorObject(DBC* dbc, DBTxnObject *txn, DBObject* db)
{
DBCursorObject* self = PyObject_New(DBCursorObject, &DBCursor_Type);
if (self == NULL)
......@@ -808,40 +951,37 @@ newDBCursorObject(DBC* dbc, DBObject* db)
self->dbc = dbc;
self->mydb = db;
INSERT_IN_DOUBLE_LINKED_LIST(self->mydb->children_cursors,self);
if (txn && ((PyObject *)txn!=Py_None)) {
INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->children_cursors,self);
self->txn=txn;
} else {
self->txn=NULL;
}
self->in_weakreflist = NULL;
Py_INCREF(self->mydb);
return self;
}
/* Forward declaration */
static PyObject *DBC_close_internal(DBCursorObject* self);
static void
DBCursor_dealloc(DBCursorObject* self)
{
int err;
PyObject *dummy;
if (self->dbc != NULL) {
dummy=DBC_close_internal(self);
Py_XDECREF(dummy);
}
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
}
if (self->dbc != NULL) {
/* If the underlying database has been closed, we don't
need to do anything. If the environment has been closed
we need to leak, as BerkeleyDB will crash trying to access
the environment. There was an exception when the
user closed the environment even though there still was
a database open. */
if (self->mydb->db && self->mydb->myenvobj &&
!self->mydb->myenvobj->closed)
/* test for: open db + no environment or non-closed environment */
if (self->mydb->db && (!self->mydb->myenvobj || (self->mydb->myenvobj &&
!self->mydb->myenvobj->closed))) {
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_close(self->dbc);
MYDB_END_ALLOW_THREADS;
}
self->dbc = NULL;
}
Py_XDECREF( self->mydb );
Py_DECREF(self->mydb);
PyObject_Del(self);
}
......@@ -858,8 +998,14 @@ newDBEnvObject(int flags)
self->flags = flags;
self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
self->children_dbs = NULL;
self->children_txns = NULL;
self->in_weakreflist = NULL;
#if (DBVER >= 40)
self->event_notifyCallback = NULL;
#endif
MYDB_BEGIN_ALLOW_THREADS;
err = db_env_create(&self->db_env, flags);
MYDB_END_ALLOW_THREADS;
......@@ -869,75 +1015,119 @@ newDBEnvObject(int flags)
}
else {
self->db_env->set_errcall(self->db_env, _db_errorCallback);
self->db_env->app_private=self;
}
return self;
}
/* Forward declaration */
static PyObject *DBEnv_close_internal(DBEnvObject* self, int flags);
static void
DBEnv_dealloc(DBEnvObject* self)
{
PyObject *dummy;
if (self->db_env && !self->closed) {
dummy=DBEnv_close_internal(self,0);
Py_XDECREF(dummy);
}
#if (DBVER >= 40)
Py_XDECREF(self->event_notifyCallback);
self->event_notifyCallback = NULL;
#endif
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
}
if (self->db_env && !self->closed) {
MYDB_BEGIN_ALLOW_THREADS;
self->db_env->close(self->db_env, 0);
MYDB_END_ALLOW_THREADS;
}
PyObject_Del(self);
}
static DBTxnObject*
newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags)
newDBTxnObject(DBEnvObject* myenv, DBTxnObject *parent, DB_TXN *txn, int flags)
{
int err;
DB_TXN *parent_txn=NULL;
DBTxnObject* self = PyObject_New(DBTxnObject, &DBTxn_Type);
if (self == NULL)
return NULL;
Py_INCREF(myenv);
self->env = (PyObject*)myenv;
self->in_weakreflist = NULL;
MYDB_BEGIN_ALLOW_THREADS;
if (parent && ((PyObject *)parent!=Py_None)) {
parent_txn=parent->txn;
}
if (txn) {
self->txn=txn;
} else {
MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 40)
err = myenv->db_env->txn_begin(myenv->db_env, parent, &(self->txn), flags);
err = myenv->db_env->txn_begin(myenv->db_env, parent_txn, &(self->txn), flags);
#else
err = txn_begin(myenv->db_env, parent, &(self->txn), flags);
err = txn_begin(myenv->db_env, parent->txn, &(self_txn), flags);
#endif
MYDB_END_ALLOW_THREADS;
if (makeDBError(err)) {
Py_DECREF(self->env);
PyObject_Del(self);
self = NULL;
MYDB_END_ALLOW_THREADS;
if (makeDBError(err)) {
PyObject_Del(self);
return NULL;
}
}
if (parent_txn) { /* Can't use 'parent' because could be 'parent==Py_None' */
self->parent_txn=parent;
Py_INCREF(parent);
self->env = NULL;
INSERT_IN_DOUBLE_LINKED_LIST(parent->children_txns,self);
} else {
self->parent_txn=NULL;
Py_INCREF(myenv);
self->env = myenv;
INSERT_IN_DOUBLE_LINKED_LIST(myenv->children_txns,self);
}
self->children_txns=NULL;
self->children_dbs=NULL;
self->children_cursors=NULL;
self->children_sequences=NULL;
self->flag_prepare=0;
return self;
}
/* Forward declaration */
static PyObject *
DBTxn_abort_discard_internal(DBTxnObject* self, int discard);
static void
DBTxn_dealloc(DBTxnObject* self)
{
PyObject *dummy;
if (self->txn) {
int flag_prepare = self->flag_prepare;
dummy=DBTxn_abort_discard_internal(self,0);
Py_XDECREF(dummy);
if (!flag_prepare) {
PyErr_Warn(PyExc_RuntimeWarning,
"DBTxn aborted in destructor. No prior commit() or abort().");
}
}
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
}
if (self->txn) {
/* it hasn't been finalized, abort it! */
MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 40)
self->txn->abort(self->txn);
#else
txn_abort(self->txn);
#endif
MYDB_END_ALLOW_THREADS;
PyErr_Warn(PyExc_RuntimeWarning,
"DBTxn aborted in destructor. No prior commit() or abort().");
if (self->env) {
Py_DECREF(self->env);
} else {
Py_DECREF(self->parent_txn);
}
Py_DECREF(self->env);
PyObject_Del(self);
}
......@@ -991,8 +1181,11 @@ newDBSequenceObject(DBObject* mydb, int flags)
return NULL;
Py_INCREF(mydb);
self->mydb = mydb;
self->in_weakreflist = NULL;
INSERT_IN_DOUBLE_LINKED_LIST(self->mydb->children_sequences,self);
self->txn=NULL;
self->in_weakreflist = NULL;
MYDB_BEGIN_ALLOW_THREADS;
err = db_sequence_create(&self->sequence, self->mydb->db, flags);
......@@ -1006,10 +1199,20 @@ newDBSequenceObject(DBObject* mydb, int flags)
return self;
}
/* Forward declaration */
static PyObject
*DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close);
static void
DBSequence_dealloc(DBSequenceObject* self)
{
PyObject *dummy;
if (self->sequence != NULL) {
dummy=DBSequence_close_internal(self,0,0);
Py_XDECREF(dummy);
}
if (self->in_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
}
......@@ -1072,11 +1275,9 @@ _db_associateCallback(DB* db, const DBT* priKey, const DBT* priData,
MYDB_BEGIN_BLOCK_THREADS;
if (type == DB_RECNO || type == DB_QUEUE)
args = Py_BuildValue("(ls#)", *((db_recno_t*)priKey->data),
priData->data, priData->size);
args = BuildValue_LS(*((db_recno_t*)priKey->data), priData->data, priData->size);
else
args = Py_BuildValue("(s#s#)", priKey->data, priKey->size,
priData->data, priData->size);
args = BuildValue_SS(priKey->data, priKey->size, priData->data, priData->size);
if (args != NULL) {
result = PyEval_CallObject(callback, args);
}
......@@ -1217,21 +1418,49 @@ DB_associate(DBObject* self, PyObject* args, PyObject* kwargs)
static PyObject*
DB_close(DBObject* self, PyObject* args)
DB_close_internal(DBObject* self, int flags)
{
int err, flags=0;
if (!PyArg_ParseTuple(args,"|i:close", &flags))
return NULL;
PyObject *dummy;
int err;
if (self->db != NULL) {
if (self->myenvobj)
CHECK_ENV_NOT_CLOSED(self->myenvobj);
/* Can be NULL if db is not in an environment */
EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(self);
if (self->txn) {
EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
self->txn=NULL;
}
while(self->children_cursors) {
dummy=DBC_close_internal(self->children_cursors);
Py_XDECREF(dummy);
}
#if (DBVER >= 43)
while(self->children_sequences) {
dummy=DBSequence_close_internal(self->children_sequences,0,0);
Py_XDECREF(dummy);
}
#endif
MYDB_BEGIN_ALLOW_THREADS;
err = self->db->close(self->db, flags);
MYDB_END_ALLOW_THREADS;
self->db = NULL;
RETURN_IF_ERR();
}
RETURN_NONE();
}
static PyObject*
DB_close(DBObject* self, PyObject* args)
{
int flags=0;
if (!PyArg_ParseTuple(args,"|i:close", &flags))
return NULL;
return DB_close_internal(self,flags);
}
static PyObject*
_DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
......@@ -1262,7 +1491,7 @@ _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
CLEAR_DBT(key);
CLEAR_DBT(data);
if (CHECK_DBFLAG(self, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
/* Tell Berkeley DB to malloc the return value (thread safe) */
data.flags = DB_DBT_MALLOC;
key.flags = DB_DBT_MALLOC;
}
......@@ -1278,8 +1507,7 @@ _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
retval = Py_None;
}
else if (!err) {
retval = Py_BuildValue("s#s#", key.data, key.size, data.data,
data.size);
retval = BuildValue_SS(key.data, key.size, data.data, data.size);
FREE_DBT(key);
FREE_DBT(data);
}
......@@ -1322,7 +1550,7 @@ DB_cursor(DBObject* self, PyObject* args, PyObject* kwargs)
err = self->db->cursor(self->db, txn, &dbc, flags);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
return (PyObject*) newDBCursorObject(dbc, self);
return (PyObject*) newDBCursorObject(dbc, (DBTxnObject *)txnobj, self);
}
......@@ -1404,7 +1632,7 @@ DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
CLEAR_DBT(data);
if (CHECK_DBFLAG(self, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
/* Tell Berkeley DB to malloc the return value (thread safe) */
data.flags = DB_DBT_MALLOC;
}
if (!add_partial_dbt(&data, dlen, doff)) {
......@@ -1429,10 +1657,9 @@ DB_get(DBObject* self, PyObject* args, PyObject* kwargs)
}
else if (!err) {
if (flags & DB_SET_RECNO) /* return both key and data */
retval = Py_BuildValue("s#s#", key.data, key.size, data.data,
data.size);
retval = BuildValue_SS(key.data, key.size, data.data, data.size);
else /* return just the data */
retval = PyString_FromStringAndSize((char*)data.data, data.size);
retval = Build_PyString(data.data, data.size);
FREE_DBT(data);
}
FREE_DBT(key);
......@@ -1472,7 +1699,7 @@ DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
CLEAR_DBT(data);
if (CHECK_DBFLAG(self, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
/* Tell Berkeley DB to malloc the return value (thread safe) */
data.flags = DB_DBT_MALLOC;
}
if (!add_partial_dbt(&data, dlen, doff)) {
......@@ -1501,13 +1728,13 @@ DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
else if (!err) {
PyObject *pkeyObj;
PyObject *dataObj;
dataObj = PyString_FromStringAndSize(data.data, data.size);
dataObj = Build_PyString(data.data, data.size);
if (self->primaryDBType == DB_RECNO ||
self->primaryDBType == DB_QUEUE)
pkeyObj = PyInt_FromLong(*(int *)pkey.data);
else
pkeyObj = PyString_FromStringAndSize(pkey.data, pkey.size);
pkeyObj = Build_PyString(pkey.data, pkey.size);
if (flags & DB_SET_RECNO) /* return key , pkey and data */
{
......@@ -1516,7 +1743,7 @@ DB_pget(DBObject* self, PyObject* args, PyObject* kwargs)
if (type == DB_RECNO || type == DB_QUEUE)
keyObj = PyInt_FromLong(*(int *)key.data);
else
keyObj = PyString_FromStringAndSize(key.data, key.size);
keyObj = Build_PyString(key.data, key.size);
#if (PY_VERSION_HEX >= 0x02040000)
retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
#else
......@@ -1620,7 +1847,7 @@ DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs)
orig_data = data.data;
if (CHECK_DBFLAG(self, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
/* Tell Berkeley DB to malloc the return value (thread safe) */
/* XXX(nnorwitz): At least 4.4.20 and 4.5.20 require this flag. */
data.flags = DB_DBT_MALLOC;
}
......@@ -1637,7 +1864,7 @@ DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs)
}
else if (!err) {
/* XXX(nnorwitz): can we do: retval = dataobj; Py_INCREF(retval); */
retval = PyString_FromStringAndSize((char*)data.data, data.size);
retval = Build_PyString(data.data, data.size);
/* Even though the flags require DB_DBT_MALLOC, data is not always
allocated. 4.4: allocated, 4.5: *not* allocated. :-( */
......@@ -1748,7 +1975,7 @@ DB_join(DBObject* self, PyObject* args)
but does not hold python references to them or prevent
them from being closed prematurely. This can cause
python to crash when things are done in the wrong order. */
return (PyObject*) newDBCursorObject(dbc, self);
return (PyObject*) newDBCursorObject(dbc, NULL, self);
}
......@@ -1845,6 +2072,17 @@ DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
return NULL;
}
#if (DBVER >= 41)
if (txn) { /* Can't use 'txnobj' because could be 'txnobj==Py_None' */
INSERT_IN_DOUBLE_LINKED_LIST_TXN(((DBTxnObject *)txnobj)->children_dbs,self);
self->txn=(DBTxnObject *)txnobj;
} else {
self->txn=NULL;
}
#else
self->txn=NULL;
#endif
MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 41)
err = self->db->open(self->db, txn, filename, dbname, type, flags, mode);
......@@ -1853,8 +2091,10 @@ DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
#endif
MYDB_END_ALLOW_THREADS;
if (makeDBError(err)) {
self->db->close(self->db, 0);
self->db = NULL;
PyObject *dummy;
dummy=DB_close_internal(self,0);
Py_XDECREF(dummy);
return NULL;
}
......@@ -1863,6 +2103,7 @@ DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
#endif
self->flags = flags;
RETURN_NONE();
}
......@@ -1993,7 +2234,7 @@ _default_cmp(const DBT *leftKey,
}
static int
_db_compareCallback(DB* db,
_db_compareCallback(DB* db,
const DBT *leftKey,
const DBT *rightKey)
{
......@@ -2015,8 +2256,7 @@ _db_compareCallback(DB* db,
} else {
MYDB_BEGIN_BLOCK_THREADS;
args = Py_BuildValue("s#s#", leftKey->data, leftKey->size,
rightKey->data, rightKey->size);
args = BuildValue_SS(leftKey->data, leftKey->size, rightKey->data, rightKey->size);
if (args != NULL) {
/* XXX(twouters) I highly doubt this INCREF is correct */
Py_INCREF(self);
......@@ -2369,6 +2609,9 @@ DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
MAKE_HASH_ENTRY(version);
MAKE_HASH_ENTRY(nkeys);
MAKE_HASH_ENTRY(ndata);
#if (DBVER >= 46)
MAKE_HASH_ENTRY(pagecnt);
#endif
MAKE_HASH_ENTRY(pagesize);
#if (DBVER < 41)
MAKE_HASH_ENTRY(nelem);
......@@ -2391,6 +2634,9 @@ DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
MAKE_BT_ENTRY(version);
MAKE_BT_ENTRY(nkeys);
MAKE_BT_ENTRY(ndata);
#if (DBVER >= 46)
MAKE_BT_ENTRY(pagecnt);
#endif
MAKE_BT_ENTRY(pagesize);
MAKE_BT_ENTRY(minkey);
MAKE_BT_ENTRY(re_len);
......@@ -2400,6 +2646,9 @@ DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
MAKE_BT_ENTRY(leaf_pg);
MAKE_BT_ENTRY(dup_pg);
MAKE_BT_ENTRY(over_pg);
#if (DBVER >= 43)
MAKE_BT_ENTRY(empty_pg);
#endif
MAKE_BT_ENTRY(free);
MAKE_BT_ENTRY(int_pgfree);
MAKE_BT_ENTRY(leaf_pgfree);
......@@ -2413,6 +2662,9 @@ DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
MAKE_QUEUE_ENTRY(nkeys);
MAKE_QUEUE_ENTRY(ndata);
MAKE_QUEUE_ENTRY(pagesize);
#if (DBVER > 40)
MAKE_QUEUE_ENTRY(extentsize);
#endif
MAKE_QUEUE_ENTRY(pages);
MAKE_QUEUE_ENTRY(re_len);
MAKE_QUEUE_ENTRY(re_pad);
......@@ -2527,15 +2779,14 @@ DB_verify(DBObject* self, PyObject* args, PyObject* kwargs)
if (outFile)
fclose(outFile);
/* DB.verify acts as a DB handle destructor (like close); this was
* documented in BerkeleyDB 4.2 but had the undocumented effect
* of not being safe in prior versions while still requiring an explicit
* DB.close call afterwards. Lets call close for the user to emulate
* the safe 4.2 behaviour. */
#if (DBVER <= 41)
self->db->close(self->db, 0);
#endif
self->db = NULL;
{ /* DB.verify acts as a DB handle destructor (like close) */
PyObject *error;
error=DB_close_internal(self,0);
if (error ) {
return error;
}
}
RETURN_IF_ERR();
RETURN_NONE();
......@@ -2622,7 +2873,7 @@ redo_stat_for_length:
so we can use any of them for the type cast */
size = ((DB_BTREE_STAT*)sp)->bt_ndata;
/* A size of 0 could mean that BerkeleyDB no longer had the stat values cached.
/* A size of 0 could mean that Berkeley DB no longer had the stat values cached.
* redo a full stat to make sure.
* Fixes SF python bug 1493322, pybsddb bug 1184012
*/
......@@ -2658,7 +2909,7 @@ PyObject* DB_subscript(DBObject* self, PyObject* keyobj)
CLEAR_DBT(data);
if (CHECK_DBFLAG(self, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
/* Tell Berkeley DB to malloc the return value (thread safe) */
data.flags = DB_DBT_MALLOC;
}
MYDB_BEGIN_ALLOW_THREADS;
......@@ -2672,7 +2923,7 @@ PyObject* DB_subscript(DBObject* self, PyObject* keyobj)
retval = NULL;
}
else {
retval = PyString_FromStringAndSize((char*)data.data, data.size);
retval = Build_PyString(data.data, data.size);
FREE_DBT(data);
}
......@@ -2802,14 +3053,9 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
return NULL;
}
if (CHECK_DBFLAG(self, DB_THREAD)) {
key.flags = DB_DBT_REALLOC;
data.flags = DB_DBT_REALLOC;
}
while (1) { /* use the cursor to traverse the DB, collecting items */
MYDB_BEGIN_ALLOW_THREADS;
err = cursor->c_get(cursor, &key, &data, DB_NEXT);
err = _DBC_get(cursor, &key, &data, DB_NEXT);
MYDB_END_ALLOW_THREADS;
if (err) {
......@@ -2823,7 +3069,7 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
case DB_BTREE:
case DB_HASH:
default:
item = PyString_FromStringAndSize((char*)key.data, key.size);
item = Build_PyString(key.data, key.size);
break;
case DB_RECNO:
case DB_QUEUE:
......@@ -2833,7 +3079,7 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
break;
case _VALUES_LIST:
item = PyString_FromStringAndSize((char*)data.data, data.size);
item = Build_PyString(data.data, data.size);
break;
case _ITEMS_LIST:
......@@ -2841,13 +3087,11 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
case DB_BTREE:
case DB_HASH:
default:
item = Py_BuildValue("s#s#", key.data, key.size, data.data,
data.size);
item = BuildValue_SS(key.data, key.size, data.data, data.size);
break;
case DB_RECNO:
case DB_QUEUE:
item = Py_BuildValue("is#", *((db_recno_t*)key.data),
data.data, data.size);
item = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
break;
}
break;
......@@ -2872,10 +3116,8 @@ _DB_make_list(DBObject* self, DB_TXN* txn, int type)
}
done:
FREE_DBT(key);
FREE_DBT(data);
MYDB_BEGIN_ALLOW_THREADS;
cursor->c_close(cursor);
_DBC_close(cursor);
MYDB_END_ALLOW_THREADS;
return list;
}
......@@ -2927,23 +3169,35 @@ DB_values(DBObject* self, PyObject* args)
static PyObject*
DBC_close(DBCursorObject* self, PyObject* args)
DBC_close_internal(DBCursorObject* self)
{
int err = 0;
if (!PyArg_ParseTuple(args, ":close"))
return NULL;
if (self->dbc != NULL) {
EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
if (self->txn) {
EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
self->txn=NULL;
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_close(self->dbc);
self->dbc = NULL;
err = _DBC_close(self->dbc);
MYDB_END_ALLOW_THREADS;
self->dbc = NULL;
}
RETURN_IF_ERR();
RETURN_NONE();
}
static PyObject*
DBC_close(DBCursorObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ":close"))
return NULL;
return DBC_close_internal(self);
}
static PyObject*
DBC_count(DBCursorObject* self, PyObject* args)
......@@ -2958,7 +3212,7 @@ DBC_count(DBCursorObject* self, PyObject* args)
CHECK_CURSOR_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_count(self->dbc, &count, flags);
err = _DBC_count(self->dbc, &count, flags);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
......@@ -2984,7 +3238,7 @@ DBC_delete(DBCursorObject* self, PyObject* args)
CHECK_CURSOR_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_del(self->dbc, flags);
err = _DBC_del(self->dbc, flags);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
......@@ -3005,11 +3259,11 @@ DBC_dup(DBCursorObject* self, PyObject* args)
CHECK_CURSOR_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_dup(self->dbc, &dbc, flags);
err = _DBC_dup(self->dbc, &dbc, flags);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
return (PyObject*) newDBCursorObject(dbc, self->mydb);
return (PyObject*) newDBCursorObject(dbc, self->txn, self->mydb);
}
static PyObject*
......@@ -3059,19 +3313,12 @@ DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
if ( (dataobj && !make_dbt(dataobj, &data)) ||
(!add_partial_dbt(&data, dlen, doff)) )
{
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
return NULL;
}
if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
data.flags = DB_DBT_MALLOC;
if (!(key.flags & DB_DBT_REALLOC)) {
key.flags |= DB_DBT_MALLOC;
}
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags);
err = _DBC_get(self->dbc, &key, &data, flags);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
......@@ -3090,18 +3337,15 @@ DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs)
case DB_BTREE:
case DB_HASH:
default:
retval = Py_BuildValue("s#s#", key.data, key.size,
data.data, data.size);
retval = BuildValue_SS(key.data, key.size, data.data, data.size);
break;
case DB_RECNO:
case DB_QUEUE:
retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
data.data, data.size);
retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
break;
}
FREE_DBT(data);
}
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
return retval;
}
......@@ -3145,22 +3389,15 @@ DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
return NULL;
if ( (dataobj && !make_dbt(dataobj, &data)) ||
(!add_partial_dbt(&data, dlen, doff)) ) {
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
return NULL;
}
if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
data.flags = DB_DBT_MALLOC;
if (!(key.flags & DB_DBT_REALLOC)) {
key.flags |= DB_DBT_MALLOC;
}
}
CLEAR_DBT(pkey);
pkey.flags = DB_DBT_MALLOC;
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_pget(self->dbc, &key, &pkey, &data, flags);
err = _DBC_pget(self->dbc, &key, &pkey, &data, flags);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
......@@ -3174,13 +3411,13 @@ DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
else {
PyObject *pkeyObj;
PyObject *dataObj;
dataObj = PyString_FromStringAndSize(data.data, data.size);
dataObj = Build_PyString(data.data, data.size);
if (self->mydb->primaryDBType == DB_RECNO ||
self->mydb->primaryDBType == DB_QUEUE)
pkeyObj = PyInt_FromLong(*(int *)pkey.data);
else
pkeyObj = PyString_FromStringAndSize(pkey.data, pkey.size);
pkeyObj = Build_PyString(pkey.data, pkey.size);
if (key.data && key.size) /* return key, pkey and data */
{
......@@ -3189,14 +3426,14 @@ DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
if (type == DB_RECNO || type == DB_QUEUE)
keyObj = PyInt_FromLong(*(int *)key.data);
else
keyObj = PyString_FromStringAndSize(key.data, key.size);
keyObj = Build_PyString(key.data, key.size);
#if (PY_VERSION_HEX >= 0x02040000)
retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
#else
retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj);
#endif
Py_DECREF(keyObj);
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
}
else /* return just the pkey and data */
{
......@@ -3209,11 +3446,10 @@ DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs)
Py_DECREF(dataObj);
Py_DECREF(pkeyObj);
FREE_DBT(pkey);
FREE_DBT(data);
}
/* the only time REALLOC should be set is if we used an integer
* key that make_key_dbt malloc'd for us. always free these. */
if (key.flags & DB_DBT_REALLOC) {
if (key.flags & DB_DBT_REALLOC) { /* 'make_key_dbt' could do a 'malloc' */
FREE_DBT(key);
}
return retval;
......@@ -3236,20 +3472,13 @@ DBC_get_recno(DBCursorObject* self, PyObject* args)
CLEAR_DBT(key);
CLEAR_DBT(data);
if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
data.flags = DB_DBT_MALLOC;
key.flags = DB_DBT_MALLOC;
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, DB_GET_RECNO);
err = _DBC_get(self->dbc, &key, &data, DB_GET_RECNO);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
recno = *((db_recno_t*)data.data);
FREE_DBT(key);
FREE_DBT(data);
return PyInt_FromLong(recno);
}
......@@ -3297,14 +3526,14 @@ DBC_put(DBCursorObject* self, PyObject* args, PyObject* kwargs)
if (!make_dbt(dataobj, &data) ||
!add_partial_dbt(&data, dlen, doff) )
{
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
return NULL;
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_put(self->dbc, &key, &data, flags);
err = _DBC_put(self->dbc, &key, &data, flags);
MYDB_END_ALLOW_THREADS;
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
RETURN_IF_ERR();
self->mydb->haveStat = 0;
RETURN_NONE();
......@@ -3331,17 +3560,13 @@ DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs)
return NULL;
CLEAR_DBT(data);
if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
data.flags = DB_DBT_MALLOC;
}
if (!add_partial_dbt(&data, dlen, doff)) {
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
return NULL;
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET);
err = _DBC_get(self->dbc, &key, &data, flags|DB_SET);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
&& self->mydb->moduleFlags.cursorSetReturnsNone) {
......@@ -3359,22 +3584,19 @@ DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs)
case DB_BTREE:
case DB_HASH:
default:
retval = Py_BuildValue("s#s#", key.data, key.size,
data.data, data.size);
retval = BuildValue_SS(key.data, key.size, data.data, data.size);
break;
case DB_RECNO:
case DB_QUEUE:
retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
data.data, data.size);
retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
break;
}
FREE_DBT(data);
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
}
/* the only time REALLOC should be set is if we used an integer
* key that make_key_dbt malloc'd for us. always free these. */
if (key.flags & DB_DBT_REALLOC) {
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
}
return retval;
......@@ -3402,19 +3624,11 @@ DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
CLEAR_DBT(data);
if (!add_partial_dbt(&data, dlen, doff)) {
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
return NULL;
}
if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
data.flags |= DB_DBT_MALLOC;
/* only BTREE databases will return anything in the key */
if (!(key.flags & DB_DBT_REALLOC) && _DB_get_type(self->mydb) == DB_BTREE) {
key.flags |= DB_DBT_MALLOC;
}
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
err = _DBC_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
&& self->mydb->moduleFlags.cursorSetReturnsNone) {
......@@ -3432,22 +3646,19 @@ DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs)
case DB_BTREE:
case DB_HASH:
default:
retval = Py_BuildValue("s#s#", key.data, key.size,
data.data, data.size);
retval = BuildValue_SS(key.data, key.size, data.data, data.size);
break;
case DB_RECNO:
case DB_QUEUE:
retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
data.data, data.size);
retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
break;
}
FREE_DBT(key);
FREE_DBT(data);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
}
/* the only time REALLOC should be set is if we used an integer
* key that make_key_dbt malloc'd for us. always free these. */
if (key.flags & DB_DBT_REALLOC) {
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
}
return retval;
......@@ -3465,12 +3676,12 @@ _DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
return NULL;
if (!make_dbt(dataobj, &data)) {
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
return NULL;
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_GET_BOTH);
err = _DBC_get(self->dbc, &key, &data, flags|DB_GET_BOTH);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && returnsNone) {
Py_INCREF(Py_None);
......@@ -3487,18 +3698,16 @@ _DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj,
case DB_BTREE:
case DB_HASH:
default:
retval = Py_BuildValue("s#s#", key.data, key.size,
data.data, data.size);
retval = BuildValue_SS(key.data, key.size, data.data, data.size);
break;
case DB_RECNO:
case DB_QUEUE:
retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
data.data, data.size);
retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size);
break;
}
}
FREE_DBT(key);
FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */
return retval;
}
......@@ -3537,7 +3746,7 @@ DBC_get_current_size(DBCursorObject* self, PyObject* args)
data.flags = DB_DBT_USERMEM;
data.ulen = 0;
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags);
err = _DBC_get(self->dbc, &key, &data, flags);
MYDB_END_ALLOW_THREADS;
if (err == DB_BUFFER_SMALL || !err) {
/* DB_BUFFER_SMALL means positive size, !err means zero length value */
......@@ -3545,8 +3754,6 @@ DBC_get_current_size(DBCursorObject* self, PyObject* args)
err = 0;
}
FREE_DBT(key);
FREE_DBT(data);
RETURN_IF_ERR();
return retval;
}
......@@ -3600,17 +3807,13 @@ DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
key.flags = DB_DBT_REALLOC;
CLEAR_DBT(data);
if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
data.flags = DB_DBT_MALLOC;
}
if (!add_partial_dbt(&data, dlen, doff)) {
FREE_DBT(key);
return NULL;
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RECNO);
err = _DBC_get(self->dbc, &key, &data, flags|DB_SET_RECNO);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
&& self->mydb->moduleFlags.cursorSetReturnsNone) {
......@@ -3621,9 +3824,7 @@ DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs)
retval = NULL;
}
else { /* Can only be used for BTrees, so no need to return int key */
retval = Py_BuildValue("s#s#", key.data, key.size,
data.data, data.size);
FREE_DBT(data);
retval = BuildValue_SS(key.data, key.size, data.data, data.size);
}
FREE_DBT(key);
......@@ -3673,13 +3874,9 @@ DBC_join_item(DBCursorObject* self, PyObject* args)
CLEAR_DBT(key);
CLEAR_DBT(data);
if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
/* Tell BerkeleyDB to malloc the return value (thread safe) */
key.flags = DB_DBT_MALLOC;
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->dbc->c_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM);
err = _DBC_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM);
MYDB_END_ALLOW_THREADS;
if ((err == DB_NOTFOUND || err == DB_KEYEMPTY)
&& self->mydb->moduleFlags.getReturnsNone) {
......@@ -3690,8 +3887,7 @@ DBC_join_item(DBCursorObject* self, PyObject* args)
retval = NULL;
}
else {
retval = Py_BuildValue("s#", key.data, key.size);
FREE_DBT(key);
retval = BuildValue_S(key.data, key.size);
}
return retval;
......@@ -3704,18 +3900,26 @@ DBC_join_item(DBCursorObject* self, PyObject* args)
static PyObject*
DBEnv_close(DBEnvObject* self, PyObject* args)
DBEnv_close_internal(DBEnvObject* self, int flags)
{
int err, flags = 0;
PyObject *dummy;
int err;
if (!PyArg_ParseTuple(args, "|i:close", &flags))
return NULL;
if (!self->closed) { /* Don't close more than once */
while(self->children_txns) {
dummy=DBTxn_abort_discard_internal(self->children_txns,0);
Py_XDECREF(dummy);
}
while(self->children_dbs) {
dummy=DB_close_internal(self->children_dbs,0);
Py_XDECREF(dummy);
}
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->close(self->db_env, flags);
MYDB_END_ALLOW_THREADS;
/* after calling DBEnv->close, regardless of error, this DBEnv
* may not be accessed again (BerkeleyDB docs). */
* may not be accessed again (Berkeley DB docs). */
self->closed = 1;
self->db_env = NULL;
RETURN_IF_ERR();
......@@ -3723,9 +3927,19 @@ DBEnv_close(DBEnvObject* self, PyObject* args)
RETURN_NONE();
}
static PyObject*
DBEnv_open(DBEnvObject* self, PyObject* args)
DBEnv_close(DBEnvObject* self, PyObject* args)
{
int flags = 0;
if (!PyArg_ParseTuple(args, "|i:close", &flags))
return NULL;
return DBEnv_close_internal(self,flags);
}
static PyObject*
DBEnv_open(DBEnvObject* self, PyObject* args)
{
int err, flags=0, mode=0660;
char *db_home;
......@@ -3982,6 +4196,25 @@ DBEnv_set_lg_max(DBEnvObject* self, PyObject* args)
RETURN_NONE();
}
#if (DBVER >= 42)
static PyObject*
DBEnv_get_lg_max(DBEnvObject* self, PyObject* args)
{
int err;
u_int32_t lg_max;
if (!PyArg_ParseTuple(args, ":get_lg_max"))
return NULL;
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->get_lg_max(self->db_env, &lg_max);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
return PyInt_FromLong(lg_max);
}
#endif
#if (DBVER >= 33)
static PyObject*
......@@ -4125,6 +4358,84 @@ DBEnv_set_tmp_dir(DBEnvObject* self, PyObject* args)
}
#if (DBVER >= 40)
static PyObject*
DBEnv_txn_recover(DBEnvObject* self, PyObject* args)
{
int flags = DB_FIRST;
int err, i;
PyObject *list, *tuple, *gid;
DBTxnObject *txn;
#define PREPLIST_LEN 16
DB_PREPLIST preplist[PREPLIST_LEN];
long retp;
if (!PyArg_ParseTuple(args, ":txn_recover"))
return NULL;
CHECK_ENV_NOT_CLOSED(self);
list=PyList_New(0);
if (!list)
return NULL;
while (!0) {
MYDB_BEGIN_ALLOW_THREADS
err=self->db_env->txn_recover(self->db_env,
preplist, PREPLIST_LEN, &retp, flags);
#undef PREPLIST_LEN
MYDB_END_ALLOW_THREADS
if (err) {
Py_DECREF(list);
RETURN_IF_ERR();
}
if (!retp) break;
flags=DB_NEXT; /* Prepare for next loop pass */
for (i=0; i<retp; i++) {
gid=PyString_FromStringAndSize((char *)(preplist[i].gid),
DB_XIDDATASIZE);
if (!gid) {
Py_DECREF(list);
return NULL;
}
txn=newDBTxnObject(self, NULL, preplist[i].txn, flags);
if (!txn) {
Py_DECREF(list);
Py_DECREF(gid);
return NULL;
}
txn->flag_prepare=1; /* Recover state */
tuple=PyTuple_New(2);
if (!tuple) {
Py_DECREF(list);
Py_DECREF(gid);
Py_DECREF(txn);
return NULL;
}
if (PyTuple_SetItem(tuple, 0, gid)) {
Py_DECREF(list);
Py_DECREF(gid);
Py_DECREF(txn);
Py_DECREF(tuple);
return NULL;
}
if (PyTuple_SetItem(tuple, 1, (PyObject *)txn)) {
Py_DECREF(list);
Py_DECREF(txn);
Py_DECREF(tuple); /* This delete the "gid" also */
return NULL;
}
if (PyList_Append(list, tuple)) {
Py_DECREF(list);
Py_DECREF(tuple);/* This delete the "gid" and the "txn" also */
return NULL;
}
Py_DECREF(tuple);
}
}
return list;
}
#endif
static PyObject*
DBEnv_txn_begin(DBEnvObject* self, PyObject* args, PyObject* kwargs)
{
......@@ -4141,7 +4452,7 @@ DBEnv_txn_begin(DBEnvObject* self, PyObject* args, PyObject* kwargs)
return NULL;
CHECK_ENV_NOT_CLOSED(self);
return (PyObject*)newDBTxnObject(self, txn, flags);
return (PyObject*)newDBTxnObject(self, (DBTxnObject *)txnobj, NULL, flags);
}
......@@ -4425,6 +4736,10 @@ DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
#if (DBVER < 41)
MAKE_ENTRY(lastid);
#endif
#if (DBVER >=41)
MAKE_ENTRY(id);
MAKE_ENTRY(cur_maxid);
#endif
MAKE_ENTRY(nmodes);
MAKE_ENTRY(maxlocks);
......@@ -4438,6 +4753,10 @@ DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
MAKE_ENTRY(maxnobjects);
MAKE_ENTRY(nrequests);
MAKE_ENTRY(nreleases);
#if (DBVER >= 44)
MAKE_ENTRY(nupgrade);
MAKE_ENTRY(ndowngrade);
#endif
#if (DBVER < 44)
MAKE_ENTRY(nnowaits); /* these were renamed in 4.4 */
MAKE_ENTRY(nconflicts);
......@@ -4446,6 +4765,23 @@ DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
MAKE_ENTRY(lock_wait);
#endif
MAKE_ENTRY(ndeadlocks);
#if (DBVER >= 41)
MAKE_ENTRY(locktimeout);
MAKE_ENTRY(txntimeout);
#endif
#if (DBVER >= 40)
MAKE_ENTRY(nlocktimeouts);
MAKE_ENTRY(ntxntimeouts);
#endif
#if (DBVER >= 46)
MAKE_ENTRY(objs_wait);
MAKE_ENTRY(objs_nowait);
MAKE_ENTRY(lockers_wait);
MAKE_ENTRY(lockers_nowait);
MAKE_ENTRY(locks_wait);
MAKE_ENTRY(locks_nowait);
MAKE_ENTRY(hash_len);
#endif
MAKE_ENTRY(regsize);
MAKE_ENTRY(region_wait);
MAKE_ENTRY(region_nowait);
......@@ -4455,6 +4791,24 @@ DBEnv_lock_stat(DBEnvObject* self, PyObject* args)
return d;
}
#if (DBVER >= 40)
static PyObject*
DBEnv_log_flush(DBEnvObject* self, PyObject* args)
{
int err;
if (!PyArg_ParseTuple(args, ":log_flush"))
return NULL;
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS
err = self->db_env->log_flush(self->db_env, NULL);
MYDB_END_ALLOW_THREADS
RETURN_IF_ERR();
RETURN_NONE();
}
#endif
static PyObject*
DBEnv_log_archive(DBEnvObject* self, PyObject* args)
......@@ -4465,120 +4819,625 @@ DBEnv_log_archive(DBEnvObject* self, PyObject* args)
PyObject* list;
PyObject* item = NULL;
if (!PyArg_ParseTuple(args, "|i:log_archive", &flags))
if (!PyArg_ParseTuple(args, "|i:log_archive", &flags))
return NULL;
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 40)
err = self->db_env->log_archive(self->db_env, &log_list, flags);
#elif (DBVER == 33)
err = log_archive(self->db_env, &log_list, flags);
#else
err = log_archive(self->db_env, &log_list, flags, NULL);
#endif
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
list = PyList_New(0);
if (list == NULL) {
if (log_list)
free(log_list);
return NULL;
}
if (log_list) {
char **log_list_start;
for (log_list_start = log_list; *log_list != NULL; ++log_list) {
item = PyString_FromString (*log_list);
if (item == NULL) {
Py_DECREF(list);
list = NULL;
break;
}
PyList_Append(list, item);
Py_DECREF(item);
}
free(log_list_start);
}
return list;
}
static PyObject*
DBEnv_txn_stat(DBEnvObject* self, PyObject* args)
{
int err;
DB_TXN_STAT* sp;
PyObject* d = NULL;
u_int32_t flags=0;
if (!PyArg_ParseTuple(args, "|i:txn_stat", &flags))
return NULL;
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 40)
err = self->db_env->txn_stat(self->db_env, &sp, flags);
#elif (DBVER == 33)
err = txn_stat(self->db_env, &sp);
#else
err = txn_stat(self->db_env, &sp, NULL);
#endif
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
/* Turn the stat structure into a dictionary */
d = PyDict_New();
if (d == NULL) {
free(sp);
return NULL;
}
#define MAKE_ENTRY(name) _addIntToDict(d, #name, sp->st_##name)
#define MAKE_TIME_T_ENTRY(name) _addTimeTToDict(d, #name, sp->st_##name)
#define MAKE_DB_LSN_ENTRY(name) _addDB_lsnToDict(d, #name, sp->st_##name)
#if (DBVER >= 40)
MAKE_DB_LSN_ENTRY(last_ckp);
#endif
MAKE_TIME_T_ENTRY(time_ckp);
MAKE_ENTRY(last_txnid);
MAKE_ENTRY(maxtxns);
MAKE_ENTRY(nactive);
MAKE_ENTRY(maxnactive);
#if (DBVER >= 45)
MAKE_ENTRY(nsnapshot);
MAKE_ENTRY(maxnsnapshot);
#endif
MAKE_ENTRY(nbegins);
MAKE_ENTRY(naborts);
MAKE_ENTRY(ncommits);
#if (DBVER >= 40)
MAKE_ENTRY(nrestores);
#endif
MAKE_ENTRY(regsize);
MAKE_ENTRY(region_wait);
MAKE_ENTRY(region_nowait);
#undef MAKE_DB_LSN_ENTRY
#undef MAKE_ENTRY
#undef MAKE_TIME_T_ENTRY
free(sp);
return d;
}
static PyObject*
DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args)
{
int flags=0;
int oldValue=0;
if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
return NULL;
CHECK_ENV_NOT_CLOSED(self);
if (self->moduleFlags.getReturnsNone)
++oldValue;
if (self->moduleFlags.cursorSetReturnsNone)
++oldValue;
self->moduleFlags.getReturnsNone = (flags >= 1);
self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
return PyInt_FromLong(oldValue);
}
#if (DBVER >= 40)
static PyObject*
DBEnv_set_verbose(DBEnvObject* self, PyObject* args)
{
int err;
int which, onoff;
if (!PyArg_ParseTuple(args, "ii:set_verbose", &which, &onoff)) {
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->set_verbose(self->db_env, which, onoff);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
RETURN_NONE();
}
#if (DBVER >= 42)
static PyObject*
DBEnv_get_verbose(DBEnvObject* self, PyObject* args)
{
int err;
int which;
int verbose;
if (!PyArg_ParseTuple(args, "i:get_verbose", &which)) {
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->get_verbose(self->db_env, which, &verbose);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
return PyBool_FromLong(verbose);
}
#endif
#endif
#if (DBVER >= 45)
static void
_dbenv_event_notifyCallback(DB_ENV* db_env, u_int32_t event, void *event_info)
{
DBEnvObject *dbenv;
PyObject* callback;
PyObject* args;
PyObject* result = NULL;
MYDB_BEGIN_BLOCK_THREADS;
dbenv = (DBEnvObject *)db_env->app_private;
callback = dbenv->event_notifyCallback;
if (callback) {
if (event == DB_EVENT_REP_NEWMASTER) {
args = Py_BuildValue("(Oii)", dbenv, event, *((int *)event_info));
} else {
args = Py_BuildValue("(OiO)", dbenv, event, Py_None);
}
if (args) {
result = PyEval_CallObject(callback, args);
}
if ((!args) || (!result)) {
PyErr_Print();
}
Py_XDECREF(args);
Py_XDECREF(result);
}
MYDB_END_BLOCK_THREADS;
}
#endif
#if (DBVER >= 45)
static PyObject*
DBEnv_set_event_notify(DBEnvObject* self, PyObject* args)
{
int err;
PyObject *notifyFunc;
if (!PyArg_ParseTuple(args, "O:set_event_notify", &notifyFunc)) {
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
if (!PyCallable_Check(notifyFunc)) {
makeTypeError("Callable", notifyFunc);
return NULL;
}
Py_XDECREF(self->event_notifyCallback);
Py_INCREF(notifyFunc);
self->event_notifyCallback = notifyFunc;
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->set_event_notify(self->db_env, _dbenv_event_notifyCallback);
MYDB_END_ALLOW_THREADS;
if (err) {
Py_DECREF(notifyFunc);
self->event_notifyCallback = NULL;
}
RETURN_IF_ERR();
RETURN_NONE();
}
#endif
/* --------------------------------------------------------------------- */
/* REPLICATION METHODS: Base Replication */
#if (DBVER >= 45)
static PyObject*
DBEnv_rep_set_nsites(DBEnvObject* self, PyObject* args)
{
int err;
int nsites;
if (!PyArg_ParseTuple(args, "i:rep_set_nsites", &nsites)) {
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->rep_set_nsites(self->db_env, nsites);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
RETURN_NONE();
}
static PyObject*
DBEnv_rep_get_nsites(DBEnvObject* self, PyObject* args)
{
int err;
int nsites;
if (!PyArg_ParseTuple(args, ":rep_get_nsites")) {
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->rep_get_nsites(self->db_env, &nsites);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
return PyInt_FromLong(nsites);
}
static PyObject*
DBEnv_rep_set_priority(DBEnvObject* self, PyObject* args)
{
int err;
int priority;
if (!PyArg_ParseTuple(args, "i:rep_set_priority", &priority)) {
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->rep_set_priority(self->db_env, priority);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
RETURN_NONE();
}
static PyObject*
DBEnv_rep_get_priority(DBEnvObject* self, PyObject* args)
{
int err;
int priority;
if (!PyArg_ParseTuple(args, ":rep_get_priority")) {
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->rep_get_priority(self->db_env, &priority);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
return PyInt_FromLong(priority);
}
static PyObject*
DBEnv_rep_set_timeout(DBEnvObject* self, PyObject* args)
{
int err;
int which, timeout;
if (!PyArg_ParseTuple(args, "ii:rep_set_timeout", &which, &timeout)) {
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->rep_set_timeout(self->db_env, which, timeout);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
RETURN_NONE();
}
static PyObject*
DBEnv_rep_get_timeout(DBEnvObject* self, PyObject* args)
{
int err;
int which;
u_int32_t timeout;
if (!PyArg_ParseTuple(args, "i:rep_get_timeout", &which)) {
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->rep_get_timeout(self->db_env, which, &timeout);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
return PyInt_FromLong(timeout);
}
#endif
/* --------------------------------------------------------------------- */
/* REPLICATION METHODS: Replication Manager */
#if (DBVER >= 45)
static PyObject*
DBEnv_repmgr_start(DBEnvObject* self, PyObject* args, PyObject*
kwargs)
{
int err;
int nthreads, flags;
static char* kwnames[] = {"nthreads","flags", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"ii:repmgr_start", kwnames, &nthreads, &flags))
{
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->repmgr_start(self->db_env, nthreads, flags);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
RETURN_NONE();
}
static PyObject*
DBEnv_repmgr_set_local_site(DBEnvObject* self, PyObject* args, PyObject*
kwargs)
{
int err;
char *host;
int port;
int flags = 0;
static char* kwnames[] = {"host", "port", "flags", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"si|i:repmgr_set_local_site", kwnames, &host, &port, &flags))
{
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->repmgr_set_local_site(self->db_env, host, port, flags);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
RETURN_NONE();
}
static PyObject*
DBEnv_repmgr_add_remote_site(DBEnvObject* self, PyObject* args, PyObject*
kwargs)
{
int err;
char *host;
int port;
int flags = 0;
int eidp;
static char* kwnames[] = {"host", "port", "flags", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"si|i:repmgr_add_remote_site", kwnames, &host, &port, &flags))
{
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->repmgr_add_remote_site(self->db_env, host, port, &eidp, flags);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
return PyInt_FromLong(eidp);
}
static PyObject*
DBEnv_repmgr_set_ack_policy(DBEnvObject* self, PyObject* args)
{
int err;
int ack_policy;
if (!PyArg_ParseTuple(args, "i:repmgr_set_ack_policy", &ack_policy))
{
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->repmgr_set_ack_policy(self->db_env, ack_policy);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
RETURN_NONE();
}
static PyObject*
DBEnv_repmgr_get_ack_policy(DBEnvObject* self, PyObject* args)
{
int err;
int ack_policy;
if (!PyArg_ParseTuple(args, ":repmgr_get_ack_policy"))
{
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->repmgr_get_ack_policy(self->db_env, &ack_policy);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
return PyInt_FromLong(ack_policy);
}
static PyObject*
DBEnv_repmgr_site_list(DBEnvObject* self, PyObject* args)
{
int err;
unsigned int countp;
DB_REPMGR_SITE *listp;
PyObject *stats, *key, *tuple;
if (!PyArg_ParseTuple(args, ":repmgr_site_list"))
{
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 40)
err = self->db_env->log_archive(self->db_env, &log_list, flags);
#elif (DBVER == 33)
err = log_archive(self->db_env, &log_list, flags);
#else
err = log_archive(self->db_env, &log_list, flags, NULL);
#endif
err = self->db_env->repmgr_site_list(self->db_env, &countp, &listp);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
list = PyList_New(0);
if (list == NULL) {
if (log_list)
free(log_list);
stats=PyDict_New();
if (stats == NULL) {
free(listp);
return NULL;
}
if (log_list) {
char **log_list_start;
for (log_list_start = log_list; *log_list != NULL; ++log_list) {
item = PyString_FromString (*log_list);
if (item == NULL) {
Py_DECREF(list);
list = NULL;
break;
}
PyList_Append(list, item);
Py_DECREF(item);
for(;countp--;) {
key=PyInt_FromLong(listp[countp].eid);
if(!key) {
Py_DECREF(stats);
free(listp);
return NULL;
}
#if (PY_VERSION_HEX >= 0x02040000)
tuple=Py_BuildValue("(sII)", listp[countp].host,
listp[countp].port, listp[countp].status);
#else
tuple=Py_BuildValue("(sii)", listp[countp].host,
listp[countp].port, listp[countp].status);
#endif
if(!tuple) {
Py_DECREF(key);
Py_DECREF(stats);
free(listp);
return NULL;
}
if(PyDict_SetItem(stats, key, tuple)) {
Py_DECREF(key);
Py_DECREF(tuple);
Py_DECREF(stats);
free(listp);
return NULL;
}
free(log_list_start);
}
return list;
free(listp);
return stats;
}
#endif
#if (DBVER >= 46)
static PyObject*
DBEnv_txn_stat(DBEnvObject* self, PyObject* args)
DBEnv_repmgr_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs)
{
int err;
DB_TXN_STAT* sp;
PyObject* d = NULL;
u_int32_t flags=0;
int flags=0;
static char* kwnames[] = { "flags", NULL };
if (!PyArg_ParseTuple(args, "|i:txn_stat", &flags))
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:repmgr_stat_print",
kwnames, &flags))
{
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
err = self->db_env->repmgr_stat_print(self->db_env, flags);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
RETURN_NONE();
}
static PyObject*
DBEnv_repmgr_stat(DBEnvObject* self, PyObject* args, PyObject *kwargs)
{
int err;
int flags=0;
DB_REPMGR_STAT *statp;
PyObject *stats;
static char* kwnames[] = { "flags", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:repmgr_stat",
kwnames, &flags))
{
return NULL;
}
CHECK_ENV_NOT_CLOSED(self);
MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 40)
err = self->db_env->txn_stat(self->db_env, &sp, flags);
#elif (DBVER == 33)
err = txn_stat(self->db_env, &sp);
#else
err = txn_stat(self->db_env, &sp, NULL);
#endif
err = self->db_env->repmgr_stat(self->db_env, &statp, flags);
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
/* Turn the stat structure into a dictionary */
d = PyDict_New();
if (d == NULL) {
free(sp);
stats=PyDict_New();
if (stats == NULL) {
free(statp);
return NULL;
}
#define MAKE_ENTRY(name) _addIntToDict(d, #name, sp->st_##name)
#define MAKE_TIME_T_ENTRY(name)_addTimeTToDict(d, #name, sp->st_##name)
#define MAKE_ENTRY(name) _addIntToDict(stats, #name, statp->st_##name)
MAKE_TIME_T_ENTRY(time_ckp);
MAKE_ENTRY(last_txnid);
MAKE_ENTRY(maxtxns);
MAKE_ENTRY(nactive);
MAKE_ENTRY(maxnactive);
MAKE_ENTRY(nbegins);
MAKE_ENTRY(naborts);
MAKE_ENTRY(ncommits);
MAKE_ENTRY(regsize);
MAKE_ENTRY(region_wait);
MAKE_ENTRY(region_nowait);
MAKE_ENTRY(perm_failed);
MAKE_ENTRY(msgs_queued);
MAKE_ENTRY(msgs_dropped);
MAKE_ENTRY(connection_drop);
MAKE_ENTRY(connect_fail);
#undef MAKE_ENTRY
#undef MAKE_TIME_T_ENTRY
free(sp);
return d;
free(statp);
return stats;
}
#endif
static PyObject*
DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args)
{
int flags=0;
int oldValue=0;
/* --------------------------------------------------------------------- */
/* DBTxn methods */
if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags))
return NULL;
CHECK_ENV_NOT_CLOSED(self);
if (self->moduleFlags.getReturnsNone)
++oldValue;
if (self->moduleFlags.cursorSetReturnsNone)
++oldValue;
self->moduleFlags.getReturnsNone = (flags >= 1);
self->moduleFlags.cursorSetReturnsNone = (flags >= 2);
return PyInt_FromLong(oldValue);
static void _close_transaction_cursors(DBTxnObject* txn)
{
PyObject *dummy;
while(txn->children_cursors) {
PyErr_Warn(PyExc_RuntimeWarning,
"Must close cursors before resolving a transaction.");
dummy=DBC_close_internal(txn->children_cursors);
Py_XDECREF(dummy);
}
}
static void _promote_transaction_dbs_and_sequences(DBTxnObject *txn)
{
DBObject *db;
#if (DBVER >= 43)
DBSequenceObject *dbs;
#endif
/* --------------------------------------------------------------------- */
/* DBTxn methods */
while (txn->children_dbs) {
db=txn->children_dbs;
EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(db);
if (txn->parent_txn) {
INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->parent_txn->children_dbs,db);
db->txn=txn->parent_txn;
} else {
/* The db is already linked to its environment,
** so nothing to do.
*/
db->txn=NULL;
}
}
#if (DBVER >= 43)
while (txn->children_sequences) {
dbs=txn->children_sequences;
EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(dbs);
if (txn->parent_txn) {
INSERT_IN_DOUBLE_LINKED_LIST_TXN(txn->parent_txn->children_sequences,dbs);
dbs->txn=txn->parent_txn;
} else {
/* The sequence is already linked to its
** parent db. Nothing to do.
*/
dbs->txn=NULL;
}
}
#endif
}
static PyObject*
......@@ -4590,15 +5449,22 @@ DBTxn_commit(DBTxnObject* self, PyObject* args)
if (!PyArg_ParseTuple(args, "|i:commit", &flags))
return NULL;
_close_transaction_cursors(self);
if (!self->txn) {
PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
"after txn_commit or txn_abort");
"after txn_commit, txn_abort "
"or txn_discard");
PyErr_SetObject(DBError, t);
Py_DECREF(t);
return NULL;
}
self->flag_prepare=0;
txn = self->txn;
self->txn = NULL; /* this DB_TXN is no longer valid after this call */
EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 40)
err = txn->commit(txn, flags);
......@@ -4606,6 +5472,9 @@ DBTxn_commit(DBTxnObject* self, PyObject* args)
err = txn_commit(txn, flags);
#endif
MYDB_END_ALLOW_THREADS;
_promote_transaction_dbs_and_sequences(self);
RETURN_IF_ERR();
RETURN_NONE();
}
......@@ -4629,11 +5498,13 @@ DBTxn_prepare(DBTxnObject* self, PyObject* args)
if (!self->txn) {
PyObject *t = Py_BuildValue("(is)", 0,"DBTxn must not be used "
"after txn_commit or txn_abort");
"after txn_commit, txn_abort "
"or txn_discard");
PyErr_SetObject(DBError, t);
Py_DECREF(t);
return NULL;
}
self->flag_prepare=1; /* Prepare state */
MYDB_BEGIN_ALLOW_THREADS;
#if (DBVER >= 40)
err = self->txn->prepare(self->txn, (u_int8_t*)gid);
......@@ -4651,7 +5522,8 @@ DBTxn_prepare(DBTxnObject* self, PyObject* args)
if (!self->txn) {
PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
"after txn_commit or txn_abort");
"after txn_commit, txn_abort "
"or txn_discard");
PyErr_SetObject(DBError, t);
Py_DECREF(t);
return NULL;
......@@ -4666,34 +5538,87 @@ DBTxn_prepare(DBTxnObject* self, PyObject* args)
static PyObject*
DBTxn_abort(DBTxnObject* self, PyObject* args)
DBTxn_abort_discard_internal(DBTxnObject* self, int discard)
{
int err;
PyObject *dummy;
int err=0;
DB_TXN *txn;
if (!PyArg_ParseTuple(args, ":abort"))
return NULL;
if (!self->txn) {
PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
"after txn_commit or txn_abort");
"after txn_commit, txn_abort "
"or txn_discard");
PyErr_SetObject(DBError, t);
Py_DECREF(t);
return NULL;
}
txn = self->txn;
self->txn = NULL; /* this DB_TXN is no longer valid after this call */
_close_transaction_cursors(self);
#if (DBVER >= 43)
while (self->children_sequences) {
dummy=DBSequence_close_internal(self->children_sequences,0,0);
Py_XDECREF(dummy);
}
#endif
while (self->children_dbs) {
dummy=DB_close_internal(self->children_dbs,0);
Py_XDECREF(dummy);
}
EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
MYDB_BEGIN_ALLOW_THREADS;
if (discard) {
assert(!self->flag_prepare);
#if (DBVER >= 40)
err = txn->discard(txn,0);
#else
err = txn_discard(txn);
#endif
} else {
/*
** If the transaction is in the "prepare" or "recover" state,
** we better do not implicitly abort it.
*/
if (!self->flag_prepare) {
#if (DBVER >= 40)
err = txn->abort(txn);
err = txn->abort(txn);
#else
err = txn_abort(txn);
err = txn_abort(txn);
#endif
}
}
MYDB_END_ALLOW_THREADS;
RETURN_IF_ERR();
RETURN_NONE();
}
static PyObject*
DBTxn_abort(DBTxnObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ":abort"))
return NULL;
self->flag_prepare=0;
_close_transaction_cursors(self);
return DBTxn_abort_discard_internal(self,0);
}
static PyObject*
DBTxn_discard(DBTxnObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ":discard"))
return NULL;
self->flag_prepare=0;
_close_transaction_cursors(self);
return DBTxn_abort_discard_internal(self,1);
}
static PyObject*
DBTxn_id(DBTxnObject* self, PyObject* args)
......@@ -4705,7 +5630,8 @@ DBTxn_id(DBTxnObject* self, PyObject* args)
if (!self->txn) {
PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used "
"after txn_commit or txn_abort");
"after txn_commit, txn_abort "
"or txn_discard");
PyErr_SetObject(DBError, t);
Py_DECREF(t);
return NULL;
......@@ -4726,23 +5652,40 @@ DBTxn_id(DBTxnObject* self, PyObject* args)
static PyObject*
DBSequence_close(DBSequenceObject* self, PyObject* args)
DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close)
{
int err, flags=0;
if (!PyArg_ParseTuple(args,"|i:close", &flags))
return NULL;
CHECK_SEQUENCE_NOT_CLOSED(self)
int err=0;
MYDB_BEGIN_ALLOW_THREADS
err = self->sequence->close(self->sequence, flags);
self->sequence = NULL;
MYDB_END_ALLOW_THREADS
if (self->sequence!=NULL) {
EXTRACT_FROM_DOUBLE_LINKED_LIST(self);
if (self->txn) {
EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self);
self->txn=NULL;
}
RETURN_IF_ERR();
if (!do_not_close) {
MYDB_BEGIN_ALLOW_THREADS
err = self->sequence->close(self->sequence, flags);
MYDB_END_ALLOW_THREADS
}
self->sequence = NULL;
RETURN_IF_ERR();
}
RETURN_NONE();
}
static PyObject*
DBSequence_close(DBSequenceObject* self, PyObject* args)
{
int flags=0;
if (!PyArg_ParseTuple(args,"|i:close", &flags))
return NULL;
return DBSequence_close_internal(self,flags,0);
}
static PyObject*
DBSequence_get(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
{
......@@ -4765,7 +5708,6 @@ DBSequence_get(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
RETURN_IF_ERR();
return PyLong_FromLongLong(value);
}
static PyObject*
......@@ -4784,6 +5726,10 @@ DBSequence_get_key(DBSequenceObject* self, PyObject* args)
int err;
DBT key;
PyObject *retval = NULL;
if (!PyArg_ParseTuple(args,":get_key"))
return NULL;
key.flags = DB_DBT_MALLOC;
CHECK_SEQUENCE_NOT_CLOSED(self)
MYDB_BEGIN_ALLOW_THREADS
......@@ -4791,7 +5737,7 @@ DBSequence_get_key(DBSequenceObject* self, PyObject* args)
MYDB_END_ALLOW_THREADS
if (!err)
retval = PyString_FromStringAndSize(key.data, key.size);
retval = Build_PyString(key.data, key.size);
FREE_DBT(key);
RETURN_IF_ERR();
......@@ -4803,13 +5749,15 @@ static PyObject*
DBSequence_init_value(DBSequenceObject* self, PyObject* args)
{
int err;
db_seq_t value;
PY_LONG_LONG value;
db_seq_t value2;
if (!PyArg_ParseTuple(args,"L:init_value", &value))
return NULL;
CHECK_SEQUENCE_NOT_CLOSED(self)
value2=value; /* If truncation, compiler should show a warning */
MYDB_BEGIN_ALLOW_THREADS
err = self->sequence->initial_value(self->sequence, value);
err = self->sequence->initial_value(self->sequence, value2);
MYDB_END_ALLOW_THREADS
RETURN_IF_ERR();
......@@ -4843,12 +5791,18 @@ DBSequence_open(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
CLEAR_DBT(key);
RETURN_IF_ERR();
if (txn) {
INSERT_IN_DOUBLE_LINKED_LIST_TXN(((DBTxnObject *)txnobj)->children_sequences,self);
self->txn=(DBTxnObject *)txnobj;
}
RETURN_NONE();
}
static PyObject*
DBSequence_remove(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
{
PyObject *dummy;
int err, flags = 0;
PyObject *txnobj = NULL;
DB_TXN *txn = NULL;
......@@ -4866,6 +5820,9 @@ DBSequence_remove(DBSequenceObject* self, PyObject* args, PyObject* kwargs)
err = self->sequence->remove(self->sequence, txn, flags);
MYDB_END_ALLOW_THREADS
dummy=DBSequence_close_internal(self,flags,1);
Py_XDECREF(dummy);
RETURN_IF_ERR();
RETURN_NONE();
}
......@@ -4916,7 +5873,6 @@ DBSequence_set_flags(DBSequenceObject* self, PyObject* args)
RETURN_IF_ERR();
RETURN_NONE();
}
static PyObject*
......@@ -4940,13 +5896,16 @@ static PyObject*
DBSequence_set_range(DBSequenceObject* self, PyObject* args)
{
int err;
db_seq_t min, max;
PY_LONG_LONG min, max;
db_seq_t min2, max2;
if (!PyArg_ParseTuple(args,"(LL):set_range", &min, &max))
return NULL;
CHECK_SEQUENCE_NOT_CLOSED(self)
min2=min; /* If truncation, compiler should show a warning */
max2=max;
MYDB_BEGIN_ALLOW_THREADS
err = self->sequence->set_range(self->sequence, min, max);
err = self->sequence->set_range(self->sequence, min2, max2);
MYDB_END_ALLOW_THREADS
RETURN_IF_ERR();
......@@ -4957,16 +5916,19 @@ static PyObject*
DBSequence_get_range(DBSequenceObject* self, PyObject* args)
{
int err;
db_seq_t min, max;
PY_LONG_LONG min, max;
db_seq_t min2, max2;
if (!PyArg_ParseTuple(args,":get_range"))
return NULL;
CHECK_SEQUENCE_NOT_CLOSED(self)
MYDB_BEGIN_ALLOW_THREADS
err = self->sequence->get_range(self->sequence, &min, &max);
err = self->sequence->get_range(self->sequence, &min2, &max2);
MYDB_END_ALLOW_THREADS
RETURN_IF_ERR();
min=min2; /* If truncation, compiler should show a warning */
max=max2;
return Py_BuildValue("(LL)", min, max);
}
......@@ -5134,6 +6096,9 @@ static PyMethodDef DBEnv_methods[] = {
{"set_lg_bsize", (PyCFunction)DBEnv_set_lg_bsize, METH_VARARGS},
{"set_lg_dir", (PyCFunction)DBEnv_set_lg_dir, METH_VARARGS},
{"set_lg_max", (PyCFunction)DBEnv_set_lg_max, METH_VARARGS},
#if (DBVER >= 42)
{"get_lg_max", (PyCFunction)DBEnv_get_lg_max, METH_VARARGS},
#endif
#if (DBVER >= 33)
{"set_lg_regionmax",(PyCFunction)DBEnv_set_lg_regionmax, METH_VARARGS},
#endif
......@@ -5160,6 +6125,9 @@ static PyMethodDef DBEnv_methods[] = {
{"lock_put", (PyCFunction)DBEnv_lock_put, METH_VARARGS},
{"lock_stat", (PyCFunction)DBEnv_lock_stat, METH_VARARGS},
{"log_archive", (PyCFunction)DBEnv_log_archive, METH_VARARGS},
#if (DBVER >= 40)
{"log_flush", (PyCFunction)DBEnv_log_flush, METH_VARARGS},
#endif
#if (DBVER >= 40)
{"log_stat", (PyCFunction)DBEnv_log_stat, METH_VARARGS},
#endif
......@@ -5167,6 +6135,46 @@ static PyMethodDef DBEnv_methods[] = {
{"lsn_reset", (PyCFunction)DBEnv_lsn_reset, METH_VARARGS|METH_KEYWORDS},
#endif
{"set_get_returns_none",(PyCFunction)DBEnv_set_get_returns_none, METH_VARARGS},
#if (DBVER >= 40)
{"txn_recover", (PyCFunction)DBEnv_txn_recover, METH_VARARGS},
#endif
#if (DBVER >= 40)
{"set_verbose", (PyCFunction)DBEnv_set_verbose, METH_VARARGS},
#if (DBVER >= 42)
{"get_verbose", (PyCFunction)DBEnv_get_verbose, METH_VARARGS},
#endif
#endif
#if (DBVER >= 45)
{"set_event_notify", (PyCFunction)DBEnv_set_event_notify, METH_VARARGS},
#endif
#if (DBVER >= 45)
{"rep_set_nsites", (PyCFunction)DBEnv_rep_set_nsites, METH_VARARGS},
{"rep_get_nsites", (PyCFunction)DBEnv_rep_get_nsites, METH_VARARGS},
{"rep_set_priority", (PyCFunction)DBEnv_rep_set_priority, METH_VARARGS},
{"rep_get_priority", (PyCFunction)DBEnv_rep_get_priority, METH_VARARGS},
{"rep_set_timeout", (PyCFunction)DBEnv_rep_set_timeout, METH_VARARGS},
{"rep_get_timeout", (PyCFunction)DBEnv_rep_get_timeout, METH_VARARGS},
#endif
#if (DBVER >= 45)
{"repmgr_start", (PyCFunction)DBEnv_repmgr_start,
METH_VARARGS|METH_KEYWORDS},
{"repmgr_set_local_site", (PyCFunction)DBEnv_repmgr_set_local_site,
METH_VARARGS|METH_KEYWORDS},
{"repmgr_add_remote_site", (PyCFunction)DBEnv_repmgr_add_remote_site,
METH_VARARGS|METH_KEYWORDS},
{"repmgr_set_ack_policy", (PyCFunction)DBEnv_repmgr_set_ack_policy,
METH_VARARGS},
{"repmgr_get_ack_policy", (PyCFunction)DBEnv_repmgr_get_ack_policy,
METH_VARARGS},
{"repmgr_site_list", (PyCFunction)DBEnv_repmgr_site_list,
METH_VARARGS},
#endif
#if (DBVER >= 46)
{"repmgr_stat", (PyCFunction)DBEnv_repmgr_stat,
METH_VARARGS|METH_KEYWORDS},
{"repmgr_stat_print", (PyCFunction)DBEnv_repmgr_stat_print,
METH_VARARGS|METH_KEYWORDS},
#endif
{NULL, NULL} /* sentinel */
};
......@@ -5174,6 +6182,7 @@ static PyMethodDef DBEnv_methods[] = {
static PyMethodDef DBTxn_methods[] = {
{"commit", (PyCFunction)DBTxn_commit, METH_VARARGS},
{"prepare", (PyCFunction)DBTxn_prepare, METH_VARARGS},
{"discard", (PyCFunction)DBTxn_discard, METH_VARARGS},
{"abort", (PyCFunction)DBTxn_abort, METH_VARARGS},
{"id", (PyCFunction)DBTxn_id, METH_VARARGS},
{NULL, NULL} /* sentinel */
......@@ -5212,11 +6221,17 @@ static PyObject*
DBEnv_getattr(DBEnvObject* self, char *name)
{
if (!strcmp(name, "db_home")) {
CHECK_ENV_NOT_CLOSED(self);
if (self->db_env->db_home == NULL) {
RETURN_NONE();
}
return PyString_FromString(self->db_env->db_home);
const char *home = NULL;
CHECK_ENV_NOT_CLOSED(self);
#if (DBVER >= 42)
self->db_env->get_home(self->db_env, &home);
#else
home=self->db_env->db_home;
#endif
if (home == NULL) {
RETURN_NONE();
}
return PyString_FromString(home);
}
return Py_FindMethod(DBEnv_methods, (PyObject* )self, name);
......@@ -5582,7 +6597,7 @@ DL_EXPORT(void) init_bsddb(void)
ADD_INT(d, DB_RPCCLIENT);
#else
ADD_INT(d, DB_CLIENT);
/* allow apps to be written using DB_RPCCLIENT on older BerkeleyDB */
/* allow apps to be written using DB_RPCCLIENT on older Berkeley DB */
_addIntToDict(d, "DB_RPCCLIENT", DB_CLIENT);
#endif
ADD_INT(d, DB_XA_CREATE);
......@@ -5590,6 +6605,9 @@ DL_EXPORT(void) init_bsddb(void)
ADD_INT(d, DB_CREATE);
ADD_INT(d, DB_NOMMAP);
ADD_INT(d, DB_THREAD);
#if (DBVER >= 45)
ADD_INT(d, DB_MULTIVERSION);
#endif
ADD_INT(d, DB_FORCE);
ADD_INT(d, DB_INIT_CDB);
......@@ -5599,6 +6617,10 @@ DL_EXPORT(void) init_bsddb(void)
ADD_INT(d, DB_INIT_TXN);
ADD_INT(d, DB_JOINENV);
#if (DBVER >= 40)
ADD_INT(d, DB_XIDDATASIZE);
#endif
ADD_INT(d, DB_RECOVER);
ADD_INT(d, DB_RECOVER_FATAL);
ADD_INT(d, DB_TXN_NOSYNC);
......@@ -5645,6 +6667,13 @@ DL_EXPORT(void) init_bsddb(void)
ADD_INT(d, DB_LOCK_MINWRITE);
#endif
#if (DBVER >= 40)
ADD_INT(d, DB_LOCK_EXPIRE);
#endif
#if (DBVER >= 43)
ADD_INT(d, DB_LOCK_MAXWRITE);
#endif
#if (DBVER >= 33)
/* docs say to use zero instead */
......@@ -5816,6 +6845,10 @@ DL_EXPORT(void) init_bsddb(void)
ADD_INT(d, DB_NOPANIC);
#endif
#if (DBVER >= 41)
ADD_INT(d, DB_OVERWRITE);
#endif
#ifdef DB_REGISTER
ADD_INT(d, DB_REGISTER);
#endif
......@@ -5832,7 +6865,76 @@ DL_EXPORT(void) init_bsddb(void)
ADD_INT(d, DB_CHKSUM);
#endif
#if (DBVER >= 44)
ADD_INT(d, DB_DSYNC_DB);
#endif
#if (DBVER >= 45)
ADD_INT(d, DB_TXN_SNAPSHOT);
#endif
#if (DBVER >= 40)
ADD_INT(d, DB_VERB_DEADLOCK);
#if (DBVER >= 46)
ADD_INT(d, DB_VERB_FILEOPS);
ADD_INT(d, DB_VERB_FILEOPS_ALL);
#endif
ADD_INT(d, DB_VERB_RECOVERY);
#if (DBVER >= 44)
ADD_INT(d, DB_VERB_REGISTER);
#endif
ADD_INT(d, DB_VERB_REPLICATION);
ADD_INT(d, DB_VERB_WAITSFOR);
#endif
#if (DBVER >= 45)
ADD_INT(d, DB_EVENT_PANIC);
ADD_INT(d, DB_EVENT_REP_CLIENT);
#if (DBVER >= 46)
ADD_INT(d, DB_EVENT_REP_ELECTED);
#endif
ADD_INT(d, DB_EVENT_REP_MASTER);
ADD_INT(d, DB_EVENT_REP_NEWMASTER);
#if (DBVER >= 46)
ADD_INT(d, DB_EVENT_REP_PERM_FAILED);
#endif
ADD_INT(d, DB_EVENT_REP_STARTUPDONE);
ADD_INT(d, DB_EVENT_WRITE_FAILED);
#endif
#if (DBVER >= 40)
ADD_INT(d, DB_REP_MASTER);
ADD_INT(d, DB_REP_CLIENT);
#if (DBVER >= 45)
ADD_INT(d, DB_REP_ELECTION);
ADD_INT(d, DB_REP_ACK_TIMEOUT);
ADD_INT(d, DB_REP_CONNECTION_RETRY);
ADD_INT(d, DB_REP_ELECTION_TIMEOUT);
ADD_INT(d, DB_REP_ELECTION_RETRY);
#endif
#if (DBVER >= 46)
ADD_INT(d, DB_REP_CHECKPOINT_DELAY);
ADD_INT(d, DB_REP_FULL_ELECTION_TIMEOUT);
#endif
#endif
#if (DBVER >= 45)
ADD_INT(d, DB_REPMGR_PEER);
ADD_INT(d, DB_REPMGR_ACKS_ALL);
ADD_INT(d, DB_REPMGR_ACKS_ALL_PEERS);
ADD_INT(d, DB_REPMGR_ACKS_NONE);
ADD_INT(d, DB_REPMGR_ACKS_ONE);
ADD_INT(d, DB_REPMGR_ACKS_ONE_PEER);
ADD_INT(d, DB_REPMGR_ACKS_QUORUM);
ADD_INT(d, DB_REPMGR_CONNECTED);
ADD_INT(d, DB_REPMGR_DISCONNECTED);
ADD_INT(d, DB_STAT_CLEAR);
ADD_INT(d, DB_STAT_ALL);
#endif
#if (DBVER >= 43)
ADD_INT(d, DB_DSYNC_LOG);
ADD_INT(d, DB_LOG_INMEMORY);
ADD_INT(d, DB_BUFFER_SMALL);
ADD_INT(d, DB_SEQ_DEC);
......@@ -5844,7 +6946,7 @@ DL_EXPORT(void) init_bsddb(void)
ADD_INT(d, DB_ENCRYPT_AES);
ADD_INT(d, DB_AUTO_COMMIT);
#else
/* allow berkeleydb 4.1 aware apps to run on older versions */
/* allow Berkeley DB 4.1 aware apps to run on older versions */
_addIntToDict(d, "DB_AUTO_COMMIT", 0);
#endif
......@@ -5920,6 +7022,10 @@ DL_EXPORT(void) init_bsddb(void)
MAKE_EX(DBNoSuchFileError);
MAKE_EX(DBPermissionsError);
#if (DBVER >= 42)
MAKE_EX(DBRepHandleDeadError);
#endif
#undef MAKE_EX
/* Initiliase the C API structure and add it to the module */
......
......@@ -36,7 +36,7 @@
/*
* Handwritten code to wrap version 3.x of the Berkeley DB library,
* written to replace a SWIG-generated file. It has since been updated
* to compile with BerkeleyDB versions 3.2 through 4.2.
* to compile with Berkeley DB versions 3.2 through 4.2.
*
* This module was started by Andrew Kuchling to remove the dependency
* on SWIG in a package by Gregory P. Smith who based his work on a
......@@ -105,7 +105,7 @@
#error "eek! DBVER can't handle minor versions > 9"
#endif
#define PY_BSDDB_VERSION "4.6.0"
#define PY_BSDDB_VERSION "4.6.5devel2"
/* Python object definitions */
......@@ -119,17 +119,27 @@ struct behaviourFlags {
};
struct DBObject; /* Forward declaration */
struct DBCursorObject; /* Forward declaration */
struct DBTxnObject; /* Forward declaration */
struct DBSequenceObject; /* Forward declaration */
typedef struct {
PyObject_HEAD
DB_ENV* db_env;
u_int32_t flags; /* saved flags from open() */
int closed;
struct behaviourFlags moduleFlags;
#if (DBVER >= 40)
PyObject* event_notifyCallback;
#endif
struct DBObject *children_dbs;
struct DBTxnObject *children_txns;
PyObject *in_weakreflist; /* List of weak references */
} DBEnvObject;
typedef struct {
typedef struct DBObject {
PyObject_HEAD
DB* db;
DBEnvObject* myenvobj; /* PyObject containing the DB_ENV */
......@@ -137,6 +147,15 @@ typedef struct {
u_int32_t setflags; /* saved flags from set_flags() */
int haveStat;
struct behaviourFlags moduleFlags;
struct DBTxnObject *txn;
struct DBCursorObject *children_cursors;
#if (DBVER >=43)
struct DBSequenceObject *children_sequences;
#endif
struct DBObject **sibling_prev_p;
struct DBObject *sibling_next;
struct DBObject **sibling_prev_p_txn;
struct DBObject *sibling_next_txn;
#if (DBVER >= 33)
PyObject* associateCallback;
PyObject* btCompareCallback;
......@@ -146,18 +165,31 @@ typedef struct {
} DBObject;
typedef struct {
typedef struct DBCursorObject {
PyObject_HEAD
DBC* dbc;
struct DBCursorObject **sibling_prev_p;
struct DBCursorObject *sibling_next;
struct DBCursorObject **sibling_prev_p_txn;
struct DBCursorObject *sibling_next_txn;
DBObject* mydb;
struct DBTxnObject *txn;
PyObject *in_weakreflist; /* List of weak references */
} DBCursorObject;
typedef struct {
typedef struct DBTxnObject {
PyObject_HEAD
DB_TXN* txn;
PyObject *env;
DBEnvObject* env;
int flag_prepare;
struct DBTxnObject *parent_txn;
struct DBTxnObject **sibling_prev_p;
struct DBTxnObject *sibling_next;
struct DBTxnObject *children_txns;
struct DBObject *children_dbs;
struct DBSequenceObject *children_sequences;
struct DBCursorObject *children_cursors;
PyObject *in_weakreflist; /* List of weak references */
} DBTxnObject;
......@@ -170,13 +202,17 @@ typedef struct {
#if (DBVER >= 43)
typedef struct {
typedef struct DBSequenceObject {
PyObject_HEAD
DB_SEQUENCE* sequence;
DBObject* mydb;
struct DBTxnObject *txn;
struct DBSequenceObject **sibling_prev_p;
struct DBSequenceObject *sibling_next;
struct DBSequenceObject **sibling_prev_p_txn;
struct DBSequenceObject *sibling_next_txn;
PyObject *in_weakreflist; /* List of weak references */
} DBSequenceObject;
staticforward PyTypeObject DBSequence_Type;
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment