| /*---------------------------------------------------------------------- |
| Copyright (c) 1999-2001, Digital Creations, Fredericksburg, VA, USA |
| and Andrew Kuchling. All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are |
| met: |
| |
| o Redistributions of source code must retain the above copyright |
| notice, this list of conditions, and the disclaimer that follows. |
| |
| o Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions, and the following disclaimer in |
| the documentation and/or other materials provided with the |
| distribution. |
| |
| o Neither the name of Digital Creations nor the names of its |
| contributors may be used to endorse or promote products derived |
| from this software without specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS |
| IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
| PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL |
| CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR |
| TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| DAMAGE. |
| ------------------------------------------------------------------------*/ |
| |
| |
| /* |
| * 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 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 |
| * similar package by Robin Dunn <robin@alldunn.com> which wrapped |
| * Berkeley DB 2.7.x. |
| * |
| * Development of this module then returned full circle back to Robin Dunn |
| * who worked on behalf of Digital Creations to complete the wrapping of |
| * 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> was once again the maintainer. |
| * |
| * Since January 2008, new maintainer is Jesus Cea <jcea@jcea.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 |
| * file is shared with the PyBSDDB project at SourceForge: |
| * |
| * http://pybsddb.sf.net |
| * |
| * This file should remain backward compatible with Python 2.1, but see PEP |
| * 291 for the most current backward compatibility requirements: |
| * |
| * http://www.python.org/peps/pep-0291.html |
| * |
| * This module contains 6 types: |
| * |
| * DB (Database) |
| * DBCursor (Database Cursor) |
| * DBEnv (database environment) |
| * DBTxn (An explicit database transaction) |
| * DBLock (A lock handle) |
| * DBSequence (Sequence) |
| * |
| */ |
| |
| /* --------------------------------------------------------------------- */ |
| |
| /* |
| * Portions of this module, associated unit tests and build scripts are the |
| * result of a contract with The Written Word (http://thewrittenword.com/) |
| * Many thanks go out to them for causing me to raise the bar on quality and |
| * functionality, resulting in a better bsddb3 package for all of us to use. |
| * |
| * --Robin |
| */ |
| |
| /* --------------------------------------------------------------------- */ |
| |
| #include <stddef.h> /* for offsetof() */ |
| #include <Python.h> |
| |
| #define COMPILING_BSDDB_C |
| #include "bsddb.h" |
| #undef COMPILING_BSDDB_C |
| |
| static char *rcs_id = "$Id$"; |
| |
| /* --------------------------------------------------------------------- */ |
| /* Various macro definitions */ |
| |
| #if (PY_VERSION_HEX < 0x02050000) |
| typedef int Py_ssize_t; |
| #endif |
| |
| #if (PY_VERSION_HEX < 0x02060000) /* really: before python trunk r63675 */ |
| /* This code now uses PyBytes* API function names instead of PyString*. |
| * These #defines map to their equivalent on earlier python versions. */ |
| #define PyBytes_FromStringAndSize PyString_FromStringAndSize |
| #define PyBytes_FromString PyString_FromString |
| #define PyBytes_AsStringAndSize PyString_AsStringAndSize |
| #define PyBytes_Check PyString_Check |
| #define PyBytes_GET_SIZE PyString_GET_SIZE |
| #define PyBytes_AS_STRING PyString_AS_STRING |
| #endif |
| |
| #if (PY_VERSION_HEX >= 0x03000000) |
| #define NUMBER_Check PyLong_Check |
| #define NUMBER_AsLong PyLong_AsLong |
| #define NUMBER_FromLong PyLong_FromLong |
| #else |
| #define NUMBER_Check PyInt_Check |
| #define NUMBER_AsLong PyInt_AsLong |
| #define NUMBER_FromLong PyInt_FromLong |
| #endif |
| |
| #ifdef WITH_THREAD |
| |
| /* These are for when calling Python --> C */ |
| #define MYDB_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS; |
| #define MYDB_END_ALLOW_THREADS Py_END_ALLOW_THREADS; |
| |
| /* For 2.3, use the PyGILState_ calls */ |
| #if (PY_VERSION_HEX >= 0x02030000) |
| #define MYDB_USE_GILSTATE |
| #endif |
| |
| /* and these are for calling C --> Python */ |
| #if defined(MYDB_USE_GILSTATE) |
| #define MYDB_BEGIN_BLOCK_THREADS \ |
| PyGILState_STATE __savestate = PyGILState_Ensure(); |
| #define MYDB_END_BLOCK_THREADS \ |
| PyGILState_Release(__savestate); |
| #else /* MYDB_USE_GILSTATE */ |
| /* Pre GILState API - do it the long old way */ |
| static PyInterpreterState* _db_interpreterState = NULL; |
| #define MYDB_BEGIN_BLOCK_THREADS { \ |
| PyThreadState* prevState; \ |
| PyThreadState* newState; \ |
| PyEval_AcquireLock(); \ |
| newState = PyThreadState_New(_db_interpreterState); \ |
| prevState = PyThreadState_Swap(newState); |
| |
| #define MYDB_END_BLOCK_THREADS \ |
| newState = PyThreadState_Swap(prevState); \ |
| PyThreadState_Clear(newState); \ |
| PyEval_ReleaseLock(); \ |
| PyThreadState_Delete(newState); \ |
| } |
| #endif /* MYDB_USE_GILSTATE */ |
| |
| #else |
| /* Compiled without threads - avoid all this cruft */ |
| #define MYDB_BEGIN_ALLOW_THREADS |
| #define MYDB_END_ALLOW_THREADS |
| #define MYDB_BEGIN_BLOCK_THREADS |
| #define MYDB_END_BLOCK_THREADS |
| |
| #endif |
| |
| /* Should DB_INCOMPLETE be turned into a warning or an exception? */ |
| #define INCOMPLETE_IS_WARNING 1 |
| |
| /* --------------------------------------------------------------------- */ |
| /* Exceptions */ |
| |
| static PyObject* DBError; /* Base class, all others derive from this */ |
| static PyObject* DBCursorClosedError; /* raised when trying to use a closed cursor object */ |
| static PyObject* DBKeyEmptyError; /* DB_KEYEMPTY: also derives from KeyError */ |
| static PyObject* DBKeyExistError; /* DB_KEYEXIST */ |
| static PyObject* DBLockDeadlockError; /* DB_LOCK_DEADLOCK */ |
| static PyObject* DBLockNotGrantedError; /* DB_LOCK_NOTGRANTED */ |
| static PyObject* DBNotFoundError; /* DB_NOTFOUND: also derives from KeyError */ |
| static PyObject* DBOldVersionError; /* DB_OLD_VERSION */ |
| static PyObject* DBRunRecoveryError; /* DB_RUNRECOVERY */ |
| static PyObject* DBVerifyBadError; /* DB_VERIFY_BAD */ |
| static PyObject* DBNoServerError; /* DB_NOSERVER */ |
| static PyObject* DBNoServerHomeError; /* DB_NOSERVER_HOME */ |
| static PyObject* DBNoServerIDError; /* DB_NOSERVER_ID */ |
| static PyObject* DBPageNotFoundError; /* DB_PAGE_NOTFOUND */ |
| static PyObject* DBSecondaryBadError; /* DB_SECONDARY_BAD */ |
| |
| #if !INCOMPLETE_IS_WARNING |
| static PyObject* DBIncompleteError; /* DB_INCOMPLETE */ |
| #endif |
| |
| static PyObject* DBInvalidArgError; /* EINVAL */ |
| static PyObject* DBAccessError; /* EACCES */ |
| static PyObject* DBNoSpaceError; /* ENOSPC */ |
| static PyObject* DBNoMemoryError; /* DB_BUFFER_SMALL (ENOMEM when < 4.3) */ |
| static PyObject* DBAgainError; /* EAGAIN */ |
| static PyObject* DBBusyError; /* EBUSY */ |
| static PyObject* DBFileExistsError; /* EEXIST */ |
| static PyObject* DBNoSuchFileError; /* ENOENT */ |
| static PyObject* DBPermissionsError; /* EPERM */ |
| |
| #if (DBVER >= 42) |
| static PyObject* DBRepHandleDeadError; /* DB_REP_HANDLE_DEAD */ |
| #endif |
| |
| static PyObject* DBRepUnavailError; /* DB_REP_UNAVAIL */ |
| |
| #if (DBVER < 43) |
| #define DB_BUFFER_SMALL ENOMEM |
| #endif |
| |
| |
| /* --------------------------------------------------------------------- */ |
| /* Structure definitions */ |
| |
| #if PYTHON_API_VERSION < 1010 |
| #error "Python 2.1 or later required" |
| #endif |
| |
| |
| /* Defaults for moduleFlags in DBEnvObject and DBObject. */ |
| #define DEFAULT_GET_RETURNS_NONE 1 |
| #define DEFAULT_CURSOR_SET_RETURNS_NONE 1 /* 0 in pybsddb < 4.2, python < 2.4 */ |
| |
| |
| /* See comment in Python 2.6 "object.h" */ |
| #ifndef staticforward |
| #define staticforward static |
| #endif |
| #ifndef statichere |
| #define statichere static |
| #endif |
| |
| 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 */ |
| #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) |
| #endif |
| |
| #define DBObject_Check(v) (Py_TYPE(v) == &DB_Type) |
| #define DBCursorObject_Check(v) (Py_TYPE(v) == &DBCursor_Type) |
| #define DBEnvObject_Check(v) (Py_TYPE(v) == &DBEnv_Type) |
| #define DBTxnObject_Check(v) (Py_TYPE(v) == &DBTxn_Type) |
| #define DBLockObject_Check(v) (Py_TYPE(v) == &DBLock_Type) |
| #if (DBVER >= 43) |
| #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; \ |
| } |
| |
| #define RETURN_NONE() Py_INCREF(Py_None); return Py_None; |
| |
| #define _CHECK_OBJECT_NOT_CLOSED(nonNull, pyErrObj, name) \ |
| if ((nonNull) == NULL) { \ |
| PyObject *errTuple = NULL; \ |
| errTuple = Py_BuildValue("(is)", 0, #name " object has been closed"); \ |
| if (errTuple) { \ |
| PyErr_SetObject((pyErrObj), errTuple); \ |
| Py_DECREF(errTuple); \ |
| } \ |
| return NULL; \ |
| } |
| |
| #define CHECK_DB_NOT_CLOSED(dbobj) \ |
| _CHECK_OBJECT_NOT_CLOSED(dbobj->db, DBError, DB) |
| |
| #define CHECK_ENV_NOT_CLOSED(env) \ |
| _CHECK_OBJECT_NOT_CLOSED(env->db_env, DBError, DBEnv) |
| |
| #define CHECK_CURSOR_NOT_CLOSED(curs) \ |
| _CHECK_OBJECT_NOT_CLOSED(curs->dbc, DBCursorClosedError, DBCursor) |
| |
| #if (DBVER >= 43) |
| #define CHECK_SEQUENCE_NOT_CLOSED(curs) \ |
| _CHECK_OBJECT_NOT_CLOSED(curs->sequence, DBError, DBSequence) |
| #endif |
| |
| #define CHECK_DBFLAG(mydb, flag) (((mydb)->flags & (flag)) || \ |
| (((mydb)->myenvobj != NULL) && ((mydb)->myenvobj->flags & (flag)))) |
| |
| #define CLEAR_DBT(dbt) (memset(&(dbt), 0, sizeof(dbt))) |
| |
| #define FREE_DBT(dbt) if ((dbt.flags & (DB_DBT_MALLOC|DB_DBT_REALLOC)) && \ |
| dbt.data != NULL) { free(dbt.data); dbt.data = NULL; } |
| |
| |
| static int makeDBError(int err); |
| |
| |
| /* Return the access method type of the DBObject */ |
| static int _DB_get_type(DBObject* self) |
| { |
| DBTYPE type; |
| int err; |
| |
| err = self->db->get_type(self->db, &type); |
| if (makeDBError(err)) { |
| return -1; |
| } |
| return type; |
| } |
| |
| |
| /* Create a DBT structure (containing key and data values) from Python |
| strings. Returns 1 on success, 0 on an error. */ |
| static int make_dbt(PyObject* obj, DBT* dbt) |
| { |
| CLEAR_DBT(*dbt); |
| if (obj == Py_None) { |
| /* no need to do anything, the structure has already been zeroed */ |
| } |
| else if (!PyArg_Parse(obj, "s#", &dbt->data, &dbt->size)) { |
| PyErr_SetString(PyExc_TypeError, |
| #if (PY_VERSION_HEX < 0x03000000) |
| "Data values must be of type string or None."); |
| #else |
| "Data values must be of type bytes or None."); |
| #endif |
| return 0; |
| } |
| return 1; |
| } |
| |
| |
| /* Recno and Queue DBs can have integer keys. This function figures out |
| what's been given, verifies that it's allowed, and then makes the DBT. |
| |
| Caller MUST call FREE_DBT(key) when done. */ |
| static int |
| make_key_dbt(DBObject* self, PyObject* keyobj, DBT* key, int* pflags) |
| { |
| db_recno_t recno; |
| int type; |
| |
| CLEAR_DBT(*key); |
| if (keyobj == Py_None) { |
| type = _DB_get_type(self); |
| if (type == -1) |
| return 0; |
| if (type == DB_RECNO || type == DB_QUEUE) { |
| PyErr_SetString( |
| PyExc_TypeError, |
| "None keys not allowed for Recno and Queue DB's"); |
| return 0; |
| } |
| /* no need to do anything, the structure has already been zeroed */ |
| } |
| |
| else if (PyBytes_Check(keyobj)) { |
| /* verify access method type */ |
| type = _DB_get_type(self); |
| if (type == -1) |
| return 0; |
| if (type == DB_RECNO || type == DB_QUEUE) { |
| PyErr_SetString( |
| PyExc_TypeError, |
| #if (PY_VERSION_HEX < 0x03000000) |
| "String keys not allowed for Recno and Queue DB's"); |
| #else |
| "Bytes keys not allowed for Recno and Queue DB's"); |
| #endif |
| return 0; |
| } |
| |
| /* |
| * NOTE(gps): I don't like doing a data copy here, it seems |
| * wasteful. But without a clean way to tell FREE_DBT if it |
| * should free key->data or not we have to. Other places in |
| * the code check for DB_THREAD and forceably set DBT_MALLOC |
| * when we otherwise would leave flags 0 to indicate that. |
| */ |
| key->data = malloc(PyBytes_GET_SIZE(keyobj)); |
| if (key->data == NULL) { |
| PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed"); |
| return 0; |
| } |
| memcpy(key->data, PyBytes_AS_STRING(keyobj), |
| PyBytes_GET_SIZE(keyobj)); |
| key->flags = DB_DBT_REALLOC; |
| key->size = PyBytes_GET_SIZE(keyobj); |
| } |
| |
| else if (NUMBER_Check(keyobj)) { |
| /* verify access method type */ |
| type = _DB_get_type(self); |
| if (type == -1) |
| return 0; |
| if (type == DB_BTREE && pflags != NULL) { |
| /* if BTREE then an Integer key is allowed with the |
| * DB_SET_RECNO flag */ |
| *pflags |= DB_SET_RECNO; |
| } |
| else if (type != DB_RECNO && type != DB_QUEUE) { |
| PyErr_SetString( |
| PyExc_TypeError, |
| "Integer keys only allowed for Recno and Queue DB's"); |
| return 0; |
| } |
| |
| /* Make a key out of the requested recno, use allocated space so DB |
| * will be able to realloc room for the real key if needed. */ |
| recno = NUMBER_AsLong(keyobj); |
| key->data = malloc(sizeof(db_recno_t)); |
| if (key->data == NULL) { |
| PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed"); |
| return 0; |
| } |
| key->ulen = key->size = sizeof(db_recno_t); |
| memcpy(key->data, &recno, sizeof(db_recno_t)); |
| key->flags = DB_DBT_REALLOC; |
| } |
| else { |
| PyErr_Format(PyExc_TypeError, |
| #if (PY_VERSION_HEX < 0x03000000) |
| "String or Integer object expected for key, %s found", |
| #else |
| "Bytes or Integer object expected for key, %s found", |
| #endif |
| Py_TYPE(keyobj)->tp_name); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| |
| /* Add partial record access to an existing DBT data struct. |
| If dlen and doff are set, then the DB_DBT_PARTIAL flag will be set |
| and the data storage/retrieval will be done using dlen and doff. */ |
| static int add_partial_dbt(DBT* d, int dlen, int doff) { |
| /* if neither were set we do nothing (-1 is the default value) */ |
| if ((dlen == -1) && (doff == -1)) { |
| return 1; |
| } |
| |
| if ((dlen < 0) || (doff < 0)) { |
| PyErr_SetString(PyExc_TypeError, "dlen and doff must both be >= 0"); |
| return 0; |
| } |
| |
| d->flags = d->flags | DB_DBT_PARTIAL; |
| d->dlen = (unsigned int) dlen; |
| d->doff = (unsigned int) doff; |
| return 1; |
| } |
| |
| /* a safe strcpy() without the zeroing behaviour and semantics of strncpy. */ |
| /* TODO: make this use the native libc strlcpy() when available (BSD) */ |
| unsigned int our_strlcpy(char* dest, const char* src, unsigned int n) |
| { |
| unsigned int srclen, copylen; |
| |
| srclen = strlen(src); |
| if (n <= 0) |
| return srclen; |
| copylen = (srclen > n-1) ? n-1 : srclen; |
| /* populate dest[0] thru dest[copylen-1] */ |
| memcpy(dest, src, copylen); |
| /* guarantee null termination */ |
| dest[copylen] = 0; |
| |
| return srclen; |
| } |
| |
| /* Callback used to save away more information about errors from the DB |
| * library. */ |
| static char _db_errmsg[1024]; |
| #if (DBVER <= 42) |
| static void _db_errorCallback(const char* prefix, char* msg) |
| #else |
| static void _db_errorCallback(const DB_ENV *db_env, |
| const char* prefix, const char* msg) |
| #endif |
| { |
| our_strlcpy(_db_errmsg, msg, sizeof(_db_errmsg)); |
| } |
| |
| |
| /* |
| ** 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 PyBytes_FromStringAndSize(p,s); |
| } |
| |
| static PyObject *BuildValue_S(const void *p,int s) |
| { |
| if (!p) { |
| p=DummyString; |
| assert(s==0); |
| } |
| return PyBytes_FromStringAndSize(p, s); |
| } |
| |
| static PyObject *BuildValue_SS(const void *p1,int s1,const void *p2,int s2) |
| { |
| PyObject *a, *b, *r; |
| |
| if (!p1) { |
| p1=DummyString; |
| assert(s1==0); |
| } |
| if (!p2) { |
| p2=DummyString; |
| assert(s2==0); |
| } |
| |
| if (!(a = PyBytes_FromStringAndSize(p1, s1))) { |
| return NULL; |
| } |
| if (!(b = PyBytes_FromStringAndSize(p2, s2))) { |
| Py_DECREF(a); |
| return NULL; |
| } |
| |
| #if (PY_VERSION_HEX >= 0x02040000) |
| r = PyTuple_Pack(2, a, b) ; |
| #else |
| r = Py_BuildValue("OO", a, b); |
| #endif |
| Py_DECREF(a); |
| Py_DECREF(b); |
| return r; |
| } |
| |
| static PyObject *BuildValue_IS(int i,const void *p,int s) |
| { |
| PyObject *a, *r; |
| |
| if (!p) { |
| p=DummyString; |
| assert(s==0); |
| } |
| |
| if (!(a = PyBytes_FromStringAndSize(p, s))) { |
| return NULL; |
| } |
| |
| r = Py_BuildValue("iO", i, a); |
| Py_DECREF(a); |
| return r; |
| } |
| |
| static PyObject *BuildValue_LS(long l,const void *p,int s) |
| { |
| PyObject *a, *r; |
| |
| if (!p) { |
| p=DummyString; |
| assert(s==0); |
| } |
| |
| if (!(a = PyBytes_FromStringAndSize(p, s))) { |
| return NULL; |
| } |
| |
| r = Py_BuildValue("lO", l, a); |
| Py_DECREF(a); |
| return r; |
| } |
| |
| |
| |
| /* make a nice exception object to raise for errors. */ |
| static int makeDBError(int err) |
| { |
| char errTxt[2048]; /* really big, just in case... */ |
| PyObject *errObj = NULL; |
| PyObject *errTuple = NULL; |
| int exceptionRaised = 0; |
| unsigned int bytes_left; |
| |
| switch (err) { |
| case 0: /* successful, no error */ break; |
| |
| #if (DBVER < 41) |
| case DB_INCOMPLETE: |
| #if INCOMPLETE_IS_WARNING |
| bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt)); |
| /* Ensure that bytes_left never goes negative */ |
| if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) { |
| bytes_left = sizeof(errTxt) - bytes_left - 4 - 1; |
| assert(bytes_left >= 0); |
| strcat(errTxt, " -- "); |
| strncat(errTxt, _db_errmsg, bytes_left); |
| } |
| _db_errmsg[0] = 0; |
| exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt); |
| |
| #else /* do an exception instead */ |
| errObj = DBIncompleteError; |
| #endif |
| break; |
| #endif /* DBVER < 41 */ |
| |
| case DB_KEYEMPTY: errObj = DBKeyEmptyError; break; |
| case DB_KEYEXIST: errObj = DBKeyExistError; break; |
| case DB_LOCK_DEADLOCK: errObj = DBLockDeadlockError; break; |
| case DB_LOCK_NOTGRANTED: errObj = DBLockNotGrantedError; break; |
| case DB_NOTFOUND: errObj = DBNotFoundError; break; |
| case DB_OLD_VERSION: errObj = DBOldVersionError; break; |
| case DB_RUNRECOVERY: errObj = DBRunRecoveryError; break; |
| case DB_VERIFY_BAD: errObj = DBVerifyBadError; break; |
| case DB_NOSERVER: errObj = DBNoServerError; break; |
| case DB_NOSERVER_HOME: errObj = DBNoServerHomeError; break; |
| case DB_NOSERVER_ID: errObj = DBNoServerIDError; break; |
| case DB_PAGE_NOTFOUND: errObj = DBPageNotFoundError; break; |
| case DB_SECONDARY_BAD: errObj = DBSecondaryBadError; break; |
| case DB_BUFFER_SMALL: errObj = DBNoMemoryError; break; |
| |
| #if (DBVER >= 43) |
| /* ENOMEM and DB_BUFFER_SMALL were one and the same until 4.3 */ |
| case ENOMEM: errObj = PyExc_MemoryError; break; |
| #endif |
| case EINVAL: errObj = DBInvalidArgError; break; |
| case EACCES: errObj = DBAccessError; break; |
| case ENOSPC: errObj = DBNoSpaceError; break; |
| case EAGAIN: errObj = DBAgainError; break; |
| case EBUSY : errObj = DBBusyError; break; |
| case EEXIST: errObj = DBFileExistsError; break; |
| case ENOENT: errObj = DBNoSuchFileError; break; |
| case EPERM : errObj = DBPermissionsError; break; |
| |
| #if (DBVER >= 42) |
| case DB_REP_HANDLE_DEAD : errObj = DBRepHandleDeadError; break; |
| #endif |
| |
| case DB_REP_UNAVAIL : errObj = DBRepUnavailError; break; |
| |
| default: errObj = DBError; break; |
| } |
| |
| if (errObj != NULL) { |
| bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt)); |
| /* Ensure that bytes_left never goes negative */ |
| if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) { |
| bytes_left = sizeof(errTxt) - bytes_left - 4 - 1; |
| assert(bytes_left >= 0); |
| strcat(errTxt, " -- "); |
| strncat(errTxt, _db_errmsg, bytes_left); |
| } |
| _db_errmsg[0] = 0; |
| |
| errTuple = Py_BuildValue("(is)", err, errTxt); |
| if (errTuple == NULL) { |
| Py_DECREF(errObj); |
| return !0; |
| } |
| PyErr_SetObject(errObj, errTuple); |
| Py_DECREF(errTuple); |
| } |
| |
| return ((errObj != NULL) || exceptionRaised); |
| } |
| |
| |
| |
| /* set a type exception */ |
| static void makeTypeError(char* expected, PyObject* found) |
| { |
| PyErr_Format(PyExc_TypeError, "Expected %s argument, %s found.", |
| expected, Py_TYPE(found)->tp_name); |
| } |
| |
| |
| /* verify that an obj is either None or a DBTxn, and set the txn pointer */ |
| static int checkTxnObj(PyObject* txnobj, DB_TXN** txn) |
| { |
| if (txnobj == Py_None || txnobj == NULL) { |
| *txn = NULL; |
| return 1; |
| } |
| if (DBTxnObject_Check(txnobj)) { |
| *txn = ((DBTxnObject*)txnobj)->txn; |
| return 1; |
| } |
| else |
| makeTypeError("DBTxn", txnobj); |
| return 0; |
| } |
| |
| |
| /* Delete a key from a database |
| Returns 0 on success, -1 on an error. */ |
| static int _DB_delete(DBObject* self, DB_TXN *txn, DBT *key, int flags) |
| { |
| int err; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->del(self->db, txn, key, 0); |
| MYDB_END_ALLOW_THREADS; |
| if (makeDBError(err)) { |
| return -1; |
| } |
| self->haveStat = 0; |
| return 0; |
| } |
| |
| |
| /* Store a key into a database |
| Returns 0 on success, -1 on an error. */ |
| static int _DB_put(DBObject* self, DB_TXN *txn, DBT *key, DBT *data, int flags) |
| { |
| int err; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->put(self->db, txn, key, data, flags); |
| MYDB_END_ALLOW_THREADS; |
| if (makeDBError(err)) { |
| return -1; |
| } |
| self->haveStat = 0; |
| return 0; |
| } |
| |
| /* Get a key/data pair from a cursor */ |
| static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags, |
| PyObject *args, PyObject *kwargs, char *format) |
| { |
| int err; |
| PyObject* retval = NULL; |
| DBT key, data; |
| int dlen = -1; |
| int doff = -1; |
| int flags = 0; |
| static char* kwnames[] = { "flags", "dlen", "doff", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, kwnames, |
| &flags, &dlen, &doff)) |
| return NULL; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| flags |= extra_flags; |
| CLEAR_DBT(key); |
| CLEAR_DBT(data); |
| if (!add_partial_dbt(&data, dlen, doff)) |
| return NULL; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = _DBC_get(self->dbc, &key, &data, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) |
| && self->mydb->moduleFlags.getReturnsNone) { |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (makeDBError(err)) { |
| retval = NULL; |
| } |
| else { /* otherwise, success! */ |
| |
| /* if Recno or Queue, return the key as an Int */ |
| switch (_DB_get_type(self->mydb)) { |
| case -1: |
| retval = NULL; |
| break; |
| |
| case DB_RECNO: |
| case DB_QUEUE: |
| retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size); |
| break; |
| case DB_HASH: |
| case DB_BTREE: |
| default: |
| retval = BuildValue_SS(key.data, key.size, data.data, data.size); |
| break; |
| } |
| } |
| return retval; |
| } |
| |
| |
| /* add an integer to a dictionary using the given name as a key */ |
| static void _addIntToDict(PyObject* dict, char *name, int value) |
| { |
| PyObject* v = NUMBER_FromLong((long) value); |
| if (!v || PyDict_SetItemString(dict, name, v)) |
| PyErr_Clear(); |
| |
| Py_XDECREF(v); |
| } |
| |
| /* The same, when the value is a time_t */ |
| static void _addTimeTToDict(PyObject* dict, char *name, time_t value) |
| { |
| PyObject* v; |
| /* if the value fits in regular int, use that. */ |
| #ifdef PY_LONG_LONG |
| if (sizeof(time_t) > sizeof(long)) |
| v = PyLong_FromLongLong((PY_LONG_LONG) value); |
| else |
| #endif |
| v = NUMBER_FromLong((long) value); |
| if (!v || PyDict_SetItemString(dict, name, v)) |
| PyErr_Clear(); |
| |
| Py_XDECREF(v); |
| } |
| |
| #if (DBVER >= 43) |
| /* add an db_seq_t to a dictionary using the given name as a key */ |
| static void _addDb_seq_tToDict(PyObject* dict, char *name, db_seq_t value) |
| { |
| PyObject* v = PyLong_FromLongLong(value); |
| if (!v || PyDict_SetItemString(dict, name, v)) |
| PyErr_Clear(); |
| |
| Py_XDECREF(v); |
| } |
| #endif |
| |
| 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); |
| } |
| |
| /* --------------------------------------------------------------------- */ |
| /* Allocators and deallocators */ |
| |
| static DBObject* |
| newDBObject(DBEnvObject* arg, int flags) |
| { |
| DBObject* self; |
| DB_ENV* db_env = NULL; |
| int err; |
| |
| self = PyObject_New(DBObject, &DB_Type); |
| if (self == NULL) |
| return NULL; |
| |
| self->haveStat = 0; |
| self->flags = 0; |
| self->setflags = 0; |
| self->myenvobj = NULL; |
| self->db = NULL; |
| self->children_cursors = NULL; |
| #if (DBVER >=43) |
| self->children_sequences = NULL; |
| #endif |
| self->associateCallback = NULL; |
| self->btCompareCallback = NULL; |
| self->primaryDBType = 0; |
| Py_INCREF(Py_None); |
| self->private_obj = Py_None; |
| self->in_weakreflist = NULL; |
| |
| /* keep a reference to our python DBEnv object */ |
| if (arg) { |
| 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; |
| else |
| self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE; |
| self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = db_create(&self->db, db_env, flags); |
| if (self->db != NULL) { |
| self->db->set_errcall(self->db, _db_errorCallback); |
| self->db->app_private = (void*)self; |
| } |
| MYDB_END_ALLOW_THREADS; |
| /* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs |
| * list so that a DBEnv can refuse to close without aborting any open |
| * DBTxns and closing any open DBs first. */ |
| if (makeDBError(err)) { |
| if (self->myenvobj) { |
| Py_DECREF(self->myenvobj); |
| self->myenvobj = NULL; |
| } |
| Py_DECREF(self); |
| self = NULL; |
| } |
| return self; |
| } |
| |
| |
| /* Forward declaration */ |
| static PyObject *DB_close_internal(DBObject* self, int flags, int do_not_close); |
| |
| static void |
| DB_dealloc(DBObject* self) |
| { |
| PyObject *dummy; |
| |
| if (self->db != NULL) { |
| dummy=DB_close_internal(self, 0, 0); |
| /* |
| ** Raising exceptions while doing |
| ** garbage collection is a fatal error. |
| */ |
| if (dummy) |
| Py_DECREF(dummy); |
| else |
| PyErr_Clear(); |
| } |
| if (self->in_weakreflist != NULL) { |
| PyObject_ClearWeakRefs((PyObject *) self); |
| } |
| if (self->myenvobj) { |
| Py_DECREF(self->myenvobj); |
| self->myenvobj = NULL; |
| } |
| if (self->associateCallback != NULL) { |
| Py_DECREF(self->associateCallback); |
| self->associateCallback = NULL; |
| } |
| if (self->btCompareCallback != NULL) { |
| Py_DECREF(self->btCompareCallback); |
| self->btCompareCallback = NULL; |
| } |
| Py_DECREF(self->private_obj); |
| PyObject_Del(self); |
| } |
| |
| static DBCursorObject* |
| newDBCursorObject(DBC* dbc, DBTxnObject *txn, DBObject* db) |
| { |
| DBCursorObject* self = PyObject_New(DBCursorObject, &DBCursor_Type); |
| if (self == NULL) |
| return NULL; |
| |
| 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) |
| { |
| PyObject *dummy; |
| |
| if (self->dbc != NULL) { |
| dummy=DBC_close_internal(self); |
| /* |
| ** Raising exceptions while doing |
| ** garbage collection is a fatal error. |
| */ |
| if (dummy) |
| Py_DECREF(dummy); |
| else |
| PyErr_Clear(); |
| } |
| if (self->in_weakreflist != NULL) { |
| PyObject_ClearWeakRefs((PyObject *) self); |
| } |
| Py_DECREF(self->mydb); |
| PyObject_Del(self); |
| } |
| |
| |
| static DBEnvObject* |
| newDBEnvObject(int flags) |
| { |
| int err; |
| DBEnvObject* self = PyObject_New(DBEnvObject, &DBEnv_Type); |
| if (self == NULL) |
| return NULL; |
| |
| self->db_env = NULL; |
| self->closed = 1; |
| 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; |
| Py_INCREF(Py_None); |
| self->private_obj = Py_None; |
| Py_INCREF(Py_None); |
| self->rep_transport = Py_None; |
| self->in_weakreflist = NULL; |
| self->event_notifyCallback = NULL; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = db_env_create(&self->db_env, flags); |
| MYDB_END_ALLOW_THREADS; |
| if (makeDBError(err)) { |
| Py_DECREF(self); |
| self = NULL; |
| } |
| 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) { |
| dummy=DBEnv_close_internal(self, 0); |
| /* |
| ** Raising exceptions while doing |
| ** garbage collection is a fatal error. |
| */ |
| if (dummy) |
| Py_DECREF(dummy); |
| else |
| PyErr_Clear(); |
| } |
| |
| Py_XDECREF(self->event_notifyCallback); |
| self->event_notifyCallback = NULL; |
| |
| if (self->in_weakreflist != NULL) { |
| PyObject_ClearWeakRefs((PyObject *) self); |
| } |
| Py_DECREF(self->private_obj); |
| Py_DECREF(self->rep_transport); |
| PyObject_Del(self); |
| } |
| |
| |
| static DBTxnObject* |
| 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; |
| |
| self->in_weakreflist = NULL; |
| self->children_txns = NULL; |
| self->children_dbs = NULL; |
| self->children_cursors = NULL; |
| self->children_sequences = NULL; |
| self->flag_prepare = 0; |
| self->parent_txn = NULL; |
| self->env = NULL; |
| |
| if (parent && ((PyObject *)parent!=Py_None)) { |
| parent_txn = parent->txn; |
| } |
| |
| if (txn) { |
| self->txn = txn; |
| } else { |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = myenv->db_env->txn_begin(myenv->db_env, parent_txn, &(self->txn), flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| if (makeDBError(err)) { |
| Py_DECREF(self); |
| return NULL; |
| } |
| } |
| |
| /* Can't use 'parent' because could be 'parent==Py_None' */ |
| if (parent_txn) { |
| 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); |
| } |
| |
| 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); |
| /* |
| ** Raising exceptions while doing |
| ** garbage collection is a fatal error. |
| */ |
| if (dummy) |
| Py_DECREF(dummy); |
| else |
| PyErr_Clear(); |
| |
| 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->env) { |
| Py_DECREF(self->env); |
| } else { |
| Py_DECREF(self->parent_txn); |
| } |
| PyObject_Del(self); |
| } |
| |
| |
| static DBLockObject* |
| newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj, |
| db_lockmode_t lock_mode, int flags) |
| { |
| int err; |
| DBLockObject* self = PyObject_New(DBLockObject, &DBLock_Type); |
| if (self == NULL) |
| return NULL; |
| self->in_weakreflist = NULL; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = myenv->db_env->lock_get(myenv->db_env, locker, flags, obj, lock_mode, |
| &self->lock); |
| MYDB_END_ALLOW_THREADS; |
| if (makeDBError(err)) { |
| Py_DECREF(self); |
| self = NULL; |
| } |
| |
| return self; |
| } |
| |
| |
| static void |
| DBLock_dealloc(DBLockObject* self) |
| { |
| if (self->in_weakreflist != NULL) { |
| PyObject_ClearWeakRefs((PyObject *) self); |
| } |
| /* TODO: is this lock held? should we release it? */ |
| |
| PyObject_Del(self); |
| } |
| |
| |
| #if (DBVER >= 43) |
| static DBSequenceObject* |
| newDBSequenceObject(DBObject* mydb, int flags) |
| { |
| int err; |
| DBSequenceObject* self = PyObject_New(DBSequenceObject, &DBSequence_Type); |
| if (self == NULL) |
| return NULL; |
| Py_INCREF(mydb); |
| self->mydb = mydb; |
| |
| 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); |
| MYDB_END_ALLOW_THREADS; |
| if (makeDBError(err)) { |
| Py_DECREF(self); |
| self = NULL; |
| } |
| |
| 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); |
| /* |
| ** Raising exceptions while doing |
| ** garbage collection is a fatal error. |
| */ |
| if (dummy) |
| Py_DECREF(dummy); |
| else |
| PyErr_Clear(); |
| } |
| |
| if (self->in_weakreflist != NULL) { |
| PyObject_ClearWeakRefs((PyObject *) self); |
| } |
| |
| Py_DECREF(self->mydb); |
| PyObject_Del(self); |
| } |
| #endif |
| |
| /* --------------------------------------------------------------------- */ |
| /* DB methods */ |
| |
| static PyObject* |
| DB_append(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| PyObject* txnobj = NULL; |
| PyObject* dataobj; |
| db_recno_t recno; |
| DBT key, data; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "data", "txn", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:append", kwnames, |
| &dataobj, &txnobj)) |
| return NULL; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| |
| /* make a dummy key out of a recno */ |
| recno = 0; |
| CLEAR_DBT(key); |
| key.data = &recno; |
| key.size = sizeof(recno); |
| key.ulen = key.size; |
| key.flags = DB_DBT_USERMEM; |
| |
| if (!make_dbt(dataobj, &data)) return NULL; |
| if (!checkTxnObj(txnobj, &txn)) return NULL; |
| |
| if (-1 == _DB_put(self, txn, &key, &data, DB_APPEND)) |
| return NULL; |
| |
| return NUMBER_FromLong(recno); |
| } |
| |
| |
| static int |
| _db_associateCallback(DB* db, const DBT* priKey, const DBT* priData, |
| DBT* secKey) |
| { |
| int retval = DB_DONOTINDEX; |
| DBObject* secondaryDB = (DBObject*)db->app_private; |
| PyObject* callback = secondaryDB->associateCallback; |
| int type = secondaryDB->primaryDBType; |
| PyObject* args; |
| PyObject* result = NULL; |
| |
| |
| if (callback != NULL) { |
| MYDB_BEGIN_BLOCK_THREADS; |
| |
| if (type == DB_RECNO || type == DB_QUEUE) |
| args = BuildValue_LS(*((db_recno_t*)priKey->data), priData->data, priData->size); |
| else |
| args = BuildValue_SS(priKey->data, priKey->size, priData->data, priData->size); |
| if (args != NULL) { |
| result = PyEval_CallObject(callback, args); |
| } |
| if (args == NULL || result == NULL) { |
| PyErr_Print(); |
| } |
| else if (result == Py_None) { |
| retval = DB_DONOTINDEX; |
| } |
| else if (NUMBER_Check(result)) { |
| retval = NUMBER_AsLong(result); |
| } |
| else if (PyBytes_Check(result)) { |
| char* data; |
| Py_ssize_t size; |
| |
| CLEAR_DBT(*secKey); |
| PyBytes_AsStringAndSize(result, &data, &size); |
| secKey->flags = DB_DBT_APPMALLOC; /* DB will free */ |
| secKey->data = malloc(size); /* TODO, check this */ |
| if (secKey->data) { |
| memcpy(secKey->data, data, size); |
| secKey->size = size; |
| retval = 0; |
| } |
| else { |
| PyErr_SetString(PyExc_MemoryError, |
| "malloc failed in _db_associateCallback"); |
| PyErr_Print(); |
| } |
| } |
| else { |
| PyErr_SetString( |
| PyExc_TypeError, |
| "DB associate callback should return DB_DONOTINDEX or string."); |
| PyErr_Print(); |
| } |
| |
| Py_XDECREF(args); |
| Py_XDECREF(result); |
| |
| MYDB_END_BLOCK_THREADS; |
| } |
| return retval; |
| } |
| |
| |
| static PyObject* |
| DB_associate(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags=0; |
| DBObject* secondaryDB; |
| PyObject* callback; |
| #if (DBVER >= 41) |
| PyObject *txnobj = NULL; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = {"secondaryDB", "callback", "flags", "txn", |
| NULL}; |
| #else |
| static char* kwnames[] = {"secondaryDB", "callback", "flags", NULL}; |
| #endif |
| |
| #if (DBVER >= 41) |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iO:associate", kwnames, |
| &secondaryDB, &callback, &flags, |
| &txnobj)) { |
| #else |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i:associate", kwnames, |
| &secondaryDB, &callback, &flags)) { |
| #endif |
| return NULL; |
| } |
| |
| #if (DBVER >= 41) |
| if (!checkTxnObj(txnobj, &txn)) return NULL; |
| #endif |
| |
| CHECK_DB_NOT_CLOSED(self); |
| if (!DBObject_Check(secondaryDB)) { |
| makeTypeError("DB", (PyObject*)secondaryDB); |
| return NULL; |
| } |
| CHECK_DB_NOT_CLOSED(secondaryDB); |
| if (callback == Py_None) { |
| callback = NULL; |
| } |
| else if (!PyCallable_Check(callback)) { |
| makeTypeError("Callable", callback); |
| return NULL; |
| } |
| |
| /* Save a reference to the callback in the secondary DB. */ |
| Py_XDECREF(secondaryDB->associateCallback); |
| Py_XINCREF(callback); |
| secondaryDB->associateCallback = callback; |
| secondaryDB->primaryDBType = _DB_get_type(self); |
| |
| /* PyEval_InitThreads is called here due to a quirk in python 1.5 |
| * - 2.2.1 (at least) according to Russell Williamson <merel@wt.net>: |
| * The global interepreter lock is not initialized until the first |
| * thread is created using thread.start_new_thread() or fork() is |
| * called. that would cause the ALLOW_THREADS here to segfault due |
| * to a null pointer reference if no threads or child processes |
| * have been created. This works around that and is a no-op if |
| * threads have already been initialized. |
| * (see pybsddb-users mailing list post on 2002-08-07) |
| */ |
| #ifdef WITH_THREAD |
| PyEval_InitThreads(); |
| #endif |
| MYDB_BEGIN_ALLOW_THREADS; |
| #if (DBVER >= 41) |
| err = self->db->associate(self->db, |
| txn, |
| secondaryDB->db, |
| _db_associateCallback, |
| flags); |
| #else |
| err = self->db->associate(self->db, |
| secondaryDB->db, |
| _db_associateCallback, |
| flags); |
| #endif |
| MYDB_END_ALLOW_THREADS; |
| |
| if (err) { |
| Py_XDECREF(secondaryDB->associateCallback); |
| secondaryDB->associateCallback = NULL; |
| secondaryDB->primaryDBType = 0; |
| } |
| |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_close_internal(DBObject* self, int flags, int do_not_close) |
| { |
| PyObject *dummy; |
| int err = 0; |
| |
| if (self->db != NULL) { |
| /* 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 |
| |
| /* |
| ** "do_not_close" is used to dispose all related objects in the |
| ** tree, without actually releasing the "root" object. |
| ** This is done, for example, because function calls like |
| ** "DB.verify()" implicitly close the underlying handle. So |
| ** the handle doesn't need to be closed, but related objects |
| ** must be cleaned up. |
| */ |
| if (!do_not_close) { |
| 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, 0); |
| } |
| |
| |
| static PyObject* |
| _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag) |
| { |
| int err, flags=0, type; |
| PyObject* txnobj = NULL; |
| PyObject* retval = NULL; |
| DBT key, data; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "txn", "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:consume", kwnames, |
| &txnobj, &flags)) |
| return NULL; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| type = _DB_get_type(self); |
| if (type == -1) |
| return NULL; |
| if (type != DB_QUEUE) { |
| PyErr_SetString(PyExc_TypeError, |
| "Consume methods only allowed for Queue DB's"); |
| return NULL; |
| } |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| |
| CLEAR_DBT(key); |
| CLEAR_DBT(data); |
| if (CHECK_DBFLAG(self, DB_THREAD)) { |
| /* Tell Berkeley DB to malloc the return value (thread safe) */ |
| data.flags = DB_DBT_MALLOC; |
| key.flags = DB_DBT_MALLOC; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->get(self->db, txn, &key, &data, flags|consume_flag); |
| MYDB_END_ALLOW_THREADS; |
| |
| if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) |
| && self->moduleFlags.getReturnsNone) { |
| err = 0; |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (!err) { |
| retval = BuildValue_SS(key.data, key.size, data.data, data.size); |
| FREE_DBT(key); |
| FREE_DBT(data); |
| } |
| |
| RETURN_IF_ERR(); |
| return retval; |
| } |
| |
| static PyObject* |
| DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag) |
| { |
| return _DB_consume(self, args, kwargs, DB_CONSUME); |
| } |
| |
| static PyObject* |
| DB_consume_wait(DBObject* self, PyObject* args, PyObject* kwargs, |
| int consume_flag) |
| { |
| return _DB_consume(self, args, kwargs, DB_CONSUME_WAIT); |
| } |
| |
| |
| static PyObject* |
| DB_cursor(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags=0; |
| DBC* dbc; |
| PyObject* txnobj = NULL; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "txn", "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames, |
| &txnobj, &flags)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->cursor(self->db, txn, &dbc, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| return (PyObject*) newDBCursorObject(dbc, (DBTxnObject *)txnobj, self); |
| } |
| |
| |
| static PyObject* |
| DB_delete(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| PyObject* txnobj = NULL; |
| int flags = 0; |
| PyObject* keyobj; |
| DBT key; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "key", "txn", "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:delete", kwnames, |
| &keyobj, &txnobj, &flags)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| if (!make_key_dbt(self, keyobj, &key, NULL)) |
| return NULL; |
| if (!checkTxnObj(txnobj, &txn)) { |
| FREE_DBT(key); |
| return NULL; |
| } |
| |
| if (-1 == _DB_delete(self, txn, &key, 0)) { |
| FREE_DBT(key); |
| return NULL; |
| } |
| |
| FREE_DBT(key); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_fd(DBObject* self) |
| { |
| int err, the_fd; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->fd(self->db, &the_fd); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| return NUMBER_FromLong(the_fd); |
| } |
| |
| |
| static PyObject* |
| DB_get(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags=0; |
| PyObject* txnobj = NULL; |
| PyObject* keyobj; |
| PyObject* dfltobj = NULL; |
| PyObject* retval = NULL; |
| int dlen = -1; |
| int doff = -1; |
| DBT key, data; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = {"key", "default", "txn", "flags", "dlen", |
| "doff", NULL}; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:get", kwnames, |
| &keyobj, &dfltobj, &txnobj, &flags, &dlen, |
| &doff)) |
| return NULL; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| if (!make_key_dbt(self, keyobj, &key, &flags)) |
| return NULL; |
| if (!checkTxnObj(txnobj, &txn)) { |
| FREE_DBT(key); |
| return NULL; |
| } |
| |
| CLEAR_DBT(data); |
| if (CHECK_DBFLAG(self, DB_THREAD)) { |
| /* Tell Berkeley DB 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->db->get(self->db, txn, &key, &data, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) { |
| err = 0; |
| Py_INCREF(dfltobj); |
| retval = dfltobj; |
| } |
| else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) |
| && self->moduleFlags.getReturnsNone) { |
| err = 0; |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (!err) { |
| if (flags & DB_SET_RECNO) /* return both key and data */ |
| retval = BuildValue_SS(key.data, key.size, data.data, data.size); |
| else /* return just the data */ |
| retval = Build_PyString(data.data, data.size); |
| FREE_DBT(data); |
| } |
| FREE_DBT(key); |
| |
| RETURN_IF_ERR(); |
| return retval; |
| } |
| |
| static PyObject* |
| DB_pget(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags=0; |
| PyObject* txnobj = NULL; |
| PyObject* keyobj; |
| PyObject* dfltobj = NULL; |
| PyObject* retval = NULL; |
| int dlen = -1; |
| int doff = -1; |
| DBT key, pkey, data; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = {"key", "default", "txn", "flags", "dlen", |
| "doff", NULL}; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:pget", kwnames, |
| &keyobj, &dfltobj, &txnobj, &flags, &dlen, |
| &doff)) |
| return NULL; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| if (!make_key_dbt(self, keyobj, &key, &flags)) |
| return NULL; |
| if (!checkTxnObj(txnobj, &txn)) { |
| FREE_DBT(key); |
| return NULL; |
| } |
| |
| CLEAR_DBT(data); |
| if (CHECK_DBFLAG(self, DB_THREAD)) { |
| /* Tell Berkeley DB to malloc the return value (thread safe) */ |
| data.flags = DB_DBT_MALLOC; |
| } |
| if (!add_partial_dbt(&data, dlen, doff)) { |
| FREE_DBT(key); |
| return NULL; |
| } |
| |
| CLEAR_DBT(pkey); |
| pkey.flags = DB_DBT_MALLOC; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->pget(self->db, txn, &key, &pkey, &data, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) { |
| err = 0; |
| Py_INCREF(dfltobj); |
| retval = dfltobj; |
| } |
| else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) |
| && self->moduleFlags.getReturnsNone) { |
| err = 0; |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (!err) { |
| PyObject *pkeyObj; |
| PyObject *dataObj; |
| dataObj = Build_PyString(data.data, data.size); |
| |
| if (self->primaryDBType == DB_RECNO || |
| self->primaryDBType == DB_QUEUE) |
| pkeyObj = NUMBER_FromLong(*(int *)pkey.data); |
| else |
| pkeyObj = Build_PyString(pkey.data, pkey.size); |
| |
| if (flags & DB_SET_RECNO) /* return key , pkey and data */ |
| { |
| PyObject *keyObj; |
| int type = _DB_get_type(self); |
| if (type == DB_RECNO || type == DB_QUEUE) |
| keyObj = NUMBER_FromLong(*(int *)key.data); |
| else |
| 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); |
| } |
| else /* return just the pkey and data */ |
| { |
| #if (PY_VERSION_HEX >= 0x02040000) |
| retval = PyTuple_Pack(2, pkeyObj, dataObj); |
| #else |
| retval = Py_BuildValue("OO", pkeyObj, dataObj); |
| #endif |
| } |
| Py_DECREF(dataObj); |
| Py_DECREF(pkeyObj); |
| FREE_DBT(pkey); |
| FREE_DBT(data); |
| } |
| FREE_DBT(key); |
| |
| RETURN_IF_ERR(); |
| return retval; |
| } |
| |
| |
| /* Return size of entry */ |
| static PyObject* |
| DB_get_size(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags=0; |
| PyObject* txnobj = NULL; |
| PyObject* keyobj; |
| PyObject* retval = NULL; |
| DBT key, data; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "key", "txn", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:get_size", kwnames, |
| &keyobj, &txnobj)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| if (!make_key_dbt(self, keyobj, &key, &flags)) |
| return NULL; |
| if (!checkTxnObj(txnobj, &txn)) { |
| FREE_DBT(key); |
| return NULL; |
| } |
| CLEAR_DBT(data); |
| |
| /* We don't allocate any memory, forcing a DB_BUFFER_SMALL error and |
| thus getting the record size. */ |
| data.flags = DB_DBT_USERMEM; |
| data.ulen = 0; |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->get(self->db, txn, &key, &data, flags); |
| MYDB_END_ALLOW_THREADS; |
| if (err == DB_BUFFER_SMALL) { |
| retval = NUMBER_FromLong((long)data.size); |
| err = 0; |
| } |
| |
| FREE_DBT(key); |
| FREE_DBT(data); |
| RETURN_IF_ERR(); |
| return retval; |
| } |
| |
| |
| static PyObject* |
| DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags=0; |
| PyObject* txnobj = NULL; |
| PyObject* keyobj; |
| PyObject* dataobj; |
| PyObject* retval = NULL; |
| DBT key, data; |
| void *orig_data; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "key", "data", "txn", "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oi:get_both", kwnames, |
| &keyobj, &dataobj, &txnobj, &flags)) |
| return NULL; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| if (!make_key_dbt(self, keyobj, &key, NULL)) |
| return NULL; |
| if ( !make_dbt(dataobj, &data) || |
| !checkTxnObj(txnobj, &txn) ) |
| { |
| FREE_DBT(key); |
| return NULL; |
| } |
| |
| flags |= DB_GET_BOTH; |
| orig_data = data.data; |
| |
| if (CHECK_DBFLAG(self, DB_THREAD)) { |
| /* 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; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->get(self->db, txn, &key, &data, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) |
| && self->moduleFlags.getReturnsNone) { |
| err = 0; |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (!err) { |
| /* XXX(nnorwitz): can we do: retval = dataobj; Py_INCREF(retval); */ |
| 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. :-( */ |
| if (data.data != orig_data) |
| FREE_DBT(data); |
| } |
| |
| FREE_DBT(key); |
| RETURN_IF_ERR(); |
| return retval; |
| } |
| |
| |
| static PyObject* |
| DB_get_byteswapped(DBObject* self) |
| { |
| int err = 0; |
| int retval = -1; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->get_byteswapped(self->db, &retval); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| return NUMBER_FromLong(retval); |
| } |
| |
| |
| static PyObject* |
| DB_get_type(DBObject* self) |
| { |
| int type; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| |
| type = _DB_get_type(self); |
| if (type == -1) |
| return NULL; |
| return NUMBER_FromLong(type); |
| } |
| |
| |
| static PyObject* |
| DB_join(DBObject* self, PyObject* args) |
| { |
| int err, flags=0; |
| int length, x; |
| PyObject* cursorsObj; |
| DBC** cursors; |
| DBC* dbc; |
| |
| if (!PyArg_ParseTuple(args,"O|i:join", &cursorsObj, &flags)) |
| return NULL; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| |
| if (!PySequence_Check(cursorsObj)) { |
| PyErr_SetString(PyExc_TypeError, |
| "Sequence of DBCursor objects expected"); |
| return NULL; |
| } |
| |
| length = PyObject_Length(cursorsObj); |
| cursors = malloc((length+1) * sizeof(DBC*)); |
| if (!cursors) { |
| PyErr_NoMemory(); |
| return NULL; |
| } |
| |
| cursors[length] = NULL; |
| for (x=0; x<length; x++) { |
| PyObject* item = PySequence_GetItem(cursorsObj, x); |
| if (item == NULL) { |
| free(cursors); |
| return NULL; |
| } |
| if (!DBCursorObject_Check(item)) { |
| PyErr_SetString(PyExc_TypeError, |
| "Sequence of DBCursor objects expected"); |
| free(cursors); |
| return NULL; |
| } |
| cursors[x] = ((DBCursorObject*)item)->dbc; |
| Py_DECREF(item); |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->join(self->db, cursors, &dbc, flags); |
| MYDB_END_ALLOW_THREADS; |
| free(cursors); |
| RETURN_IF_ERR(); |
| |
| /* FIXME: this is a buggy interface. The returned cursor |
| contains internal references to the passed in cursors |
| 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, NULL, self); |
| } |
| |
| |
| static PyObject* |
| DB_key_range(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags=0; |
| PyObject* txnobj = NULL; |
| PyObject* keyobj; |
| DBT key; |
| DB_TXN *txn = NULL; |
| DB_KEY_RANGE range; |
| static char* kwnames[] = { "key", "txn", "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:key_range", kwnames, |
| &keyobj, &txnobj, &flags)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| if (!make_dbt(keyobj, &key)) |
| /* BTree only, don't need to allow for an int key */ |
| return NULL; |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->key_range(self->db, txn, &key, &range, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| RETURN_IF_ERR(); |
| return Py_BuildValue("ddd", range.less, range.equal, range.greater); |
| } |
| |
| |
| static PyObject* |
| DB_open(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, type = DB_UNKNOWN, flags=0, mode=0660; |
| char* filename = NULL; |
| char* dbname = NULL; |
| #if (DBVER >= 41) |
| PyObject *txnobj = NULL; |
| DB_TXN *txn = NULL; |
| /* with dbname */ |
| static char* kwnames[] = { |
| "filename", "dbname", "dbtype", "flags", "mode", "txn", NULL}; |
| /* without dbname */ |
| static char* kwnames_basic[] = { |
| "filename", "dbtype", "flags", "mode", "txn", NULL}; |
| #else |
| /* with dbname */ |
| static char* kwnames[] = { |
| "filename", "dbname", "dbtype", "flags", "mode", NULL}; |
| /* without dbname */ |
| static char* kwnames_basic[] = { |
| "filename", "dbtype", "flags", "mode", NULL}; |
| #endif |
| |
| #if (DBVER >= 41) |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziiiO:open", kwnames, |
| &filename, &dbname, &type, &flags, &mode, |
| &txnobj)) |
| #else |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziii:open", kwnames, |
| &filename, &dbname, &type, &flags, |
| &mode)) |
| #endif |
| { |
| PyErr_Clear(); |
| type = DB_UNKNOWN; flags = 0; mode = 0660; |
| filename = NULL; dbname = NULL; |
| #if (DBVER >= 41) |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iiiO:open", |
| kwnames_basic, |
| &filename, &type, &flags, &mode, |
| &txnobj)) |
| return NULL; |
| #else |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iii:open", |
| kwnames_basic, |
| &filename, &type, &flags, &mode)) |
| return NULL; |
| #endif |
| } |
| |
| #if (DBVER >= 41) |
| if (!checkTxnObj(txnobj, &txn)) return NULL; |
| #endif |
| |
| if (NULL == self->db) { |
| PyObject *t = Py_BuildValue("(is)", 0, |
| "Cannot call open() twice for DB object"); |
| if (t) { |
| PyErr_SetObject(DBError, t); |
| Py_DECREF(t); |
| } |
| 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); |
| #else |
| err = self->db->open(self->db, filename, dbname, type, flags, mode); |
| #endif |
| MYDB_END_ALLOW_THREADS; |
| if (makeDBError(err)) { |
| PyObject *dummy; |
| |
| dummy=DB_close_internal(self, 0, 0); |
| Py_XDECREF(dummy); |
| return NULL; |
| } |
| |
| #if (DBVER >= 42) |
| self->db->get_flags(self->db, &self->setflags); |
| #endif |
| |
| self->flags = flags; |
| |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_put(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int flags=0; |
| PyObject* txnobj = NULL; |
| int dlen = -1; |
| int doff = -1; |
| PyObject* keyobj, *dataobj, *retval; |
| DBT key, data; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "key", "data", "txn", "flags", "dlen", |
| "doff", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oiii:put", kwnames, |
| &keyobj, &dataobj, &txnobj, &flags, &dlen, &doff)) |
| return NULL; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| if (!make_key_dbt(self, keyobj, &key, NULL)) |
| return NULL; |
| if ( !make_dbt(dataobj, &data) || |
| !add_partial_dbt(&data, dlen, doff) || |
| !checkTxnObj(txnobj, &txn) ) |
| { |
| FREE_DBT(key); |
| return NULL; |
| } |
| |
| if (-1 == _DB_put(self, txn, &key, &data, flags)) { |
| FREE_DBT(key); |
| return NULL; |
| } |
| |
| if (flags & DB_APPEND) |
| retval = NUMBER_FromLong(*((db_recno_t*)key.data)); |
| else { |
| retval = Py_None; |
| Py_INCREF(retval); |
| } |
| FREE_DBT(key); |
| return retval; |
| } |
| |
| |
| |
| static PyObject* |
| DB_remove(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| char* filename; |
| char* database = NULL; |
| int err, flags=0; |
| static char* kwnames[] = { "filename", "dbname", "flags", NULL}; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zi:remove", kwnames, |
| &filename, &database, &flags)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| EXTRACT_FROM_DOUBLE_LINKED_LIST_MAYBE_NULL(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->remove(self->db, filename, database, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| self->db = NULL; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| |
| static PyObject* |
| DB_rename(DBObject* self, PyObject* args) |
| { |
| char* filename; |
| char* database; |
| char* newname; |
| int err, flags=0; |
| |
| if (!PyArg_ParseTuple(args, "sss|i:rename", &filename, &database, &newname, |
| &flags)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->rename(self->db, filename, database, newname, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_get_private(DBObject* self) |
| { |
| /* We can give out the private field even if db is closed */ |
| Py_INCREF(self->private_obj); |
| return self->private_obj; |
| } |
| |
| static PyObject* |
| DB_set_private(DBObject* self, PyObject* private_obj) |
| { |
| /* We can set the private field even if db is closed */ |
| Py_DECREF(self->private_obj); |
| Py_INCREF(private_obj); |
| self->private_obj = private_obj; |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_bt_minkey(DBObject* self, PyObject* args) |
| { |
| int err, minkey; |
| |
| if (!PyArg_ParseTuple(args,"i:set_bt_minkey", &minkey )) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_bt_minkey(self->db, minkey); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static int |
| _default_cmp(const DBT *leftKey, |
| const DBT *rightKey) |
| { |
| int res; |
| int lsize = leftKey->size, rsize = rightKey->size; |
| |
| res = memcmp(leftKey->data, rightKey->data, |
| lsize < rsize ? lsize : rsize); |
| |
| if (res == 0) { |
| if (lsize < rsize) { |
| res = -1; |
| } |
| else if (lsize > rsize) { |
| res = 1; |
| } |
| } |
| return res; |
| } |
| |
| static int |
| _db_compareCallback(DB* db, |
| const DBT *leftKey, |
| const DBT *rightKey) |
| { |
| int res = 0; |
| PyObject *args; |
| PyObject *result = NULL; |
| DBObject *self = (DBObject *)db->app_private; |
| |
| if (self == NULL || self->btCompareCallback == NULL) { |
| MYDB_BEGIN_BLOCK_THREADS; |
| PyErr_SetString(PyExc_TypeError, |
| (self == 0 |
| ? "DB_bt_compare db is NULL." |
| : "DB_bt_compare callback is NULL.")); |
| /* we're in a callback within the DB code, we can't raise */ |
| PyErr_Print(); |
| res = _default_cmp(leftKey, rightKey); |
| MYDB_END_BLOCK_THREADS; |
| } else { |
| MYDB_BEGIN_BLOCK_THREADS; |
| |
| 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); |
| result = PyEval_CallObject(self->btCompareCallback, args); |
| } |
| if (args == NULL || result == NULL) { |
| /* we're in a callback within the DB code, we can't raise */ |
| PyErr_Print(); |
| res = _default_cmp(leftKey, rightKey); |
| } else if (NUMBER_Check(result)) { |
| res = NUMBER_AsLong(result); |
| } else { |
| PyErr_SetString(PyExc_TypeError, |
| "DB_bt_compare callback MUST return an int."); |
| /* we're in a callback within the DB code, we can't raise */ |
| PyErr_Print(); |
| res = _default_cmp(leftKey, rightKey); |
| } |
| |
| Py_XDECREF(args); |
| Py_XDECREF(result); |
| |
| MYDB_END_BLOCK_THREADS; |
| } |
| return res; |
| } |
| |
| static PyObject* |
| DB_set_bt_compare(DBObject* self, PyObject* comparator) |
| { |
| int err; |
| PyObject *tuple, *result; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| |
| if (!PyCallable_Check(comparator)) { |
| makeTypeError("Callable", comparator); |
| return NULL; |
| } |
| |
| /* |
| * Perform a test call of the comparator function with two empty |
| * string objects here. verify that it returns an int (0). |
| * err if not. |
| */ |
| tuple = Py_BuildValue("(ss)", "", ""); |
| result = PyEval_CallObject(comparator, tuple); |
| Py_DECREF(tuple); |
| if (result == NULL) |
| return NULL; |
| if (!NUMBER_Check(result)) { |
| PyErr_SetString(PyExc_TypeError, |
| "callback MUST return an int"); |
| return NULL; |
| } else if (NUMBER_AsLong(result) != 0) { |
| PyErr_SetString(PyExc_TypeError, |
| "callback failed to return 0 on two empty strings"); |
| return NULL; |
| } |
| Py_DECREF(result); |
| |
| /* We don't accept multiple set_bt_compare operations, in order to |
| * simplify the code. This would have no real use, as one cannot |
| * change the function once the db is opened anyway */ |
| if (self->btCompareCallback != NULL) { |
| PyErr_SetString(PyExc_RuntimeError, "set_bt_compare() cannot be called more than once"); |
| return NULL; |
| } |
| |
| Py_INCREF(comparator); |
| self->btCompareCallback = comparator; |
| |
| /* This is to workaround a problem with un-initialized threads (see |
| comment in DB_associate) */ |
| #ifdef WITH_THREAD |
| PyEval_InitThreads(); |
| #endif |
| |
| err = self->db->set_bt_compare(self->db, _db_compareCallback); |
| |
| if (err) { |
| /* restore the old state in case of error */ |
| Py_DECREF(comparator); |
| self->btCompareCallback = NULL; |
| } |
| |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_cachesize(DBObject* self, PyObject* args) |
| { |
| int err; |
| int gbytes = 0, bytes = 0, ncache = 0; |
| |
| if (!PyArg_ParseTuple(args,"ii|i:set_cachesize", |
| &gbytes,&bytes,&ncache)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_cachesize(self->db, gbytes, bytes, ncache); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_flags(DBObject* self, PyObject* args) |
| { |
| int err, flags; |
| |
| if (!PyArg_ParseTuple(args,"i:set_flags", &flags)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_flags(self->db, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| self->setflags |= flags; |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_h_ffactor(DBObject* self, PyObject* args) |
| { |
| int err, ffactor; |
| |
| if (!PyArg_ParseTuple(args,"i:set_h_ffactor", &ffactor)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_h_ffactor(self->db, ffactor); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_h_nelem(DBObject* self, PyObject* args) |
| { |
| int err, nelem; |
| |
| if (!PyArg_ParseTuple(args,"i:set_h_nelem", &nelem)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_h_nelem(self->db, nelem); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_lorder(DBObject* self, PyObject* args) |
| { |
| int err, lorder; |
| |
| if (!PyArg_ParseTuple(args,"i:set_lorder", &lorder)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_lorder(self->db, lorder); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_pagesize(DBObject* self, PyObject* args) |
| { |
| int err, pagesize; |
| |
| if (!PyArg_ParseTuple(args,"i:set_pagesize", &pagesize)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_pagesize(self->db, pagesize); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_re_delim(DBObject* self, PyObject* args) |
| { |
| int err; |
| char delim; |
| |
| if (!PyArg_ParseTuple(args,"b:set_re_delim", &delim)) { |
| PyErr_Clear(); |
| if (!PyArg_ParseTuple(args,"c:set_re_delim", &delim)) |
| return NULL; |
| } |
| |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_re_delim(self->db, delim); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DB_set_re_len(DBObject* self, PyObject* args) |
| { |
| int err, len; |
| |
| if (!PyArg_ParseTuple(args,"i:set_re_len", &len)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_re_len(self->db, len); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_re_pad(DBObject* self, PyObject* args) |
| { |
| int err; |
| char pad; |
| |
| if (!PyArg_ParseTuple(args,"b:set_re_pad", &pad)) { |
| PyErr_Clear(); |
| if (!PyArg_ParseTuple(args,"c:set_re_pad", &pad)) |
| return NULL; |
| } |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_re_pad(self->db, pad); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_re_source(DBObject* self, PyObject* args) |
| { |
| int err; |
| char *re_source; |
| |
| if (!PyArg_ParseTuple(args,"s:set_re_source", &re_source)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_re_source(self->db, re_source); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_q_extentsize(DBObject* self, PyObject* args) |
| { |
| int err; |
| int extentsize; |
| |
| if (!PyArg_ParseTuple(args,"i:set_q_extentsize", &extentsize)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_q_extentsize(self->db, extentsize); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DB_stat(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags = 0, type; |
| void* sp; |
| PyObject* d; |
| #if (DBVER >= 43) |
| PyObject* txnobj = NULL; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "flags", "txn", NULL }; |
| #else |
| static char* kwnames[] = { "flags", NULL }; |
| #endif |
| |
| #if (DBVER >= 43) |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iO:stat", kwnames, |
| &flags, &txnobj)) |
| return NULL; |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| #else |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat", kwnames, &flags)) |
| return NULL; |
| #endif |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| #if (DBVER >= 43) |
| err = self->db->stat(self->db, txn, &sp, flags); |
| #else |
| err = self->db->stat(self->db, &sp, flags); |
| #endif |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| self->haveStat = 1; |
| |
| /* Turn the stat structure into a dictionary */ |
| type = _DB_get_type(self); |
| if ((type == -1) || ((d = PyDict_New()) == NULL)) { |
| free(sp); |
| return NULL; |
| } |
| |
| #define MAKE_HASH_ENTRY(name) _addIntToDict(d, #name, ((DB_HASH_STAT*)sp)->hash_##name) |
| #define MAKE_BT_ENTRY(name) _addIntToDict(d, #name, ((DB_BTREE_STAT*)sp)->bt_##name) |
| #define MAKE_QUEUE_ENTRY(name) _addIntToDict(d, #name, ((DB_QUEUE_STAT*)sp)->qs_##name) |
| |
| switch (type) { |
| case DB_HASH: |
| MAKE_HASH_ENTRY(magic); |
| 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); |
| #endif |
| MAKE_HASH_ENTRY(ffactor); |
| MAKE_HASH_ENTRY(buckets); |
| MAKE_HASH_ENTRY(free); |
| MAKE_HASH_ENTRY(bfree); |
| MAKE_HASH_ENTRY(bigpages); |
| MAKE_HASH_ENTRY(big_bfree); |
| MAKE_HASH_ENTRY(overflows); |
| MAKE_HASH_ENTRY(ovfl_free); |
| MAKE_HASH_ENTRY(dup); |
| MAKE_HASH_ENTRY(dup_free); |
| break; |
| |
| case DB_BTREE: |
| case DB_RECNO: |
| MAKE_BT_ENTRY(magic); |
| 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); |
| MAKE_BT_ENTRY(re_pad); |
| MAKE_BT_ENTRY(levels); |
| MAKE_BT_ENTRY(int_pg); |
| 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); |
| MAKE_BT_ENTRY(dup_pgfree); |
| MAKE_BT_ENTRY(over_pgfree); |
| break; |
| |
| case DB_QUEUE: |
| MAKE_QUEUE_ENTRY(magic); |
| MAKE_QUEUE_ENTRY(version); |
| MAKE_QUEUE_ENTRY(nkeys); |
| MAKE_QUEUE_ENTRY(ndata); |
| MAKE_QUEUE_ENTRY(pagesize); |
| #if (DBVER >= 41) |
| MAKE_QUEUE_ENTRY(extentsize); |
| #endif |
| MAKE_QUEUE_ENTRY(pages); |
| MAKE_QUEUE_ENTRY(re_len); |
| MAKE_QUEUE_ENTRY(re_pad); |
| MAKE_QUEUE_ENTRY(pgfree); |
| #if (DBVER == 31) |
| MAKE_QUEUE_ENTRY(start); |
| #endif |
| MAKE_QUEUE_ENTRY(first_recno); |
| MAKE_QUEUE_ENTRY(cur_recno); |
| break; |
| |
| default: |
| PyErr_SetString(PyExc_TypeError, "Unknown DB type, unable to stat"); |
| Py_DECREF(d); |
| d = NULL; |
| } |
| |
| #undef MAKE_HASH_ENTRY |
| #undef MAKE_BT_ENTRY |
| #undef MAKE_QUEUE_ENTRY |
| |
| free(sp); |
| return d; |
| } |
| |
| static PyObject* |
| DB_sync(DBObject* self, PyObject* args) |
| { |
| int err; |
| int flags = 0; |
| |
| if (!PyArg_ParseTuple(args,"|i:sync", &flags )) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->sync(self->db, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_truncate(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags=0; |
| u_int32_t count=0; |
| PyObject* txnobj = NULL; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "txn", "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames, |
| &txnobj, &flags)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->truncate(self->db, txn, &count, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| return NUMBER_FromLong(count); |
| } |
| |
| |
| static PyObject* |
| DB_upgrade(DBObject* self, PyObject* args) |
| { |
| int err, flags=0; |
| char *filename; |
| |
| if (!PyArg_ParseTuple(args,"s|i:upgrade", &filename, &flags)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->upgrade(self->db, filename, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_verify(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags=0; |
| char* fileName; |
| char* dbName=NULL; |
| char* outFileName=NULL; |
| FILE* outFile=NULL; |
| static char* kwnames[] = { "filename", "dbname", "outfile", "flags", |
| NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zzi:verify", kwnames, |
| &fileName, &dbName, &outFileName, &flags)) |
| return NULL; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| if (outFileName) |
| outFile = fopen(outFileName, "w"); |
| /* XXX(nnorwitz): it should probably be an exception if outFile |
| can't be opened. */ |
| |
| { /* DB.verify acts as a DB handle destructor (like close) */ |
| PyObject *error; |
| |
| error=DB_close_internal(self, 0, 1); |
| if (error ) { |
| return error; |
| } |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->verify(self->db, fileName, dbName, outFile, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| self->db = NULL; /* Implicit close; related objects already released */ |
| |
| if (outFile) |
| fclose(outFile); |
| |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DB_set_get_returns_none(DBObject* self, PyObject* args) |
| { |
| int flags=0; |
| int oldValue=0; |
| |
| if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags)) |
| return NULL; |
| CHECK_DB_NOT_CLOSED(self); |
| |
| if (self->moduleFlags.getReturnsNone) |
| ++oldValue; |
| if (self->moduleFlags.cursorSetReturnsNone) |
| ++oldValue; |
| self->moduleFlags.getReturnsNone = (flags >= 1); |
| self->moduleFlags.cursorSetReturnsNone = (flags >= 2); |
| return NUMBER_FromLong(oldValue); |
| } |
| |
| #if (DBVER >= 41) |
| static PyObject* |
| DB_set_encrypt(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err; |
| u_int32_t flags=0; |
| char *passwd = NULL; |
| static char* kwnames[] = { "passwd", "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames, |
| &passwd, &flags)) { |
| return NULL; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->set_encrypt(self->db, passwd, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| #endif /* DBVER >= 41 */ |
| |
| |
| /*-------------------------------------------------------------- */ |
| /* Mapping and Dictionary-like access routines */ |
| |
| Py_ssize_t DB_length(PyObject* _self) |
| { |
| int err; |
| Py_ssize_t size = 0; |
| int flags = 0; |
| void* sp; |
| DBObject* self = (DBObject*)_self; |
| |
| if (self->db == NULL) { |
| PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed"); |
| if (t) { |
| PyErr_SetObject(DBError, t); |
| Py_DECREF(t); |
| } |
| return -1; |
| } |
| |
| if (self->haveStat) { /* Has the stat function been called recently? If |
| so, we can use the cached value. */ |
| flags = DB_FAST_STAT; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| redo_stat_for_length: |
| #if (DBVER >= 43) |
| err = self->db->stat(self->db, /*txnid*/ NULL, &sp, flags); |
| #else |
| err = self->db->stat(self->db, &sp, flags); |
| #endif |
| |
| /* All the stat structures have matching fields upto the ndata field, |
| 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 Berkeley DB no longer had the stat values cached. |
| * redo a full stat to make sure. |
| * Fixes SF python bug 1493322, pybsddb bug 1184012 |
| */ |
| if (size == 0 && (flags & DB_FAST_STAT)) { |
| flags = 0; |
| if (!err) |
| free(sp); |
| goto redo_stat_for_length; |
| } |
| |
| MYDB_END_ALLOW_THREADS; |
| |
| if (err) |
| return -1; |
| |
| self->haveStat = 1; |
| |
| free(sp); |
| return size; |
| } |
| |
| |
| PyObject* DB_subscript(DBObject* self, PyObject* keyobj) |
| { |
| int err; |
| PyObject* retval; |
| DBT key; |
| DBT data; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| if (!make_key_dbt(self, keyobj, &key, NULL)) |
| return NULL; |
| |
| CLEAR_DBT(data); |
| if (CHECK_DBFLAG(self, DB_THREAD)) { |
| /* Tell Berkeley DB to malloc the return value (thread safe) */ |
| data.flags = DB_DBT_MALLOC; |
| } |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->get(self->db, NULL, &key, &data, 0); |
| MYDB_END_ALLOW_THREADS; |
| if (err == DB_NOTFOUND || err == DB_KEYEMPTY) { |
| PyErr_SetObject(PyExc_KeyError, keyobj); |
| retval = NULL; |
| } |
| else if (makeDBError(err)) { |
| retval = NULL; |
| } |
| else { |
| retval = Build_PyString(data.data, data.size); |
| FREE_DBT(data); |
| } |
| |
| FREE_DBT(key); |
| return retval; |
| } |
| |
| |
| static int |
| DB_ass_sub(DBObject* self, PyObject* keyobj, PyObject* dataobj) |
| { |
| DBT key, data; |
| int retval; |
| int flags = 0; |
| |
| if (self->db == NULL) { |
| PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed"); |
| if (t) { |
| PyErr_SetObject(DBError, t); |
| Py_DECREF(t); |
| } |
| return -1; |
| } |
| |
| if (!make_key_dbt(self, keyobj, &key, NULL)) |
| return -1; |
| |
| if (dataobj != NULL) { |
| if (!make_dbt(dataobj, &data)) |
| retval = -1; |
| else { |
| if (self->setflags & (DB_DUP|DB_DUPSORT)) |
| /* dictionaries shouldn't have duplicate keys */ |
| flags = DB_NOOVERWRITE; |
| retval = _DB_put(self, NULL, &key, &data, flags); |
| |
| if ((retval == -1) && (self->setflags & (DB_DUP|DB_DUPSORT))) { |
| /* try deleting any old record that matches and then PUT it |
| * again... */ |
| _DB_delete(self, NULL, &key, 0); |
| PyErr_Clear(); |
| retval = _DB_put(self, NULL, &key, &data, flags); |
| } |
| } |
| } |
| else { |
| /* dataobj == NULL, so delete the key */ |
| retval = _DB_delete(self, NULL, &key, 0); |
| } |
| FREE_DBT(key); |
| return retval; |
| } |
| |
| |
| static PyObject* |
| DB_has_key(DBObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err; |
| PyObject* keyobj; |
| DBT key, data; |
| PyObject* txnobj = NULL; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = {"key","txn", NULL}; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:has_key", kwnames, |
| &keyobj, &txnobj)) |
| return NULL; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| if (!make_key_dbt(self, keyobj, &key, NULL)) |
| return NULL; |
| if (!checkTxnObj(txnobj, &txn)) { |
| FREE_DBT(key); |
| return NULL; |
| } |
| |
| /* This causes DB_BUFFER_SMALL to be returned when the db has the key because |
| it has a record but can't allocate a buffer for the data. This saves |
| having to deal with data we won't be using. |
| */ |
| CLEAR_DBT(data); |
| data.flags = DB_DBT_USERMEM; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->get(self->db, txn, &key, &data, 0); |
| MYDB_END_ALLOW_THREADS; |
| FREE_DBT(key); |
| |
| if (err == DB_BUFFER_SMALL || err == 0) { |
| return NUMBER_FromLong(1); |
| } else if (err == DB_NOTFOUND || err == DB_KEYEMPTY) { |
| return NUMBER_FromLong(0); |
| } |
| |
| makeDBError(err); |
| return NULL; |
| } |
| |
| |
| #define _KEYS_LIST 1 |
| #define _VALUES_LIST 2 |
| #define _ITEMS_LIST 3 |
| |
| static PyObject* |
| _DB_make_list(DBObject* self, DB_TXN* txn, int type) |
| { |
| int err, dbtype; |
| DBT key; |
| DBT data; |
| DBC *cursor; |
| PyObject* list; |
| PyObject* item = NULL; |
| |
| CHECK_DB_NOT_CLOSED(self); |
| CLEAR_DBT(key); |
| CLEAR_DBT(data); |
| |
| dbtype = _DB_get_type(self); |
| if (dbtype == -1) |
| return NULL; |
| |
| list = PyList_New(0); |
| if (list == NULL) |
| return NULL; |
| |
| /* get a cursor */ |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db->cursor(self->db, txn, &cursor, 0); |
| MYDB_END_ALLOW_THREADS; |
| if (makeDBError(err)) { |
| Py_DECREF(list); |
| return NULL; |
| } |
| |
| while (1) { /* use the cursor to traverse the DB, collecting items */ |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = _DBC_get(cursor, &key, &data, DB_NEXT); |
| MYDB_END_ALLOW_THREADS; |
| |
| if (err) { |
| /* for any error, break out of the loop */ |
| break; |
| } |
| |
| switch (type) { |
| case _KEYS_LIST: |
| switch(dbtype) { |
| case DB_BTREE: |
| case DB_HASH: |
| default: |
| item = Build_PyString(key.data, key.size); |
| break; |
| case DB_RECNO: |
| case DB_QUEUE: |
| item = NUMBER_FromLong(*((db_recno_t*)key.data)); |
| break; |
| } |
| break; |
| |
| case _VALUES_LIST: |
| item = Build_PyString(data.data, data.size); |
| break; |
| |
| case _ITEMS_LIST: |
| switch(dbtype) { |
| case DB_BTREE: |
| case DB_HASH: |
| default: |
| item = BuildValue_SS(key.data, key.size, data.data, data.size); |
| break; |
| case DB_RECNO: |
| case DB_QUEUE: |
| item = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size); |
| break; |
| } |
| break; |
| default: |
| PyErr_Format(PyExc_ValueError, "Unknown key type 0x%x", type); |
| item = NULL; |
| break; |
| } |
| if (item == NULL) { |
| Py_DECREF(list); |
| list = NULL; |
| goto done; |
| } |
| if (PyList_Append(list, item)) { |
| Py_DECREF(list); |
| Py_DECREF(item); |
| list = NULL; |
| goto done; |
| } |
| Py_DECREF(item); |
| } |
| |
| /* DB_NOTFOUND || DB_KEYEMPTY is okay, it means we got to the end */ |
| if (err != DB_NOTFOUND && err != DB_KEYEMPTY && makeDBError(err)) { |
| Py_DECREF(list); |
| list = NULL; |
| } |
| |
| done: |
| MYDB_BEGIN_ALLOW_THREADS; |
| _DBC_close(cursor); |
| MYDB_END_ALLOW_THREADS; |
| return list; |
| } |
| |
| |
| static PyObject* |
| DB_keys(DBObject* self, PyObject* args) |
| { |
| PyObject* txnobj = NULL; |
| DB_TXN *txn = NULL; |
| |
| if (!PyArg_UnpackTuple(args, "keys", 0, 1, &txnobj)) |
| return NULL; |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| return _DB_make_list(self, txn, _KEYS_LIST); |
| } |
| |
| |
| static PyObject* |
| DB_items(DBObject* self, PyObject* args) |
| { |
| PyObject* txnobj = NULL; |
| DB_TXN *txn = NULL; |
| |
| if (!PyArg_UnpackTuple(args, "items", 0, 1, &txnobj)) |
| return NULL; |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| return _DB_make_list(self, txn, _ITEMS_LIST); |
| } |
| |
| |
| static PyObject* |
| DB_values(DBObject* self, PyObject* args) |
| { |
| PyObject* txnobj = NULL; |
| DB_TXN *txn = NULL; |
| |
| if (!PyArg_UnpackTuple(args, "values", 0, 1, &txnobj)) |
| return NULL; |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| return _DB_make_list(self, txn, _VALUES_LIST); |
| } |
| |
| /* --------------------------------------------------------------------- */ |
| /* DBCursor methods */ |
| |
| |
| static PyObject* |
| DBC_close_internal(DBCursorObject* self) |
| { |
| int err = 0; |
| |
| 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 = _DBC_close(self->dbc); |
| MYDB_END_ALLOW_THREADS; |
| self->dbc = NULL; |
| } |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBC_close(DBCursorObject* self) |
| { |
| return DBC_close_internal(self); |
| } |
| |
| |
| static PyObject* |
| DBC_count(DBCursorObject* self, PyObject* args) |
| { |
| int err = 0; |
| db_recno_t count; |
| int flags = 0; |
| |
| if (!PyArg_ParseTuple(args, "|i:count", &flags)) |
| return NULL; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = _DBC_count(self->dbc, &count, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| return NUMBER_FromLong(count); |
| } |
| |
| |
| static PyObject* |
| DBC_current(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| return _DBCursor_get(self,DB_CURRENT,args,kwargs,"|iii:current"); |
| } |
| |
| |
| static PyObject* |
| DBC_delete(DBCursorObject* self, PyObject* args) |
| { |
| int err, flags=0; |
| |
| if (!PyArg_ParseTuple(args, "|i:delete", &flags)) |
| return NULL; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = _DBC_del(self->dbc, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| self->mydb->haveStat = 0; |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBC_dup(DBCursorObject* self, PyObject* args) |
| { |
| int err, flags =0; |
| DBC* dbc = NULL; |
| |
| if (!PyArg_ParseTuple(args, "|i:dup", &flags)) |
| return NULL; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = _DBC_dup(self->dbc, &dbc, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| return (PyObject*) newDBCursorObject(dbc, self->txn, self->mydb); |
| } |
| |
| static PyObject* |
| DBC_first(DBCursorObject* self, PyObject* args, PyObject* kwargs) |
| { |
| return _DBCursor_get(self,DB_FIRST,args,kwargs,"|iii:first"); |
| } |
| |
| |
| static PyObject* |
| DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| int err, flags=0; |
| PyObject* keyobj = NULL; |
| PyObject* dataobj = NULL; |
| PyObject* retval = NULL; |
| int dlen = -1; |
| int doff = -1; |
| DBT key, data; |
| static char* kwnames[] = { "key","data", "flags", "dlen", "doff", |
| NULL }; |
| |
| CLEAR_DBT(key); |
| CLEAR_DBT(data); |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:get", &kwnames[2], |
| &flags, &dlen, &doff)) |
| { |
| PyErr_Clear(); |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:get", |
| &kwnames[1], |
| &keyobj, &flags, &dlen, &doff)) |
| { |
| PyErr_Clear(); |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:get", |
| kwnames, &keyobj, &dataobj, |
| &flags, &dlen, &doff)) |
| { |
| return NULL; |
| } |
| } |
| } |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL)) |
| return NULL; |
| if ( (dataobj && !make_dbt(dataobj, &data)) || |
| (!add_partial_dbt(&data, dlen, doff)) ) |
| { |
| FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */ |
| return NULL; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = _DBC_get(self->dbc, &key, &data, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) |
| && self->mydb->moduleFlags.getReturnsNone) { |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (makeDBError(err)) { |
| retval = NULL; |
| } |
| else { |
| switch (_DB_get_type(self->mydb)) { |
| case -1: |
| retval = NULL; |
| break; |
| case DB_BTREE: |
| case DB_HASH: |
| default: |
| retval = BuildValue_SS(key.data, key.size, data.data, data.size); |
| break; |
| case DB_RECNO: |
| case DB_QUEUE: |
| retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size); |
| break; |
| } |
| } |
| FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */ |
| return retval; |
| } |
| |
| static PyObject* |
| DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| int err, flags=0; |
| PyObject* keyobj = NULL; |
| PyObject* dataobj = NULL; |
| PyObject* retval = NULL; |
| int dlen = -1; |
| int doff = -1; |
| DBT key, pkey, data; |
| static char* kwnames_keyOnly[] = { "key", "flags", "dlen", "doff", NULL }; |
| static char* kwnames[] = { "key", "data", "flags", "dlen", "doff", NULL }; |
| |
| CLEAR_DBT(key); |
| CLEAR_DBT(data); |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:pget", &kwnames[2], |
| &flags, &dlen, &doff)) |
| { |
| PyErr_Clear(); |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:pget", |
| kwnames_keyOnly, |
| &keyobj, &flags, &dlen, &doff)) |
| { |
| PyErr_Clear(); |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:pget", |
| kwnames, &keyobj, &dataobj, |
| &flags, &dlen, &doff)) |
| { |
| return NULL; |
| } |
| } |
| } |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL)) |
| return NULL; |
| if ( (dataobj && !make_dbt(dataobj, &data)) || |
| (!add_partial_dbt(&data, dlen, doff)) ) { |
| FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */ |
| return NULL; |
| } |
| |
| CLEAR_DBT(pkey); |
| pkey.flags = DB_DBT_MALLOC; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = _DBC_pget(self->dbc, &key, &pkey, &data, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) |
| && self->mydb->moduleFlags.getReturnsNone) { |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (makeDBError(err)) { |
| retval = NULL; |
| } |
| else { |
| PyObject *pkeyObj; |
| PyObject *dataObj; |
| dataObj = Build_PyString(data.data, data.size); |
| |
| if (self->mydb->primaryDBType == DB_RECNO || |
| self->mydb->primaryDBType == DB_QUEUE) |
| pkeyObj = NUMBER_FromLong(*(int *)pkey.data); |
| else |
| pkeyObj = Build_PyString(pkey.data, pkey.size); |
| |
| if (key.data && key.size) /* return key, pkey and data */ |
| { |
| PyObject *keyObj; |
| int type = _DB_get_type(self->mydb); |
| if (type == DB_RECNO || type == DB_QUEUE) |
| keyObj = NUMBER_FromLong(*(int *)key.data); |
| else |
| 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); /* 'make_key_dbt' could do a 'malloc' */ |
| } |
| else /* return just the pkey and data */ |
| { |
| #if (PY_VERSION_HEX >= 0x02040000) |
| retval = PyTuple_Pack(2, pkeyObj, dataObj); |
| #else |
| retval = Py_BuildValue("OO", pkeyObj, dataObj); |
| #endif |
| } |
| Py_DECREF(dataObj); |
| Py_DECREF(pkeyObj); |
| FREE_DBT(pkey); |
| } |
| /* 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) { /* 'make_key_dbt' could do a 'malloc' */ |
| FREE_DBT(key); |
| } |
| return retval; |
| } |
| |
| |
| static PyObject* |
| DBC_get_recno(DBCursorObject* self) |
| { |
| int err; |
| db_recno_t recno; |
| DBT key; |
| DBT data; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| CLEAR_DBT(key); |
| CLEAR_DBT(data); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = _DBC_get(self->dbc, &key, &data, DB_GET_RECNO); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| recno = *((db_recno_t*)data.data); |
| return NUMBER_FromLong(recno); |
| } |
| |
| |
| static PyObject* |
| DBC_last(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| return _DBCursor_get(self,DB_LAST,args,kwargs,"|iii:last"); |
| } |
| |
| |
| static PyObject* |
| DBC_next(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| return _DBCursor_get(self,DB_NEXT,args,kwargs,"|iii:next"); |
| } |
| |
| |
| static PyObject* |
| DBC_prev(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| return _DBCursor_get(self,DB_PREV,args,kwargs,"|iii:prev"); |
| } |
| |
| |
| static PyObject* |
| DBC_put(DBCursorObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags = 0; |
| PyObject* keyobj, *dataobj; |
| DBT key, data; |
| static char* kwnames[] = { "key", "data", "flags", "dlen", "doff", |
| NULL }; |
| int dlen = -1; |
| int doff = -1; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iii:put", kwnames, |
| &keyobj, &dataobj, &flags, &dlen, &doff)) |
| return NULL; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) |
| return NULL; |
| if (!make_dbt(dataobj, &data) || |
| !add_partial_dbt(&data, dlen, doff) ) |
| { |
| FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */ |
| return NULL; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = _DBC_put(self->dbc, &key, &data, flags); |
| MYDB_END_ALLOW_THREADS; |
| FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */ |
| RETURN_IF_ERR(); |
| self->mydb->haveStat = 0; |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| int err, flags = 0; |
| DBT key, data; |
| PyObject* retval, *keyobj; |
| static char* kwnames[] = { "key", "flags", "dlen", "doff", NULL }; |
| int dlen = -1; |
| int doff = -1; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set", kwnames, |
| &keyobj, &flags, &dlen, &doff)) |
| return NULL; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) |
| return NULL; |
| |
| CLEAR_DBT(data); |
| if (!add_partial_dbt(&data, dlen, doff)) { |
| FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */ |
| return NULL; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| 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) { |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (makeDBError(err)) { |
| retval = NULL; |
| } |
| else { |
| switch (_DB_get_type(self->mydb)) { |
| case -1: |
| retval = NULL; |
| break; |
| case DB_BTREE: |
| case DB_HASH: |
| default: |
| retval = BuildValue_SS(key.data, key.size, data.data, data.size); |
| break; |
| case DB_RECNO: |
| case DB_QUEUE: |
| retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size); |
| break; |
| } |
| 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); /* 'make_key_dbt' could do a 'malloc' */ |
| } |
| |
| return retval; |
| } |
| |
| |
| static PyObject* |
| DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags = 0; |
| DBT key, data; |
| PyObject* retval, *keyobj; |
| static char* kwnames[] = { "key", "flags", "dlen", "doff", NULL }; |
| int dlen = -1; |
| int doff = -1; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set_range", kwnames, |
| &keyobj, &flags, &dlen, &doff)) |
| return NULL; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) |
| return NULL; |
| |
| CLEAR_DBT(data); |
| if (!add_partial_dbt(&data, dlen, doff)) { |
| FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */ |
| return NULL; |
| } |
| MYDB_BEGIN_ALLOW_THREADS; |
| 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) { |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (makeDBError(err)) { |
| retval = NULL; |
| } |
| else { |
| switch (_DB_get_type(self->mydb)) { |
| case -1: |
| retval = NULL; |
| break; |
| case DB_BTREE: |
| case DB_HASH: |
| default: |
| retval = BuildValue_SS(key.data, key.size, data.data, data.size); |
| break; |
| case DB_RECNO: |
| case DB_QUEUE: |
| retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size); |
| break; |
| } |
| 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); /* 'make_key_dbt' could do a 'malloc' */ |
| } |
| |
| return retval; |
| } |
| |
| static PyObject* |
| _DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj, |
| int flags, unsigned int returnsNone) |
| { |
| int err; |
| DBT key, data; |
| PyObject* retval; |
| |
| /* the caller did this: CHECK_CURSOR_NOT_CLOSED(self); */ |
| if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) |
| return NULL; |
| if (!make_dbt(dataobj, &data)) { |
| FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */ |
| return NULL; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| 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); |
| retval = Py_None; |
| } |
| else if (makeDBError(err)) { |
| retval = NULL; |
| } |
| else { |
| switch (_DB_get_type(self->mydb)) { |
| case -1: |
| retval = NULL; |
| break; |
| case DB_BTREE: |
| case DB_HASH: |
| default: |
| retval = BuildValue_SS(key.data, key.size, data.data, data.size); |
| break; |
| case DB_RECNO: |
| case DB_QUEUE: |
| retval = BuildValue_IS(*((db_recno_t*)key.data), data.data, data.size); |
| break; |
| } |
| } |
| |
| FREE_DBT(key); /* 'make_key_dbt' could do a 'malloc' */ |
| return retval; |
| } |
| |
| static PyObject* |
| DBC_get_both(DBCursorObject* self, PyObject* args) |
| { |
| int flags=0; |
| PyObject *keyobj, *dataobj; |
| |
| if (!PyArg_ParseTuple(args, "OO|i:get_both", &keyobj, &dataobj, &flags)) |
| return NULL; |
| |
| /* if the cursor is closed, self->mydb may be invalid */ |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| return _DBC_get_set_both(self, keyobj, dataobj, flags, |
| self->mydb->moduleFlags.getReturnsNone); |
| } |
| |
| /* Return size of entry */ |
| static PyObject* |
| DBC_get_current_size(DBCursorObject* self) |
| { |
| int err, flags=DB_CURRENT; |
| PyObject* retval = NULL; |
| DBT key, data; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| CLEAR_DBT(key); |
| CLEAR_DBT(data); |
| |
| /* We don't allocate any memory, forcing a DB_BUFFER_SMALL error and thus |
| getting the record size. */ |
| data.flags = DB_DBT_USERMEM; |
| data.ulen = 0; |
| MYDB_BEGIN_ALLOW_THREADS; |
| 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 */ |
| retval = NUMBER_FromLong((long)data.size); |
| err = 0; |
| } |
| |
| RETURN_IF_ERR(); |
| return retval; |
| } |
| |
| static PyObject* |
| DBC_set_both(DBCursorObject* self, PyObject* args) |
| { |
| int flags=0; |
| PyObject *keyobj, *dataobj; |
| |
| if (!PyArg_ParseTuple(args, "OO|i:set_both", &keyobj, &dataobj, &flags)) |
| return NULL; |
| |
| /* if the cursor is closed, self->mydb may be invalid */ |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| return _DBC_get_set_both(self, keyobj, dataobj, flags, |
| self->mydb->moduleFlags.cursorSetReturnsNone); |
| } |
| |
| |
| static PyObject* |
| DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| int err, irecno, flags=0; |
| db_recno_t recno; |
| DBT key, data; |
| PyObject* retval; |
| int dlen = -1; |
| int doff = -1; |
| static char* kwnames[] = { "recno","flags", "dlen", "doff", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iii:set_recno", kwnames, |
| &irecno, &flags, &dlen, &doff)) |
| return NULL; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| CLEAR_DBT(key); |
| recno = (db_recno_t) irecno; |
| /* use allocated space so DB will be able to realloc room for the real |
| * key */ |
| key.data = malloc(sizeof(db_recno_t)); |
| if (key.data == NULL) { |
| PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed"); |
| return NULL; |
| } |
| key.size = sizeof(db_recno_t); |
| key.ulen = key.size; |
| memcpy(key.data, &recno, sizeof(db_recno_t)); |
| key.flags = DB_DBT_REALLOC; |
| |
| CLEAR_DBT(data); |
| if (!add_partial_dbt(&data, dlen, doff)) { |
| FREE_DBT(key); |
| return NULL; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| 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) { |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (makeDBError(err)) { |
| retval = NULL; |
| } |
| else { /* Can only be used for BTrees, so no need to return int key */ |
| retval = BuildValue_SS(key.data, key.size, data.data, data.size); |
| } |
| FREE_DBT(key); |
| |
| return retval; |
| } |
| |
| |
| static PyObject* |
| DBC_consume(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| return _DBCursor_get(self,DB_CONSUME,args,kwargs,"|iii:consume"); |
| } |
| |
| |
| static PyObject* |
| DBC_next_dup(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| return _DBCursor_get(self,DB_NEXT_DUP,args,kwargs,"|iii:next_dup"); |
| } |
| |
| |
| static PyObject* |
| DBC_next_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| return _DBCursor_get(self,DB_NEXT_NODUP,args,kwargs,"|iii:next_nodup"); |
| } |
| |
| |
| static PyObject* |
| DBC_prev_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs) |
| { |
| return _DBCursor_get(self,DB_PREV_NODUP,args,kwargs,"|iii:prev_nodup"); |
| } |
| |
| |
| static PyObject* |
| DBC_join_item(DBCursorObject* self, PyObject* args) |
| { |
| int err, flags=0; |
| DBT key, data; |
| PyObject* retval; |
| |
| if (!PyArg_ParseTuple(args, "|i:join_item", &flags)) |
| return NULL; |
| |
| CHECK_CURSOR_NOT_CLOSED(self); |
| |
| CLEAR_DBT(key); |
| CLEAR_DBT(data); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| 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) { |
| Py_INCREF(Py_None); |
| retval = Py_None; |
| } |
| else if (makeDBError(err)) { |
| retval = NULL; |
| } |
| else { |
| retval = BuildValue_S(key.data, key.size); |
| } |
| |
| return retval; |
| } |
| |
| |
| |
| /* --------------------------------------------------------------------- */ |
| /* DBEnv methods */ |
| |
| |
| static PyObject* |
| DBEnv_close_internal(DBEnvObject* self, int flags) |
| { |
| PyObject *dummy; |
| int err; |
| |
| 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, 0); |
| Py_XDECREF(dummy); |
| } |
| } |
| |
| self->closed = 1; |
| if (self->db_env) { |
| 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 (Berkeley DB docs). */ |
| self->db_env = NULL; |
| RETURN_IF_ERR(); |
| } |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| 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; |
| |
| if (!PyArg_ParseTuple(args, "z|ii:open", &db_home, &flags, &mode)) |
| return NULL; |
| |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->open(self->db_env, db_home, flags, mode); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| self->closed = 0; |
| self->flags = flags; |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_remove(DBEnvObject* self, PyObject* args) |
| { |
| int err, flags=0; |
| char *db_home; |
| |
| if (!PyArg_ParseTuple(args, "s|i:remove", &db_home, &flags)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->remove(self->db_env, db_home, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| #if (DBVER >= 41) |
| static PyObject* |
| DBEnv_dbremove(DBEnvObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err; |
| u_int32_t flags=0; |
| char *file = NULL; |
| char *database = NULL; |
| PyObject *txnobj = NULL; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "file", "database", "txn", "flags", |
| NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zOi:dbremove", kwnames, |
| &file, &database, &txnobj, &flags)) { |
| return NULL; |
| } |
| if (!checkTxnObj(txnobj, &txn)) { |
| return NULL; |
| } |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->dbremove(self->db_env, txn, file, database, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBEnv_dbrename(DBEnvObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err; |
| u_int32_t flags=0; |
| char *file = NULL; |
| char *database = NULL; |
| char *newname = NULL; |
| PyObject *txnobj = NULL; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "file", "database", "newname", "txn", |
| "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "szs|Oi:dbrename", kwnames, |
| &file, &database, &newname, &txnobj, &flags)) { |
| return NULL; |
| } |
| if (!checkTxnObj(txnobj, &txn)) { |
| return NULL; |
| } |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->dbrename(self->db_env, txn, file, database, newname, |
| flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBEnv_set_encrypt(DBEnvObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err; |
| u_int32_t flags=0; |
| char *passwd = NULL; |
| static char* kwnames[] = { "passwd", "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames, |
| &passwd, &flags)) { |
| return NULL; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_encrypt(self->db_env, passwd, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| #endif /* DBVER >= 41 */ |
| |
| static PyObject* |
| DBEnv_set_timeout(DBEnvObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err; |
| u_int32_t flags=0; |
| u_int32_t timeout = 0; |
| static char* kwnames[] = { "timeout", "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames, |
| &timeout, &flags)) { |
| return NULL; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_timeout(self->db_env, (db_timeout_t)timeout, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBEnv_set_shm_key(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| long shm_key = 0; |
| |
| if (!PyArg_ParseTuple(args, "l:set_shm_key", &shm_key)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| err = self->db_env->set_shm_key(self->db_env, shm_key); |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBEnv_set_cachesize(DBEnvObject* self, PyObject* args) |
| { |
| int err, gbytes=0, bytes=0, ncache=0; |
| |
| if (!PyArg_ParseTuple(args, "ii|i:set_cachesize", |
| &gbytes, &bytes, &ncache)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_cachesize(self->db_env, gbytes, bytes, ncache); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_flags(DBEnvObject* self, PyObject* args) |
| { |
| int err, flags=0, onoff=0; |
| |
| if (!PyArg_ParseTuple(args, "ii:set_flags", |
| &flags, &onoff)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_flags(self->db_env, flags, onoff); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| #if (DBVER >= 47) |
| static PyObject* |
| DBEnv_log_set_config(DBEnvObject* self, PyObject* args) |
| { |
| int err, flags, onoff; |
| |
| if (!PyArg_ParseTuple(args, "ii:log_set_config", |
| &flags, &onoff)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->log_set_config(self->db_env, flags, onoff); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| #endif /* DBVER >= 47 */ |
| |
| |
| static PyObject* |
| DBEnv_set_data_dir(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| char *dir; |
| |
| if (!PyArg_ParseTuple(args, "s:set_data_dir", &dir)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_data_dir(self->db_env, dir); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_lg_bsize(DBEnvObject* self, PyObject* args) |
| { |
| int err, lg_bsize; |
| |
| if (!PyArg_ParseTuple(args, "i:set_lg_bsize", &lg_bsize)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_lg_bsize(self->db_env, lg_bsize); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_lg_dir(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| char *dir; |
| |
| if (!PyArg_ParseTuple(args, "s:set_lg_dir", &dir)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_lg_dir(self->db_env, dir); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBEnv_set_lg_max(DBEnvObject* self, PyObject* args) |
| { |
| int err, lg_max; |
| |
| if (!PyArg_ParseTuple(args, "i:set_lg_max", &lg_max)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_lg_max(self->db_env, lg_max); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| #if (DBVER >= 42) |
| static PyObject* |
| DBEnv_get_lg_max(DBEnvObject* self) |
| { |
| int err; |
| u_int32_t lg_max; |
| |
| 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 NUMBER_FromLong(lg_max); |
| } |
| #endif |
| |
| |
| static PyObject* |
| DBEnv_set_lg_regionmax(DBEnvObject* self, PyObject* args) |
| { |
| int err, lg_max; |
| |
| if (!PyArg_ParseTuple(args, "i:set_lg_regionmax", &lg_max)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_lg_regionmax(self->db_env, lg_max); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_lk_detect(DBEnvObject* self, PyObject* args) |
| { |
| int err, lk_detect; |
| |
| if (!PyArg_ParseTuple(args, "i:set_lk_detect", &lk_detect)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_lk_detect(self->db_env, lk_detect); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| #if (DBVER < 45) |
| static PyObject* |
| DBEnv_set_lk_max(DBEnvObject* self, PyObject* args) |
| { |
| int err, max; |
| |
| if (!PyArg_ParseTuple(args, "i:set_lk_max", &max)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_lk_max(self->db_env, max); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| #endif |
| |
| |
| |
| static PyObject* |
| DBEnv_set_lk_max_locks(DBEnvObject* self, PyObject* args) |
| { |
| int err, max; |
| |
| if (!PyArg_ParseTuple(args, "i:set_lk_max_locks", &max)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_lk_max_locks(self->db_env, max); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_lk_max_lockers(DBEnvObject* self, PyObject* args) |
| { |
| int err, max; |
| |
| if (!PyArg_ParseTuple(args, "i:set_lk_max_lockers", &max)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_lk_max_lockers(self->db_env, max); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_lk_max_objects(DBEnvObject* self, PyObject* args) |
| { |
| int err, max; |
| |
| if (!PyArg_ParseTuple(args, "i:set_lk_max_objects", &max)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_lk_max_objects(self->db_env, max); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_mp_mmapsize(DBEnvObject* self, PyObject* args) |
| { |
| int err, mp_mmapsize; |
| |
| if (!PyArg_ParseTuple(args, "i:set_mp_mmapsize", &mp_mmapsize)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_mp_mmapsize(self->db_env, mp_mmapsize); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_tmp_dir(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| char *dir; |
| |
| if (!PyArg_ParseTuple(args, "s:set_tmp_dir", &dir)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_tmp_dir(self->db_env, dir); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_txn_recover(DBEnvObject* self) |
| { |
| int flags = DB_FIRST; |
| int err, i; |
| PyObject *list, *tuple, *gid; |
| DBTxnObject *txn; |
| #define PREPLIST_LEN 16 |
| DB_PREPLIST preplist[PREPLIST_LEN]; |
| long retp; |
| |
| 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=PyBytes_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; |
| } |
| |
| static PyObject* |
| DBEnv_txn_begin(DBEnvObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int flags = 0; |
| PyObject* txnobj = NULL; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = { "parent", "flags", NULL }; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:txn_begin", kwnames, |
| &txnobj, &flags)) |
| return NULL; |
| |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| return (PyObject*)newDBTxnObject(self, (DBTxnObject *)txnobj, NULL, flags); |
| } |
| |
| |
| static PyObject* |
| DBEnv_txn_checkpoint(DBEnvObject* self, PyObject* args) |
| { |
| int err, kbyte=0, min=0, flags=0; |
| |
| if (!PyArg_ParseTuple(args, "|iii:txn_checkpoint", &kbyte, &min, &flags)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->txn_checkpoint(self->db_env, kbyte, min, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_tx_max(DBEnvObject* self, PyObject* args) |
| { |
| int err, max; |
| |
| if (!PyArg_ParseTuple(args, "i:set_tx_max", &max)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| err = self->db_env->set_tx_max(self->db_env, max); |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_tx_timestamp(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| long stamp; |
| time_t timestamp; |
| |
| if (!PyArg_ParseTuple(args, "l:set_tx_timestamp", &stamp)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| timestamp = (time_t)stamp; |
| err = self->db_env->set_tx_timestamp(self->db_env, ×tamp); |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_lock_detect(DBEnvObject* self, PyObject* args) |
| { |
| int err, atype, flags=0; |
| int aborted = 0; |
| |
| if (!PyArg_ParseTuple(args, "i|i:lock_detect", &atype, &flags)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->lock_detect(self->db_env, flags, atype, &aborted); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| return NUMBER_FromLong(aborted); |
| } |
| |
| |
| static PyObject* |
| DBEnv_lock_get(DBEnvObject* self, PyObject* args) |
| { |
| int flags=0; |
| int locker, lock_mode; |
| DBT obj; |
| PyObject* objobj; |
| |
| if (!PyArg_ParseTuple(args, "iOi|i:lock_get", &locker, &objobj, &lock_mode, &flags)) |
| return NULL; |
| |
| |
| if (!make_dbt(objobj, &obj)) |
| return NULL; |
| |
| return (PyObject*)newDBLockObject(self, locker, &obj, lock_mode, flags); |
| } |
| |
| |
| static PyObject* |
| DBEnv_lock_id(DBEnvObject* self) |
| { |
| int err; |
| u_int32_t theID; |
| |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->lock_id(self->db_env, &theID); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| return NUMBER_FromLong((long)theID); |
| } |
| |
| static PyObject* |
| DBEnv_lock_id_free(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| u_int32_t theID; |
| |
| if (!PyArg_ParseTuple(args, "I:lock_id_free", &theID)) |
| return NULL; |
| |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->lock_id_free(self->db_env, theID); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBEnv_lock_put(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| DBLockObject* dblockobj; |
| |
| if (!PyArg_ParseTuple(args, "O!:lock_put", &DBLock_Type, &dblockobj)) |
| return NULL; |
| |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->lock_put(self->db_env, &dblockobj->lock); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| #if (DBVER >= 44) |
| static PyObject* |
| DBEnv_lsn_reset(DBEnvObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err; |
| char *file; |
| u_int32_t flags = 0; |
| static char* kwnames[] = { "file", "flags", NULL}; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|i:lsn_reset", kwnames, |
| &file, &flags)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->lsn_reset(self->db_env, file, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| #endif /* DBVER >= 4.4 */ |
| |
| static PyObject* |
| DBEnv_log_stat(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| DB_LOG_STAT* statp = NULL; |
| PyObject* d = NULL; |
| u_int32_t flags = 0; |
| |
| if (!PyArg_ParseTuple(args, "|i:log_stat", &flags)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->log_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) { |
| if (statp) |
| free(statp); |
| return NULL; |
| } |
| |
| #define MAKE_ENTRY(name) _addIntToDict(d, #name, statp->st_##name) |
| |
| MAKE_ENTRY(magic); |
| MAKE_ENTRY(version); |
| MAKE_ENTRY(mode); |
| MAKE_ENTRY(lg_bsize); |
| #if (DBVER >= 44) |
| MAKE_ENTRY(lg_size); |
| MAKE_ENTRY(record); |
| #endif |
| #if (DBVER < 41) |
| MAKE_ENTRY(lg_max); |
| #endif |
| MAKE_ENTRY(w_mbytes); |
| MAKE_ENTRY(w_bytes); |
| MAKE_ENTRY(wc_mbytes); |
| MAKE_ENTRY(wc_bytes); |
| MAKE_ENTRY(wcount); |
| MAKE_ENTRY(wcount_fill); |
| #if (DBVER >= 44) |
| MAKE_ENTRY(rcount); |
| #endif |
| MAKE_ENTRY(scount); |
| MAKE_ENTRY(cur_file); |
| MAKE_ENTRY(cur_offset); |
| MAKE_ENTRY(disk_file); |
| MAKE_ENTRY(disk_offset); |
| MAKE_ENTRY(maxcommitperflush); |
| MAKE_ENTRY(mincommitperflush); |
| MAKE_ENTRY(regsize); |
| MAKE_ENTRY(region_wait); |
| MAKE_ENTRY(region_nowait); |
| |
| #undef MAKE_ENTRY |
| free(statp); |
| return d; |
| } /* DBEnv_log_stat */ |
| |
| |
| static PyObject* |
| DBEnv_lock_stat(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| DB_LOCK_STAT* sp; |
| PyObject* d = NULL; |
| u_int32_t flags = 0; |
| |
| if (!PyArg_ParseTuple(args, "|i:lock_stat", &flags)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->lock_stat(self->db_env, &sp, flags); |
| 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) |
| |
| #if (DBVER < 41) |
| MAKE_ENTRY(lastid); |
| #endif |
| #if (DBVER >=41) |
| MAKE_ENTRY(id); |
| MAKE_ENTRY(cur_maxid); |
| #endif |
| MAKE_ENTRY(nmodes); |
| MAKE_ENTRY(maxlocks); |
| MAKE_ENTRY(maxlockers); |
| MAKE_ENTRY(maxobjects); |
| MAKE_ENTRY(nlocks); |
| MAKE_ENTRY(maxnlocks); |
| MAKE_ENTRY(nlockers); |
| MAKE_ENTRY(maxnlockers); |
| MAKE_ENTRY(nobjects); |
| 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); |
| #else |
| MAKE_ENTRY(lock_nowait); |
| MAKE_ENTRY(lock_wait); |
| #endif |
| MAKE_ENTRY(ndeadlocks); |
| #if (DBVER >= 41) |
| MAKE_ENTRY(locktimeout); |
| MAKE_ENTRY(txntimeout); |
| #endif |
| MAKE_ENTRY(nlocktimeouts); |
| MAKE_ENTRY(ntxntimeouts); |
| #if (DBVER >= 46) |
| MAKE_ENTRY(objs_wait); |
| MAKE_ENTRY(objs_nowait); |
| MAKE_ENTRY(lockers_wait); |
| MAKE_ENTRY(lockers_nowait); |
| #if (DBVER >= 47) |
| MAKE_ENTRY(lock_wait); |
| MAKE_ENTRY(lock_nowait); |
| #else |
| MAKE_ENTRY(locks_wait); |
| MAKE_ENTRY(locks_nowait); |
| #endif |
| MAKE_ENTRY(hash_len); |
| #endif |
| MAKE_ENTRY(regsize); |
| MAKE_ENTRY(region_wait); |
| MAKE_ENTRY(region_nowait); |
| |
| #undef MAKE_ENTRY |
| free(sp); |
| return d; |
| } |
| |
| static PyObject* |
| DBEnv_log_flush(DBEnvObject* self) |
| { |
| int err; |
| |
| 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(); |
| } |
| |
| static PyObject* |
| DBEnv_log_archive(DBEnvObject* self, PyObject* args) |
| { |
| int flags=0; |
| int err; |
| char **log_list = NULL; |
| PyObject* list; |
| PyObject* item = NULL; |
| |
| if (!PyArg_ParseTuple(args, "|i:log_archive", &flags)) |
| return NULL; |
| |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->log_archive(self->db_env, &log_list, flags); |
| 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 = PyBytes_FromString (*log_list); |
| if (item == NULL) { |
| Py_DECREF(list); |
| list = NULL; |
| break; |
| } |
| if (PyList_Append(list, item)) { |
| Py_DECREF(list); |
| list = NULL; |
| Py_DECREF(item); |
| break; |
| } |
| 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; |
| err = self->db_env->txn_stat(self->db_env, &sp, flags); |
| 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) |
| |
| MAKE_DB_LSN_ENTRY(last_ckp); |
| 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); |
| MAKE_ENTRY(nrestores); |
| 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 NUMBER_FromLong(oldValue); |
| } |
| |
| static PyObject* |
| DBEnv_get_private(DBEnvObject* self) |
| { |
| /* We can give out the private field even if dbenv is closed */ |
| Py_INCREF(self->private_obj); |
| return self->private_obj; |
| } |
| |
| static PyObject* |
| DBEnv_set_private(DBEnvObject* self, PyObject* private_obj) |
| { |
| /* We can set the private field even if dbenv is closed */ |
| Py_DECREF(self->private_obj); |
| Py_INCREF(private_obj); |
| self->private_obj = private_obj; |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBEnv_set_rpc_server(DBEnvObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err; |
| char *host; |
| long cl_timeout=0, sv_timeout=0; |
| |
| static char* kwnames[] = { "host", "cl_timeout", "sv_timeout", NULL}; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ll:set_rpc_server", kwnames, |
| &host, &cl_timeout, &sv_timeout)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->set_rpc_server(self->db_env, NULL, host, cl_timeout, |
| sv_timeout, 0); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| 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 |
| |
| #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* notifyFunc) |
| { |
| int err; |
| |
| 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; |
| |
| /* This is to workaround a problem with un-initialized threads (see |
| comment in DB_associate) */ |
| #ifdef WITH_THREAD |
| PyEval_InitThreads(); |
| #endif |
| |
| 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 */ |
| |
| |
| static PyObject* |
| DBEnv_rep_process_message(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| PyObject *control_py, *rec_py; |
| DBT control, rec; |
| int envid; |
| #if (DBVER >= 42) |
| DB_LSN lsn; |
| #endif |
| |
| if (!PyArg_ParseTuple(args, "OOi:rep_process_message", &control_py, |
| &rec_py, &envid)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| if (!make_dbt(control_py, &control)) |
| return NULL; |
| if (!make_dbt(rec_py, &rec)) |
| return NULL; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| #if (DBVER >= 46) |
| err = self->db_env->rep_process_message(self->db_env, &control, &rec, |
| envid, &lsn); |
| #else |
| #if (DBVER >= 42) |
| err = self->db_env->rep_process_message(self->db_env, &control, &rec, |
| &envid, &lsn); |
| #else |
| err = self->db_env->rep_process_message(self->db_env, &control, &rec, |
| &envid); |
| #endif |
| #endif |
| MYDB_END_ALLOW_THREADS; |
| switch (err) { |
| case DB_REP_NEWMASTER : |
| return Py_BuildValue("(iO)", envid, Py_None); |
| break; |
| |
| case DB_REP_DUPMASTER : |
| case DB_REP_HOLDELECTION : |
| #if (DBVER >= 44) |
| case DB_REP_IGNORE : |
| case DB_REP_JOIN_FAILURE : |
| #endif |
| return Py_BuildValue("(iO)", err, Py_None); |
| break; |
| case DB_REP_NEWSITE : |
| { |
| PyObject *tmp, *r; |
| |
| if (!(tmp = PyBytes_FromStringAndSize(rec.data, rec.size))) { |
| return NULL; |
| } |
| |
| r = Py_BuildValue("(iO)", err, tmp); |
| Py_DECREF(tmp); |
| return r; |
| break; |
| } |
| #if (DBVER >= 42) |
| case DB_REP_NOTPERM : |
| case DB_REP_ISPERM : |
| return Py_BuildValue("(i(ll))", err, lsn.file, lsn.offset); |
| break; |
| #endif |
| } |
| RETURN_IF_ERR(); |
| return Py_BuildValue("(OO)", Py_None, Py_None); |
| } |
| |
| static int |
| _DBEnv_rep_transportCallback(DB_ENV* db_env, const DBT* control, const DBT* rec, |
| const DB_LSN *lsn, int envid, u_int32_t flags) |
| { |
| DBEnvObject *dbenv; |
| PyObject* rep_transport; |
| PyObject* args; |
| PyObject *a, *b; |
| PyObject* result = NULL; |
| int ret=0; |
| |
| MYDB_BEGIN_BLOCK_THREADS; |
| dbenv = (DBEnvObject *)db_env->app_private; |
| rep_transport = dbenv->rep_transport; |
| |
| /* |
| ** The errors in 'a' or 'b' are detected in "Py_BuildValue". |
| */ |
| a = PyBytes_FromStringAndSize(control->data, control->size); |
| b = PyBytes_FromStringAndSize(rec->data, rec->size); |
| |
| args = Py_BuildValue( |
| #if (PY_VERSION_HEX >= 0x02040000) |
| "(OOO(ll)iI)", |
| #else |
| "(OOO(ll)ii)", |
| #endif |
| dbenv, |
| a, b, |
| lsn->file, lsn->offset, envid, flags); |
| if (args) { |
| result = PyEval_CallObject(rep_transport, args); |
| } |
| |
| if ((!args) || (!result)) { |
| PyErr_Print(); |
| ret = -1; |
| } |
| Py_XDECREF(a); |
| Py_XDECREF(b); |
| Py_XDECREF(args); |
| Py_XDECREF(result); |
| MYDB_END_BLOCK_THREADS; |
| return ret; |
| } |
| |
| #if (DBVER <= 41) |
| static int |
| _DBEnv_rep_transportCallbackOLD(DB_ENV* db_env, const DBT* control, const DBT* rec, |
| int envid, u_int32_t flags) |
| { |
| DB_LSN lsn; |
| |
| lsn.file = -1; /* Dummy values */ |
| lsn.offset = -1; |
| return _DBEnv_rep_transportCallback(db_env, control, rec, &lsn, envid, |
| flags); |
| } |
| #endif |
| |
| static PyObject* |
| DBEnv_rep_set_transport(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| int envid; |
| PyObject *rep_transport; |
| |
| if (!PyArg_ParseTuple(args, "iO:rep_set_transport", &envid, &rep_transport)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| if (!PyCallable_Check(rep_transport)) { |
| makeTypeError("Callable", rep_transport); |
| return NULL; |
| } |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| #if (DBVER >=45) |
| err = self->db_env->rep_set_transport(self->db_env, envid, |
| &_DBEnv_rep_transportCallback); |
| #else |
| #if (DBVER >= 42) |
| err = self->db_env->set_rep_transport(self->db_env, envid, |
| &_DBEnv_rep_transportCallback); |
| #else |
| err = self->db_env->set_rep_transport(self->db_env, envid, |
| &_DBEnv_rep_transportCallbackOLD); |
| #endif |
| #endif |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| Py_DECREF(self->rep_transport); |
| Py_INCREF(rep_transport); |
| self->rep_transport = rep_transport; |
| RETURN_NONE(); |
| } |
| |
| #if (DBVER >= 47) |
| static PyObject* |
| DBEnv_rep_set_request(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| unsigned int minimum, maximum; |
| |
| if (!PyArg_ParseTuple(args,"II:rep_set_request", &minimum, &maximum)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->rep_set_request(self->db_env, minimum, maximum); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBEnv_rep_get_request(DBEnvObject* self) |
| { |
| int err; |
| u_int32_t minimum, maximum; |
| |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->rep_get_request(self->db_env, &minimum, &maximum); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| #if (PY_VERSION_HEX >= 0x02040000) |
| return Py_BuildValue("II", minimum, maximum); |
| #else |
| return Py_BuildValue("ii", minimum, maximum); |
| #endif |
| } |
| #endif |
| |
| #if (DBVER >= 45) |
| static PyObject* |
| DBEnv_rep_set_limit(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| int limit; |
| |
| if (!PyArg_ParseTuple(args,"i:rep_set_limit", &limit)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->rep_set_limit(self->db_env, 0, limit); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBEnv_rep_get_limit(DBEnvObject* self) |
| { |
| int err; |
| u_int32_t gbytes, bytes; |
| |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->rep_get_limit(self->db_env, &gbytes, &bytes); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| return NUMBER_FromLong(bytes); |
| } |
| #endif |
| |
| #if (DBVER >= 44) |
| static PyObject* |
| DBEnv_rep_set_config(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| int which; |
| int onoff; |
| |
| if (!PyArg_ParseTuple(args,"ii:rep_set_config", &which, &onoff)) |
| return NULL; |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->rep_set_config(self->db_env, which, onoff); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBEnv_rep_get_config(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| int which; |
| int onoff; |
| |
| if (!PyArg_ParseTuple(args, "i:rep_get_config", &which)) { |
| return NULL; |
| } |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->rep_get_config(self->db_env, which, &onoff); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| return PyBool_FromLong(onoff); |
| } |
| #endif |
| |
| #if (DBVER >= 46) |
| static PyObject* |
| DBEnv_rep_elect(DBEnvObject* self, PyObject* args) |
| { |
| int err; |
| u_int32_t nsites, nvotes; |
| |
| if (!PyArg_ParseTuple(args, "II:rep_elect", &nsites, &nvotes)) { |
| return NULL; |
| } |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->rep_elect(self->db_env, nvotes, nvotes, 0); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| #endif |
| |
| static PyObject* |
| DBEnv_rep_start(DBEnvObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err; |
| PyObject *cdata_py = Py_None; |
| DBT cdata; |
| int flags; |
| static char* kwnames[] = {"flags","cdata", NULL}; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, |
| "i|O:rep_start", kwnames, &flags, &cdata_py)) |
| { |
| return NULL; |
| } |
| CHECK_ENV_NOT_CLOSED(self); |
| |
| if (!make_dbt(cdata_py, &cdata)) |
| return NULL; |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->rep_start(self->db_env, cdata.size ? &cdata : NULL, |
| flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| #if (DBVER >= 44) |
| static PyObject* |
| DBEnv_rep_sync(DBEnvObject* self) |
| { |
| int err; |
| |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->rep_sync(self->db_env, 0); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| #endif |
| |
| |
| #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) |
| { |
| int err; |
| #if (DBVER >= 47) |
| u_int32_t nsites; |
| #else |
| int nsites; |
| #endif |
| |
| 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 NUMBER_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) |
| { |
| int err; |
| #if (DBVER >= 47) |
| u_int32_t priority; |
| #else |
| int priority; |
| #endif |
| |
| 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 NUMBER_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 NUMBER_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 NUMBER_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) |
| { |
| int err; |
| int ack_policy; |
| |
| 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 NUMBER_FromLong(ack_policy); |
| } |
| |
| static PyObject* |
| DBEnv_repmgr_site_list(DBEnvObject* self) |
| { |
| int err; |
| unsigned int countp; |
| DB_REPMGR_SITE *listp; |
| PyObject *stats, *key, *tuple; |
| |
| CHECK_ENV_NOT_CLOSED(self); |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->db_env->repmgr_site_list(self->db_env, &countp, &listp); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| stats=PyDict_New(); |
| if (stats == NULL) { |
| free(listp); |
| return NULL; |
| } |
| |
| for(;countp--;) { |
| key=NUMBER_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(listp); |
| return stats; |
| } |
| #endif |
| |
| #if (DBVER >= 46) |
| static PyObject* |
| DBEnv_repmgr_stat_print(DBEnvObject* self, PyObject* args, PyObject *kwargs) |
| { |
| int err; |
| int flags=0; |
| static char* kwnames[] = { "flags", NULL }; |
| |
| 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; |
| err = self->db_env->repmgr_stat(self->db_env, &statp, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| stats=PyDict_New(); |
| if (stats == NULL) { |
| free(statp); |
| return NULL; |
| } |
| |
| #define MAKE_ENTRY(name) _addIntToDict(stats, #name, statp->st_##name) |
| |
| MAKE_ENTRY(perm_failed); |
| MAKE_ENTRY(msgs_queued); |
| MAKE_ENTRY(msgs_dropped); |
| MAKE_ENTRY(connection_drop); |
| MAKE_ENTRY(connect_fail); |
| |
| #undef MAKE_ENTRY |
| |
| free(statp); |
| return stats; |
| } |
| #endif |
| |
| |
| /* --------------------------------------------------------------------- */ |
| /* DBTxn methods */ |
| |
| |
| 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 |
| |
| 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* |
| DBTxn_commit(DBTxnObject* self, PyObject* args) |
| { |
| int flags=0, err; |
| DB_TXN *txn; |
| |
| 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, txn_abort " |
| "or txn_discard"); |
| if (t) { |
| 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; |
| err = txn->commit(txn, flags); |
| MYDB_END_ALLOW_THREADS; |
| |
| _promote_transaction_dbs_and_sequences(self); |
| |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBTxn_prepare(DBTxnObject* self, PyObject* args) |
| { |
| int err; |
| char* gid=NULL; |
| int gid_size=0; |
| |
| if (!PyArg_ParseTuple(args, "s#:prepare", &gid, &gid_size)) |
| return NULL; |
| |
| if (gid_size != DB_XIDDATASIZE) { |
| PyErr_SetString(PyExc_TypeError, |
| "gid must be DB_XIDDATASIZE bytes long"); |
| return NULL; |
| } |
| |
| if (!self->txn) { |
| PyObject *t = Py_BuildValue("(is)", 0,"DBTxn must not be used " |
| "after txn_commit, txn_abort " |
| "or txn_discard"); |
| if (t) { |
| PyErr_SetObject(DBError, t); |
| Py_DECREF(t); |
| } |
| return NULL; |
| } |
| self->flag_prepare=1; /* Prepare state */ |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->txn->prepare(self->txn, (u_int8_t*)gid); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| |
| static PyObject* |
| DBTxn_abort_discard_internal(DBTxnObject* self, int discard) |
| { |
| PyObject *dummy; |
| int err=0; |
| DB_TXN *txn; |
| |
| if (!self->txn) { |
| PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used " |
| "after txn_commit, txn_abort " |
| "or txn_discard"); |
| if (t) { |
| 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, 0); |
| Py_XDECREF(dummy); |
| } |
| |
| EXTRACT_FROM_DOUBLE_LINKED_LIST(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| if (discard) { |
| assert(!self->flag_prepare); |
| err = txn->discard(txn,0); |
| } else { |
| /* |
| ** If the transaction is in the "prepare" or "recover" state, |
| ** we better do not implicitly abort it. |
| */ |
| if (!self->flag_prepare) { |
| err = txn->abort(txn); |
| } |
| } |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBTxn_abort(DBTxnObject* self) |
| { |
| self->flag_prepare=0; |
| _close_transaction_cursors(self); |
| |
| return DBTxn_abort_discard_internal(self,0); |
| } |
| |
| static PyObject* |
| DBTxn_discard(DBTxnObject* self) |
| { |
| self->flag_prepare=0; |
| _close_transaction_cursors(self); |
| |
| return DBTxn_abort_discard_internal(self,1); |
| } |
| |
| |
| static PyObject* |
| DBTxn_id(DBTxnObject* self) |
| { |
| int id; |
| |
| if (!self->txn) { |
| PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used " |
| "after txn_commit, txn_abort " |
| "or txn_discard"); |
| if (t) { |
| PyErr_SetObject(DBError, t); |
| Py_DECREF(t); |
| } |
| return NULL; |
| } |
| MYDB_BEGIN_ALLOW_THREADS; |
| id = self->txn->id(self->txn); |
| MYDB_END_ALLOW_THREADS; |
| return NUMBER_FromLong(id); |
| } |
| |
| #if (DBVER >= 43) |
| /* --------------------------------------------------------------------- */ |
| /* DBSequence methods */ |
| |
| |
| static PyObject* |
| DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close) |
| { |
| int err=0; |
| |
| if (self->sequence!=NULL) { |
| EXTRACT_FROM_DOUBLE_LINKED_LIST(self); |
| if (self->txn) { |
| EXTRACT_FROM_DOUBLE_LINKED_LIST_TXN(self); |
| self->txn=NULL; |
| } |
| |
| /* |
| ** "do_not_close" is used to dispose all related objects in the |
| ** tree, without actually releasing the "root" object. |
| ** This is done, for example, because function calls like |
| ** "DBSequence.remove()" implicitly close the underlying handle. So |
| ** the handle doesn't need to be closed, but related objects |
| ** must be cleaned up. |
| */ |
| 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) |
| { |
| int err, flags = 0; |
| int delta = 1; |
| db_seq_t value; |
| PyObject *txnobj = NULL; |
| DB_TXN *txn = NULL; |
| static char* kwnames[] = {"delta", "txn", "flags", NULL }; |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iOi:get", kwnames, &delta, &txnobj, &flags)) |
| return NULL; |
| CHECK_SEQUENCE_NOT_CLOSED(self) |
| |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| |
| MYDB_BEGIN_ALLOW_THREADS |
| err = self->sequence->get(self->sequence, txn, delta, &value, flags); |
| MYDB_END_ALLOW_THREADS |
| |
| RETURN_IF_ERR(); |
| return PyLong_FromLongLong(value); |
| } |
| |
| static PyObject* |
| DBSequence_get_dbp(DBSequenceObject* self) |
| { |
| CHECK_SEQUENCE_NOT_CLOSED(self) |
| Py_INCREF(self->mydb); |
| return (PyObject* )self->mydb; |
| } |
| |
| static PyObject* |
| DBSequence_get_key(DBSequenceObject* self) |
| { |
| int err; |
| DBT key; |
| PyObject *retval = NULL; |
| |
| key.flags = DB_DBT_MALLOC; |
| CHECK_SEQUENCE_NOT_CLOSED(self) |
| MYDB_BEGIN_ALLOW_THREADS |
| err = self->sequence->get_key(self->sequence, &key); |
| MYDB_END_ALLOW_THREADS |
| |
| if (!err) |
| retval = Build_PyString(key.data, key.size); |
| |
| FREE_DBT(key); |
| RETURN_IF_ERR(); |
| |
| return retval; |
| } |
| |
| static PyObject* |
| DBSequence_init_value(DBSequenceObject* self, PyObject* args) |
| { |
| int err; |
| 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, value2); |
| MYDB_END_ALLOW_THREADS |
| |
| RETURN_IF_ERR(); |
| |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBSequence_open(DBSequenceObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags = 0; |
| PyObject* keyobj; |
| PyObject *txnobj = NULL; |
| DB_TXN *txn = NULL; |
| DBT key; |
| |
| static char* kwnames[] = {"key", "txn", "flags", NULL }; |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:open", kwnames, &keyobj, &txnobj, &flags)) |
| return NULL; |
| |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| |
| if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) |
| return NULL; |
| |
| MYDB_BEGIN_ALLOW_THREADS |
| err = self->sequence->open(self->sequence, txn, &key, flags); |
| MYDB_END_ALLOW_THREADS |
| |
| FREE_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; |
| |
| static char* kwnames[] = {"txn", "flags", NULL }; |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:remove", kwnames, &txnobj, &flags)) |
| return NULL; |
| |
| if (!checkTxnObj(txnobj, &txn)) |
| return NULL; |
| |
| CHECK_SEQUENCE_NOT_CLOSED(self) |
| |
| MYDB_BEGIN_ALLOW_THREADS |
| 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(); |
| } |
| |
| static PyObject* |
| DBSequence_set_cachesize(DBSequenceObject* self, PyObject* args) |
| { |
| int err, size; |
| if (!PyArg_ParseTuple(args,"i:set_cachesize", &size)) |
| return NULL; |
| CHECK_SEQUENCE_NOT_CLOSED(self) |
| |
| MYDB_BEGIN_ALLOW_THREADS |
| err = self->sequence->set_cachesize(self->sequence, size); |
| MYDB_END_ALLOW_THREADS |
| |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBSequence_get_cachesize(DBSequenceObject* self) |
| { |
| int err, size; |
| |
| CHECK_SEQUENCE_NOT_CLOSED(self) |
| |
| MYDB_BEGIN_ALLOW_THREADS |
| err = self->sequence->get_cachesize(self->sequence, &size); |
| MYDB_END_ALLOW_THREADS |
| |
| RETURN_IF_ERR(); |
| return NUMBER_FromLong(size); |
| } |
| |
| static PyObject* |
| DBSequence_set_flags(DBSequenceObject* self, PyObject* args) |
| { |
| int err, flags = 0; |
| if (!PyArg_ParseTuple(args,"i:set_flags", &flags)) |
| return NULL; |
| CHECK_SEQUENCE_NOT_CLOSED(self) |
| |
| MYDB_BEGIN_ALLOW_THREADS |
| err = self->sequence->set_flags(self->sequence, flags); |
| MYDB_END_ALLOW_THREADS |
| |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBSequence_get_flags(DBSequenceObject* self) |
| { |
| unsigned int flags; |
| int err; |
| |
| CHECK_SEQUENCE_NOT_CLOSED(self) |
| |
| MYDB_BEGIN_ALLOW_THREADS |
| err = self->sequence->get_flags(self->sequence, &flags); |
| MYDB_END_ALLOW_THREADS |
| |
| RETURN_IF_ERR(); |
| return NUMBER_FromLong((int)flags); |
| } |
| |
| static PyObject* |
| DBSequence_set_range(DBSequenceObject* self, PyObject* args) |
| { |
| int err; |
| 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, min2, max2); |
| MYDB_END_ALLOW_THREADS |
| |
| RETURN_IF_ERR(); |
| RETURN_NONE(); |
| } |
| |
| static PyObject* |
| DBSequence_get_range(DBSequenceObject* self) |
| { |
| int err; |
| PY_LONG_LONG min, max; |
| db_seq_t min2, max2; |
| |
| CHECK_SEQUENCE_NOT_CLOSED(self) |
| |
| MYDB_BEGIN_ALLOW_THREADS |
| 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); |
| } |
| |
| static PyObject* |
| DBSequence_stat(DBSequenceObject* self, PyObject* args, PyObject* kwargs) |
| { |
| int err, flags = 0; |
| DB_SEQUENCE_STAT* sp = NULL; |
| PyObject* dict_stat; |
| static char* kwnames[] = {"flags", NULL }; |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat", kwnames, &flags)) |
| return NULL; |
| CHECK_SEQUENCE_NOT_CLOSED(self); |
| |
| MYDB_BEGIN_ALLOW_THREADS; |
| err = self->sequence->stat(self->sequence, &sp, flags); |
| MYDB_END_ALLOW_THREADS; |
| RETURN_IF_ERR(); |
| |
| if ((dict_stat = PyDict_New()) == NULL) { |
| free(sp); |
| return NULL; |
| } |
| |
| |
| #define MAKE_INT_ENTRY(name) _addIntToDict(dict_stat, #name, sp->st_##name) |
| #define MAKE_LONG_LONG_ENTRY(name) _addDb_seq_tToDict(dict_stat, #name, sp->st_##name) |
| |
| MAKE_INT_ENTRY(wait); |
| MAKE_INT_ENTRY(nowait); |
| MAKE_LONG_LONG_ENTRY(current); |
| MAKE_LONG_LONG_ENTRY(value); |
| MAKE_LONG_LONG_ENTRY(last_value); |
| MAKE_LONG_LONG_ENTRY(min); |
| MAKE_LONG_LONG_ENTRY(max); |
| MAKE_INT_ENTRY(cache_size); |
| MAKE_INT_ENTRY(flags); |
| |
| #undef MAKE_INT_ENTRY |
| #undef MAKE_LONG_LONG_ENTRY |
| |
| free(sp); |
| return dict_stat; |
| } |
| #endif |
| |
| |
| /* --------------------------------------------------------------------- */ |
| /* Method definition tables and type objects */ |
| |
| static PyMethodDef DB_methods[] = { |
| {"append", (PyCFunction)DB_append, METH_VARARGS|METH_KEYWORDS}, |
| {"associate", (PyCFunction)DB_associate, METH_VARARGS|METH_KEYWORDS}, |
| {"close", (PyCFunction)DB_close, METH_VARARGS}, |
| {"consume", (PyCFunction)DB_consume, METH_VARARGS|METH_KEYWORDS}, |
| {"consume_wait", (PyCFunction)DB_consume_wait, METH_VARARGS|METH_KEYWORDS}, |
| {"cursor", (PyCFunction)DB_cursor, METH_VARARGS|METH_KEYWORDS}, |
| {"delete", (PyCFunction)DB_delete, METH_VARARGS|METH_KEYWORDS}, |
| {"fd", (PyCFunction)DB_fd, METH_NOARGS}, |
| {"get", (PyCFunction)DB_get, METH_VARARGS|METH_KEYWORDS}, |
| {"pget", (PyCFunction)DB_pget, METH_VARARGS|METH_KEYWORDS}, |
| {"get_both", (PyCFunction)DB_get_both, METH_VARARGS|METH_KEYWORDS}, |
| {"get_byteswapped", (PyCFunction)DB_get_byteswapped,METH_NOARGS}, |
| {"get_size", (PyCFunction)DB_get_size, METH_VARARGS|METH_KEYWORDS}, |
| {"get_type", (PyCFunction)DB_get_type, METH_NOARGS}, |
| {"join", (PyCFunction)DB_join, METH_VARARGS}, |
| {"key_range", (PyCFunction)DB_key_range, METH_VARARGS|METH_KEYWORDS}, |
| {"has_key", (PyCFunction)DB_has_key, METH_VARARGS|METH_KEYWORDS}, |
| {"items", (PyCFunction)DB_items, METH_VARARGS}, |
| {"keys", (PyCFunction)DB_keys, METH_VARARGS}, |
| {"open", (PyCFunction)DB_open, METH_VARARGS|METH_KEYWORDS}, |
| {"put", (PyCFunction)DB_put, METH_VARARGS|METH_KEYWORDS}, |
| {"remove", (PyCFunction)DB_remove, METH_VARARGS|METH_KEYWORDS}, |
| {"rename", (PyCFunction)DB_rename, METH_VARARGS}, |
| {"set_bt_minkey", (PyCFunction)DB_set_bt_minkey, METH_VARARGS}, |
| {"set_bt_compare", (PyCFunction)DB_set_bt_compare, METH_O}, |
| {"set_cachesize", (PyCFunction)DB_set_cachesize, METH_VARARGS}, |
| #if (DBVER >= 41) |
| {"set_encrypt", (PyCFunction)DB_set_encrypt, METH_VARARGS|METH_KEYWORDS}, |
| #endif |
| {"set_flags", (PyCFunction)DB_set_flags, METH_VARARGS}, |
| {"set_h_ffactor", (PyCFunction)DB_set_h_ffactor, METH_VARARGS}, |
| {"set_h_nelem", (PyCFunction)DB_set_h_nelem, METH_VARARGS}, |
| {"set_lorder", (PyCFunction)DB_set_lorder, METH_VARARGS}, |
| {"set_pagesize", (PyCFunction)DB_set_pagesize, METH_VARARGS}, |
| {"set_re_delim", (PyCFunction)DB_set_re_delim, METH_VARARGS}, |
| {"set_re_len", (PyCFunction)DB_set_re_len, METH_VARARGS}, |
| {"set_re_pad", (PyCFunction)DB_set_re_pad, METH_VARARGS}, |
| {"set_re_source", (PyCFunction)DB_set_re_source, METH_VARARGS}, |
| {"set_q_extentsize",(PyCFunction)DB_set_q_extentsize, METH_VARARGS}, |
| {"set_private", (PyCFunction)DB_set_private, METH_O}, |
| {"get_private", (PyCFunction)DB_get_private, METH_NOARGS}, |
| {"stat", (PyCFunction)DB_stat, METH_VARARGS|METH_KEYWORDS}, |
| {"sync", (PyCFunction)DB_sync, METH_VARARGS}, |
| {"truncate", (PyCFunction)DB_truncate, METH_VARARGS|METH_KEYWORDS}, |
| {"type", (PyCFunction)DB_get_type, METH_NOARGS}, |
| {"upgrade", (PyCFunction)DB_upgrade, METH_VARARGS}, |
| {"values", (PyCFunction)DB_values, METH_VARARGS}, |
| {"verify", (PyCFunction)DB_verify, METH_VARARGS|METH_KEYWORDS}, |
| {"set_get_returns_none",(PyCFunction)DB_set_get_returns_none, METH_VARARGS}, |
| {NULL, NULL} /* sentinel */ |
| }; |
| |
| |
| static PyMappingMethods DB_mapping = { |
| DB_length, /*mp_length*/ |
| (binaryfunc)DB_subscript, /*mp_subscript*/ |
| (objobjargproc)DB_ass_sub, /*mp_ass_subscript*/ |
| }; |
| |
| |
| static PyMethodDef DBCursor_methods[] = { |
| {"close", (PyCFunction)DBC_close, METH_NOARGS}, |
| {"count", (PyCFunction)DBC_count, METH_VARARGS}, |
| {"current", (PyCFunction)DBC_current, METH_VARARGS|METH_KEYWORDS}, |
| {"delete", (PyCFunction)DBC_delete, METH_VARARGS}, |
| {"dup", (PyCFunction)DBC_dup, METH_VARARGS}, |
| {"first", (PyCFunction)DBC_first, METH_VARARGS|METH_KEYWORDS}, |
| {"get", (PyCFunction)DBC_get, METH_VARARGS|METH_KEYWORDS}, |
| {"pget", (PyCFunction)DBC_pget, METH_VARARGS|METH_KEYWORDS}, |
| {"get_recno", (PyCFunction)DBC_get_recno, METH_NOARGS}, |
| {"last", (PyCFunction)DBC_last, METH_VARARGS|METH_KEYWORDS}, |
| {"next", (PyCFunction)DBC_next, METH_VARARGS|METH_KEYWORDS}, |
| {"prev", (PyCFunction)DBC_prev, METH_VARARGS|METH_KEYWORDS}, |
| {"put", (PyCFunction)DBC_put, METH_VARARGS|METH_KEYWORDS}, |
| {"set", (PyCFunction)DBC_set, METH_VARARGS|METH_KEYWORDS}, |
| {"set_range", (PyCFunction)DBC_set_range, METH_VARARGS|METH_KEYWORDS}, |
| {"get_both", (PyCFunction)DBC_get_both, METH_VARARGS}, |
| {"get_current_size",(PyCFunction)DBC_get_current_size, METH_NOARGS}, |
| {"set_both", (PyCFunction)DBC_set_both, METH_VARARGS}, |
| {"set_recno", (PyCFunction)DBC_set_recno, METH_VARARGS|METH_KEYWORDS}, |
| {"consume", (PyCFunction)DBC_consume, METH_VARARGS|METH_KEYWORDS}, |
| {"next_dup", (PyCFunction)DBC_next_dup, METH_VARARGS|METH_KEYWORDS}, |
| {"next_nodup", (PyCFunction)DBC_next_nodup, METH_VARARGS|METH_KEYWORDS}, |
| {"prev_nodup", (PyCFunction)DBC_prev_nodup, METH_VARARGS|METH_KEYWORDS}, |
| {"join_item", (PyCFunction)DBC_join_item, METH_VARARGS}, |
| {NULL, NULL} /* sentinel */ |
| }; |
| |
| |
| static PyMethodDef DBEnv_methods[] = { |
| {"close", (PyCFunction)DBEnv_close, METH_VARARGS}, |
| {"open", (PyCFunction)DBEnv_open, METH_VARARGS}, |
| {"remove", (PyCFunction)DBEnv_remove, METH_VARARGS}, |
| #if (DBVER >= 41) |
| {"dbremove", (PyCFunction)DBEnv_dbremove, METH_VARARGS|METH_KEYWORDS}, |
| {"dbrename", (PyCFunction)DBEnv_dbrename, METH_VARARGS|METH_KEYWORDS}, |
| {"set_encrypt", (PyCFunction)DBEnv_set_encrypt, METH_VARARGS|METH_KEYWORDS}, |
| #endif |
| {"set_timeout", (PyCFunction)DBEnv_set_timeout, METH_VARARGS|METH_KEYWORDS}, |
| {"set_shm_key", (PyCFunction)DBEnv_set_shm_key, METH_VARARGS}, |
| {"set_cachesize", (PyCFunction)DBEnv_set_cachesize, METH_VARARGS}, |
| {"set_data_dir", (PyCFunction)DBEnv_set_data_dir, METH_VARARGS}, |
| {"set_flags", (PyCFunction)DBEnv_set_flags, METH_VARARGS}, |
| #if (DBVER >= 47) |
| {"log_set_config", (PyCFunction)DBEnv_log_set_config, METH_VARARGS}, |
| #endif |
| {"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_NOARGS}, |
| #endif |
| {"set_lg_regionmax",(PyCFunction)DBEnv_set_lg_regionmax, METH_VARARGS}, |
| {"set_lk_detect", (PyCFunction)DBEnv_set_lk_detect, METH_VARARGS}, |
| #if (DBVER < 45) |
| {"set_lk_max", (PyCFunction)DBEnv_set_lk_max, METH_VARARGS}, |
| #endif |
| {"set_lk_max_locks", (PyCFunction)DBEnv_set_lk_max_locks, METH_VARARGS}, |
| {"set_lk_max_lockers", (PyCFunction)DBEnv_set_lk_max_lockers, METH_VARARGS}, |
| {"set_lk_max_objects", (PyCFunction)DBEnv_set_lk_max_objects, METH_VARARGS}, |
| {"set_mp_mmapsize", (PyCFunction)DBEnv_set_mp_mmapsize, METH_VARARGS}, |
| {"set_tmp_dir", (PyCFunction)DBEnv_set_tmp_dir, METH_VARARGS}, |
| {"txn_begin", (PyCFunction)DBEnv_txn_begin, METH_VARARGS|METH_KEYWORDS}, |
| {"txn_checkpoint", (PyCFunction)DBEnv_txn_checkpoint, METH_VARARGS}, |
| {"txn_stat", (PyCFunction)DBEnv_txn_stat, METH_VARARGS}, |
| {"set_tx_max", (PyCFunction)DBEnv_set_tx_max, METH_VARARGS}, |
| {"set_tx_timestamp", (PyCFunction)DBEnv_set_tx_timestamp, METH_VARARGS}, |
| {"lock_detect", (PyCFunction)DBEnv_lock_detect, METH_VARARGS}, |
| {"lock_get", (PyCFunction)DBEnv_lock_get, METH_VARARGS}, |
| {"lock_id", (PyCFunction)DBEnv_lock_id, METH_NOARGS}, |
| {"lock_id_free", (PyCFunction)DBEnv_lock_id_free, METH_VARARGS}, |
| {"lock_put", (PyCFunction)DBEnv_lock_put, METH_VARARGS}, |
| {"lock_stat", (PyCFunction)DBEnv_lock_stat, METH_VARARGS}, |
| {"log_archive", (PyCFunction)DBEnv_log_archive, METH_VARARGS}, |
| {"log_flush", (PyCFunction)DBEnv_log_flush, METH_NOARGS}, |
| {"log_stat", (PyCFunction)DBEnv_log_stat, METH_VARARGS}, |
| #if (DBVER >= 44) |
| {"lsn_reset", (PyCFunction)DBEnv_lsn_reset, METH_VARARGS|METH_KEYWORDS}, |
| #endif |
| {"set_get_returns_none",(PyCFunction)DBEnv_set_get_returns_none, METH_VARARGS}, |
| {"txn_recover", (PyCFunction)DBEnv_txn_recover, METH_NOARGS}, |
| {"set_rpc_server", (PyCFunction)DBEnv_set_rpc_server, |
| METH_VARARGS||METH_KEYWORDS}, |
| {"set_verbose", (PyCFunction)DBEnv_set_verbose, METH_VARARGS}, |
| #if (DBVER >= 42) |
| {"get_verbose", (PyCFunction)DBEnv_get_verbose, METH_VARARGS}, |
| #endif |
| {"set_private", (PyCFunction)DBEnv_set_private, METH_O}, |
| {"get_private", (PyCFunction)DBEnv_get_private, METH_NOARGS}, |
| {"rep_start", (PyCFunction)DBEnv_rep_start, |
| METH_VARARGS|METH_KEYWORDS}, |
| {"rep_set_transport", (PyCFunction)DBEnv_rep_set_transport, METH_VARARGS}, |
| {"rep_process_message", (PyCFunction)DBEnv_rep_process_message, |
| METH_VARARGS}, |
| #if (DBVER >= 46) |
| {"rep_elect", (PyCFunction)DBEnv_rep_elect, METH_VARARGS}, |
| #endif |
| #if (DBVER >= 44) |
| {"rep_set_config", (PyCFunction)DBEnv_rep_set_config, METH_VARARGS}, |
| {"rep_get_config", (PyCFunction)DBEnv_rep_get_config, METH_VARARGS}, |
| {"rep_sync", (PyCFunction)DBEnv_rep_sync, METH_NOARGS}, |
| #endif |
| #if (DBVER >= 45) |
| {"rep_set_limit", (PyCFunction)DBEnv_rep_set_limit, METH_VARARGS}, |
| {"rep_get_limit", (PyCFunction)DBEnv_rep_get_limit, METH_NOARGS}, |
| #endif |
| #if (DBVER >= 47) |
| {"rep_set_request", (PyCFunction)DBEnv_rep_set_request, METH_VARARGS}, |
| {"rep_get_request", (PyCFunction)DBEnv_rep_get_request, METH_NOARGS}, |
| #endif |
| #if (DBVER >= 45) |
| {"set_event_notify", (PyCFunction)DBEnv_set_event_notify, METH_O}, |
| #endif |
| #if (DBVER >= 45) |
| {"rep_set_nsites", (PyCFunction)DBEnv_rep_set_nsites, METH_VARARGS}, |
| {"rep_get_nsites", (PyCFunction)DBEnv_rep_get_nsites, METH_NOARGS}, |
| {"rep_set_priority", (PyCFunction)DBEnv_rep_set_priority, METH_VARARGS}, |
| {"rep_get_priority", (PyCFunction)DBEnv_rep_get_priority, METH_NOARGS}, |
| {"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_NOARGS}, |
| {"repmgr_site_list", (PyCFunction)DBEnv_repmgr_site_list, |
| METH_NOARGS}, |
| #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 */ |
| }; |
| |
| |
| static PyMethodDef DBTxn_methods[] = { |
| {"commit", (PyCFunction)DBTxn_commit, METH_VARARGS}, |
| {"prepare", (PyCFunction)DBTxn_prepare, METH_VARARGS}, |
| {"discard", (PyCFunction)DBTxn_discard, METH_NOARGS}, |
| {"abort", (PyCFunction)DBTxn_abort, METH_NOARGS}, |
| {"id", (PyCFunction)DBTxn_id, METH_NOARGS}, |
| {NULL, NULL} /* sentinel */ |
| }; |
| |
| |
| #if (DBVER >= 43) |
| static PyMethodDef DBSequence_methods[] = { |
| {"close", (PyCFunction)DBSequence_close, METH_VARARGS}, |
| {"get", (PyCFunction)DBSequence_get, METH_VARARGS|METH_KEYWORDS}, |
| {"get_dbp", (PyCFunction)DBSequence_get_dbp, METH_NOARGS}, |
| {"get_key", (PyCFunction)DBSequence_get_key, METH_NOARGS}, |
| {"init_value", (PyCFunction)DBSequence_init_value, METH_VARARGS}, |
| {"open", (PyCFunction)DBSequence_open, METH_VARARGS|METH_KEYWORDS}, |
| {"remove", (PyCFunction)DBSequence_remove, METH_VARARGS|METH_KEYWORDS}, |
| {"set_cachesize", (PyCFunction)DBSequence_set_cachesize, METH_VARARGS}, |
| {"get_cachesize", (PyCFunction)DBSequence_get_cachesize, METH_NOARGS}, |
| {"set_flags", (PyCFunction)DBSequence_set_flags, METH_VARARGS}, |
| {"get_flags", (PyCFunction)DBSequence_get_flags, METH_NOARGS}, |
| {"set_range", (PyCFunction)DBSequence_set_range, METH_VARARGS}, |
| {"get_range", (PyCFunction)DBSequence_get_range, METH_NOARGS}, |
| {"stat", (PyCFunction)DBSequence_stat, METH_VARARGS|METH_KEYWORDS}, |
| {NULL, NULL} /* sentinel */ |
| }; |
| #endif |
| |
| |
| static PyObject* |
| DBEnv_db_home_get(DBEnvObject* self) |
| { |
| 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 PyBytes_FromString(home); |
| } |
| |
| static PyGetSetDef DBEnv_getsets[] = { |
| {"db_home", (getter)DBEnv_db_home_get, NULL,}, |
| {NULL} |
| }; |
| |
| |
| statichere PyTypeObject DB_Type = { |
| #if (PY_VERSION_HEX < 0x03000000) |
| PyObject_HEAD_INIT(NULL) |
| 0, /*ob_size*/ |
| #else |
| PyVarObject_HEAD_INIT(NULL, 0) |
| #endif |
| "DB", /*tp_name*/ |
| sizeof(DBObject), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| /* methods */ |
| (destructor)DB_dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| &DB_mapping,/*tp_as_mapping*/ |
| 0, /*tp_hash*/ |
| 0, /* tp_call */ |
| 0, /* tp_str */ |
| 0, /* tp_getattro */ |
| 0, /* tp_setattro */ |
| 0, /* tp_as_buffer */ |
| #if (PY_VERSION_HEX < 0x03000000) |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ |
| #else |
| Py_TPFLAGS_DEFAULT, /* tp_flags */ |
| #endif |
| 0, /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| offsetof(DBObject, in_weakreflist), /* tp_weaklistoffset */ |
| 0, /*tp_iter*/ |
| 0, /*tp_iternext*/ |
| DB_methods, /*tp_methods*/ |
| 0, /*tp_members*/ |
| }; |
| |
| |
| statichere PyTypeObject DBCursor_Type = { |
| #if (PY_VERSION_HEX < 0x03000000) |
| PyObject_HEAD_INIT(NULL) |
| 0, /*ob_size*/ |
| #else |
| PyVarObject_HEAD_INIT(NULL, 0) |
| #endif |
| "DBCursor", /*tp_name*/ |
| sizeof(DBCursorObject), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| /* methods */ |
| (destructor)DBCursor_dealloc,/*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| 0, /*tp_as_mapping*/ |
| 0, /*tp_hash*/ |
| 0, /*tp_call*/ |
| 0, /*tp_str*/ |
| 0, /*tp_getattro*/ |
| 0, /*tp_setattro*/ |
| 0, /*tp_as_buffer*/ |
| #if (PY_VERSION_HEX < 0x03000000) |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ |
| #else |
| Py_TPFLAGS_DEFAULT, /* tp_flags */ |
| #endif |
| 0, /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| offsetof(DBCursorObject, in_weakreflist), /* tp_weaklistoffset */ |
| 0, /*tp_iter*/ |
| 0, /*tp_iternext*/ |
| DBCursor_methods, /*tp_methods*/ |
| 0, /*tp_members*/ |
| }; |
| |
| |
| statichere PyTypeObject DBEnv_Type = { |
| #if (PY_VERSION_HEX < 0x03000000) |
| PyObject_HEAD_INIT(NULL) |
| 0, /*ob_size*/ |
| #else |
| PyVarObject_HEAD_INIT(NULL, 0) |
| #endif |
| "DBEnv", /*tp_name*/ |
| sizeof(DBEnvObject), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| /* methods */ |
| (destructor)DBEnv_dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| 0, /*tp_as_mapping*/ |
| 0, /*tp_hash*/ |
| 0, /* tp_call */ |
| 0, /* tp_str */ |
| 0, /* tp_getattro */ |
| 0, /* tp_setattro */ |
| 0, /* tp_as_buffer */ |
| #if (PY_VERSION_HEX < 0x03000000) |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ |
| #else |
| Py_TPFLAGS_DEFAULT, /* tp_flags */ |
| #endif |
| 0, /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| offsetof(DBEnvObject, in_weakreflist), /* tp_weaklistoffset */ |
| 0, /* tp_iter */ |
| 0, /* tp_iternext */ |
| DBEnv_methods, /* tp_methods */ |
| 0, /* tp_members */ |
| DBEnv_getsets, /* tp_getsets */ |
| }; |
| |
| statichere PyTypeObject DBTxn_Type = { |
| #if (PY_VERSION_HEX < 0x03000000) |
| PyObject_HEAD_INIT(NULL) |
| 0, /*ob_size*/ |
| #else |
| PyVarObject_HEAD_INIT(NULL, 0) |
| #endif |
| "DBTxn", /*tp_name*/ |
| sizeof(DBTxnObject), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| /* methods */ |
| (destructor)DBTxn_dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| 0, /*tp_as_mapping*/ |
| 0, /*tp_hash*/ |
| 0, /* tp_call */ |
| 0, /* tp_str */ |
| 0, /* tp_getattro */ |
| 0, /* tp_setattro */ |
| 0, /* tp_as_buffer */ |
| #if (PY_VERSION_HEX < 0x03000000) |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ |
| #else |
| Py_TPFLAGS_DEFAULT, /* tp_flags */ |
| #endif |
| 0, /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| offsetof(DBTxnObject, in_weakreflist), /* tp_weaklistoffset */ |
| 0, /*tp_iter*/ |
| 0, /*tp_iternext*/ |
| DBTxn_methods, /*tp_methods*/ |
| 0, /*tp_members*/ |
| }; |
| |
| |
| statichere PyTypeObject DBLock_Type = { |
| #if (PY_VERSION_HEX < 0x03000000) |
| PyObject_HEAD_INIT(NULL) |
| 0, /*ob_size*/ |
| #else |
| PyVarObject_HEAD_INIT(NULL, 0) |
| #endif |
| "DBLock", /*tp_name*/ |
| sizeof(DBLockObject), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| /* methods */ |
| (destructor)DBLock_dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| 0, /*tp_as_mapping*/ |
| 0, /*tp_hash*/ |
| 0, /* tp_call */ |
| 0, /* tp_str */ |
| 0, /* tp_getattro */ |
| 0, /* tp_setattro */ |
| 0, /* tp_as_buffer */ |
| #if (PY_VERSION_HEX < 0x03000000) |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ |
| #else |
| Py_TPFLAGS_DEFAULT, /* tp_flags */ |
| #endif |
| 0, /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| offsetof(DBLockObject, in_weakreflist), /* tp_weaklistoffset */ |
| }; |
| |
| #if (DBVER >= 43) |
| statichere PyTypeObject DBSequence_Type = { |
| #if (PY_VERSION_HEX < 0x03000000) |
| PyObject_HEAD_INIT(NULL) |
| 0, /*ob_size*/ |
| #else |
| PyVarObject_HEAD_INIT(NULL, 0) |
| #endif |
| "DBSequence", /*tp_name*/ |
| sizeof(DBSequenceObject), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| /* methods */ |
| (destructor)DBSequence_dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| 0, /*tp_as_mapping*/ |
| 0, /*tp_hash*/ |
| 0, /* tp_call */ |
| 0, /* tp_str */ |
| 0, /* tp_getattro */ |
| 0, /* tp_setattro */ |
| 0, /* tp_as_buffer */ |
| #if (PY_VERSION_HEX < 0x03000000) |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ |
| #else |
| Py_TPFLAGS_DEFAULT, /* tp_flags */ |
| #endif |
| 0, /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| offsetof(DBSequenceObject, in_weakreflist), /* tp_weaklistoffset */ |
| 0, /*tp_iter*/ |
| 0, /*tp_iternext*/ |
| DBSequence_methods, /*tp_methods*/ |
| 0, /*tp_members*/ |
| }; |
| #endif |
| |
| /* --------------------------------------------------------------------- */ |
| /* Module-level functions */ |
| |
| static PyObject* |
| DB_construct(PyObject* self, PyObject* args, PyObject* kwargs) |
| { |
| PyObject* dbenvobj = NULL; |
| int flags = 0; |
| static char* kwnames[] = { "dbEnv", "flags", NULL}; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:DB", kwnames, |
| &dbenvobj, &flags)) |
| return NULL; |
| if (dbenvobj == Py_None) |
| dbenvobj = NULL; |
| else if (dbenvobj && !DBEnvObject_Check(dbenvobj)) { |
| makeTypeError("DBEnv", dbenvobj); |
| return NULL; |
| } |
| |
| return (PyObject* )newDBObject((DBEnvObject*)dbenvobj, flags); |
| } |
| |
| |
| static PyObject* |
| DBEnv_construct(PyObject* self, PyObject* args) |
| { |
| int flags = 0; |
| if (!PyArg_ParseTuple(args, "|i:DbEnv", &flags)) return NULL; |
| return (PyObject* )newDBEnvObject(flags); |
| } |
| |
| #if (DBVER >= 43) |
| static PyObject* |
| DBSequence_construct(PyObject* self, PyObject* args, PyObject* kwargs) |
| { |
| PyObject* dbobj; |
| int flags = 0; |
| static char* kwnames[] = { "db", "flags", NULL}; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:DBSequence", kwnames, &dbobj, &flags)) |
| return NULL; |
| if (!DBObject_Check(dbobj)) { |
| makeTypeError("DB", dbobj); |
| return NULL; |
| } |
| return (PyObject* )newDBSequenceObject((DBObject*)dbobj, flags); |
| } |
| #endif |
| |
| static char bsddb_version_doc[] = |
| "Returns a tuple of major, minor, and patch release numbers of the\n\ |
| underlying DB library."; |
| |
| static PyObject* |
| bsddb_version(PyObject* self) |
| { |
| int major, minor, patch; |
| |
| db_version(&major, &minor, &patch); |
| return Py_BuildValue("(iii)", major, minor, patch); |
| } |
| |
| |
| /* List of functions defined in the module */ |
| static PyMethodDef bsddb_methods[] = { |
| {"DB", (PyCFunction)DB_construct, METH_VARARGS | METH_KEYWORDS }, |
| {"DBEnv", (PyCFunction)DBEnv_construct, METH_VARARGS}, |
| #if (DBVER >= 43) |
| {"DBSequence", (PyCFunction)DBSequence_construct, METH_VARARGS | METH_KEYWORDS }, |
| #endif |
| {"version", (PyCFunction)bsddb_version, METH_NOARGS, bsddb_version_doc}, |
| {NULL, NULL} /* sentinel */ |
| }; |
| |
| |
| /* API structure */ |
| static BSDDB_api bsddb_api; |
| |
| |
| /* --------------------------------------------------------------------- */ |
| /* Module initialization */ |
| |
| |
| /* Convenience routine to export an integer value. |
| * Errors are silently ignored, for better or for worse... |
| */ |
| #define ADD_INT(dict, NAME) _addIntToDict(dict, #NAME, NAME) |
| |
| #define MODULE_NAME_MAX_LEN 11 |
| static char _bsddbModuleName[MODULE_NAME_MAX_LEN+1] = "_bsddb"; |
| |
| #if (PY_VERSION_HEX >= 0x03000000) |
| static struct PyModuleDef bsddbmodule = { |
| PyModuleDef_HEAD_INIT, |
| _bsddbModuleName, /* Name of module */ |
| NULL, /* module documentation, may be NULL */ |
| -1, /* size of per-interpreter state of the module, |
| or -1 if the module keeps state in global variables. */ |
| bsddb_methods, |
| NULL, /* Reload */ |
| NULL, /* Traverse */ |
| NULL, /* Clear */ |
| NULL /* Free */ |
| }; |
| #endif |
| |
| |
| #if (PY_VERSION_HEX < 0x03000000) |
| DL_EXPORT(void) init_bsddb(void) |
| #else |
| PyMODINIT_FUNC PyInit__bsddb(void) /* Note the two underscores */ |
| #endif |
| { |
| PyObject* m; |
| PyObject* d; |
| PyObject* pybsddb_version_s = PyBytes_FromString( PY_BSDDB_VERSION ); |
| PyObject* db_version_s = PyBytes_FromString( DB_VERSION_STRING ); |
| PyObject* cvsid_s = PyBytes_FromString( rcs_id ); |
| PyObject* py_api; |
| |
| /* Initialize object types */ |
| if ((PyType_Ready(&DB_Type) < 0) |
| || (PyType_Ready(&DBCursor_Type) < 0) |
| || (PyType_Ready(&DBEnv_Type) < 0) |
| || (PyType_Ready(&DBTxn_Type) < 0) |
| || (PyType_Ready(&DBLock_Type) < 0) |
| #if (DBVER >= 43) |
| || (PyType_Ready(&DBSequence_Type) < 0) |
| #endif |
| ) { |
| #if (PY_VERSION_HEX < 0x03000000) |
| return; |
| #else |
| return NULL; |
| #endif |
| } |
| |
| #if defined(WITH_THREAD) && !defined(MYDB_USE_GILSTATE) |
| /* Save the current interpreter, so callbacks can do the right thing. */ |
| _db_interpreterState = PyThreadState_GET()->interp; |
| #endif |
| |
| /* Create the module and add the functions */ |
| #if (PY_VERSION_HEX < 0x03000000) |
| m = Py_InitModule(_bsddbModuleName, bsddb_methods); |
| #else |
| m=PyModule_Create(&bsddbmodule); |
| #endif |
| if (m == NULL) { |
| #if (PY_VERSION_HEX < 0x03000000) |
| return; |
| #else |
| return NULL; |
| #endif |
| } |
| |
| /* Add some symbolic constants to the module */ |
| d = PyModule_GetDict(m); |
| PyDict_SetItemString(d, "__version__", pybsddb_version_s); |
| PyDict_SetItemString(d, "cvsid", cvsid_s); |
| PyDict_SetItemString(d, "DB_VERSION_STRING", db_version_s); |
| Py_DECREF(pybsddb_version_s); |
| pybsddb_version_s = NULL; |
| Py_DECREF(cvsid_s); |
| cvsid_s = NULL; |
| Py_DECREF(db_version_s); |
| db_version_s = NULL; |
| |
| ADD_INT(d, DB_VERSION_MAJOR); |
| ADD_INT(d, DB_VERSION_MINOR); |
| ADD_INT(d, DB_VERSION_PATCH); |
| |
| ADD_INT(d, DB_MAX_PAGES); |
| ADD_INT(d, DB_MAX_RECORDS); |
| |
| #if (DBVER >= 42) |
| ADD_INT(d, DB_RPCCLIENT); |
| #else |
| ADD_INT(d, DB_CLIENT); |
| /* 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); |
| |
| 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); |
| ADD_INT(d, DB_INIT_LOCK); |
| ADD_INT(d, DB_INIT_LOG); |
| ADD_INT(d, DB_INIT_MPOOL); |
| ADD_INT(d, DB_INIT_TXN); |
| ADD_INT(d, DB_JOINENV); |
| |
| ADD_INT(d, DB_XIDDATASIZE); |
| |
| ADD_INT(d, DB_RECOVER); |
| ADD_INT(d, DB_RECOVER_FATAL); |
| ADD_INT(d, DB_TXN_NOSYNC); |
| ADD_INT(d, DB_USE_ENVIRON); |
| ADD_INT(d, DB_USE_ENVIRON_ROOT); |
| |
| ADD_INT(d, DB_LOCKDOWN); |
| ADD_INT(d, DB_PRIVATE); |
| ADD_INT(d, DB_SYSTEM_MEM); |
| |
| ADD_INT(d, DB_TXN_SYNC); |
| ADD_INT(d, DB_TXN_NOWAIT); |
| |
| ADD_INT(d, DB_EXCL); |
| ADD_INT(d, DB_FCNTL_LOCKING); |
| ADD_INT(d, DB_ODDFILESIZE); |
| ADD_INT(d, DB_RDWRMASTER); |
| ADD_INT(d, DB_RDONLY); |
| ADD_INT(d, DB_TRUNCATE); |
| ADD_INT(d, DB_EXTENT); |
| ADD_INT(d, DB_CDB_ALLDB); |
| ADD_INT(d, DB_VERIFY); |
| ADD_INT(d, DB_UPGRADE); |
| |
| ADD_INT(d, DB_AGGRESSIVE); |
| ADD_INT(d, DB_NOORDERCHK); |
| ADD_INT(d, DB_ORDERCHKONLY); |
| ADD_INT(d, DB_PR_PAGE); |
| |
| ADD_INT(d, DB_PR_RECOVERYTEST); |
| ADD_INT(d, DB_SALVAGE); |
| |
| ADD_INT(d, DB_LOCK_NORUN); |
| ADD_INT(d, DB_LOCK_DEFAULT); |
| ADD_INT(d, DB_LOCK_OLDEST); |
| ADD_INT(d, DB_LOCK_RANDOM); |
| ADD_INT(d, DB_LOCK_YOUNGEST); |
| ADD_INT(d, DB_LOCK_MAXLOCKS); |
| ADD_INT(d, DB_LOCK_MINLOCKS); |
| ADD_INT(d, DB_LOCK_MINWRITE); |
| |
| ADD_INT(d, DB_LOCK_EXPIRE); |
| #if (DBVER >= 43) |
| ADD_INT(d, DB_LOCK_MAXWRITE); |
| #endif |
| |
| _addIntToDict(d, "DB_LOCK_CONFLICT", 0); |
| |
| ADD_INT(d, DB_LOCK_DUMP); |
| ADD_INT(d, DB_LOCK_GET); |
| ADD_INT(d, DB_LOCK_INHERIT); |
| ADD_INT(d, DB_LOCK_PUT); |
| ADD_INT(d, DB_LOCK_PUT_ALL); |
| ADD_INT(d, DB_LOCK_PUT_OBJ); |
| |
| ADD_INT(d, DB_LOCK_NG); |
| ADD_INT(d, DB_LOCK_READ); |
| ADD_INT(d, DB_LOCK_WRITE); |
| ADD_INT(d, DB_LOCK_NOWAIT); |
| ADD_INT(d, DB_LOCK_WAIT); |
| ADD_INT(d, DB_LOCK_IWRITE); |
| ADD_INT(d, DB_LOCK_IREAD); |
| ADD_INT(d, DB_LOCK_IWR); |
| #if (DBVER < 44) |
| ADD_INT(d, DB_LOCK_DIRTY); |
| #else |
| ADD_INT(d, DB_LOCK_READ_UNCOMMITTED); /* renamed in 4.4 */ |
| #endif |
| ADD_INT(d, DB_LOCK_WWRITE); |
| |
| ADD_INT(d, DB_LOCK_RECORD); |
| ADD_INT(d, DB_LOCK_UPGRADE); |
| ADD_INT(d, DB_LOCK_SWITCH); |
| ADD_INT(d, DB_LOCK_UPGRADE_WRITE); |
| |
| ADD_INT(d, DB_LOCK_NOWAIT); |
| ADD_INT(d, DB_LOCK_RECORD); |
| ADD_INT(d, DB_LOCK_UPGRADE); |
| |
| ADD_INT(d, DB_LSTAT_ABORTED); |
| #if (DBVER < 43) |
| ADD_INT(d, DB_LSTAT_ERR); |
| #endif |
| ADD_INT(d, DB_LSTAT_FREE); |
| ADD_INT(d, DB_LSTAT_HELD); |
| |
| ADD_INT(d, DB_LSTAT_PENDING); |
| ADD_INT(d, DB_LSTAT_WAITING); |
| |
| ADD_INT(d, DB_ARCH_ABS); |
| ADD_INT(d, DB_ARCH_DATA); |
| ADD_INT(d, DB_ARCH_LOG); |
| #if (DBVER >= 42) |
| ADD_INT(d, DB_ARCH_REMOVE); |
| #endif |
| |
| ADD_INT(d, DB_BTREE); |
| ADD_INT(d, DB_HASH); |
| ADD_INT(d, DB_RECNO); |
| ADD_INT(d, DB_QUEUE); |
| ADD_INT(d, DB_UNKNOWN); |
| |
| ADD_INT(d, DB_DUP); |
| ADD_INT(d, DB_DUPSORT); |
| ADD_INT(d, DB_RECNUM); |
| ADD_INT(d, DB_RENUMBER); |
| ADD_INT(d, DB_REVSPLITOFF); |
| ADD_INT(d, DB_SNAPSHOT); |
| |
| ADD_INT(d, DB_JOIN_NOSORT); |
| |
| ADD_INT(d, DB_AFTER); |
| ADD_INT(d, DB_APPEND); |
| ADD_INT(d, DB_BEFORE); |
| #if (DBVER < 45) |
| ADD_INT(d, DB_CACHED_COUNTS); |
| #endif |
| |
| #if (DBVER >= 41) |
| _addIntToDict(d, "DB_CHECKPOINT", 0); |
| #else |
| ADD_INT(d, DB_CHECKPOINT); |
| ADD_INT(d, DB_CURLSN); |
| #endif |
| #if (DBVER <= 41) |
| ADD_INT(d, DB_COMMIT); |
| #endif |
| ADD_INT(d, DB_CONSUME); |
| ADD_INT(d, DB_CONSUME_WAIT); |
| ADD_INT(d, DB_CURRENT); |
| ADD_INT(d, DB_FAST_STAT); |
| ADD_INT(d, DB_FIRST); |
| ADD_INT(d, DB_FLUSH); |
| ADD_INT(d, DB_GET_BOTH); |
| ADD_INT(d, DB_GET_RECNO); |
| ADD_INT(d, DB_JOIN_ITEM); |
| ADD_INT(d, DB_KEYFIRST); |
| ADD_INT(d, DB_KEYLAST); |
| ADD_INT(d, DB_LAST); |
| ADD_INT(d, DB_NEXT); |
| ADD_INT(d, DB_NEXT_DUP); |
| ADD_INT(d, DB_NEXT_NODUP); |
| ADD_INT(d, DB_NODUPDATA); |
| ADD_INT(d, DB_NOOVERWRITE); |
| ADD_INT(d, DB_NOSYNC); |
| ADD_INT(d, DB_POSITION); |
| ADD_INT(d, DB_PREV); |
| ADD_INT(d, DB_PREV_NODUP); |
| #if (DBVER < 45) |
| ADD_INT(d, DB_RECORDCOUNT); |
| #endif |
| ADD_INT(d, DB_SET); |
| ADD_INT(d, DB_SET_RANGE); |
| ADD_INT(d, DB_SET_RECNO); |
| ADD_INT(d, DB_WRITECURSOR); |
| |
| ADD_INT(d, DB_OPFLAGS_MASK); |
| ADD_INT(d, DB_RMW); |
| ADD_INT(d, DB_DIRTY_READ); |
| ADD_INT(d, DB_MULTIPLE); |
| ADD_INT(d, DB_MULTIPLE_KEY); |
| |
| #if (DBVER >= 44) |
| ADD_INT(d, DB_READ_UNCOMMITTED); /* replaces DB_DIRTY_READ in 4.4 */ |
| ADD_INT(d, DB_READ_COMMITTED); |
| #endif |
| |
| ADD_INT(d, DB_DONOTINDEX); |
| |
| #if (DBVER >= 41) |
| _addIntToDict(d, "DB_INCOMPLETE", 0); |
| #else |
| ADD_INT(d, DB_INCOMPLETE); |
| #endif |
| ADD_INT(d, DB_KEYEMPTY); |
| ADD_INT(d, DB_KEYEXIST); |
| ADD_INT(d, DB_LOCK_DEADLOCK); |
| ADD_INT(d, DB_LOCK_NOTGRANTED); |
| ADD_INT(d, DB_NOSERVER); |
| ADD_INT(d, DB_NOSERVER_HOME); |
| ADD_INT(d, DB_NOSERVER_ID); |
| ADD_INT(d, DB_NOTFOUND); |
| ADD_INT(d, DB_OLD_VERSION); |
| ADD_INT(d, DB_RUNRECOVERY); |
| ADD_INT(d, DB_VERIFY_BAD); |
| ADD_INT(d, DB_PAGE_NOTFOUND); |
| ADD_INT(d, DB_SECONDARY_BAD); |
| ADD_INT(d, DB_STAT_CLEAR); |
| ADD_INT(d, DB_REGION_INIT); |
| ADD_INT(d, DB_NOLOCKING); |
| ADD_INT(d, DB_YIELDCPU); |
| ADD_INT(d, DB_PANIC_ENVIRONMENT); |
| ADD_INT(d, DB_NOPANIC); |
| |
| #if (DBVER >= 41) |
| ADD_INT(d, DB_OVERWRITE); |
| #endif |
| |
| #ifdef DB_REGISTER |
| ADD_INT(d, DB_REGISTER); |
| #endif |
| |
| #if (DBVER >= 42) |
| ADD_INT(d, DB_TIME_NOTGRANTED); |
| ADD_INT(d, DB_TXN_NOT_DURABLE); |
| ADD_INT(d, DB_TXN_WRITE_NOSYNC); |
| ADD_INT(d, DB_DIRECT_DB); |
| ADD_INT(d, DB_INIT_REP); |
| ADD_INT(d, DB_ENCRYPT); |
| ADD_INT(d, DB_CHKSUM); |
| #endif |
| |
| #if (DBVER >= 42) && (DBVER < 47) |
| ADD_INT(d, DB_LOG_AUTOREMOVE); |
| ADD_INT(d, DB_DIRECT_LOG); |
| #endif |
| |
| #if (DBVER >= 47) |
| ADD_INT(d, DB_LOG_DIRECT); |
| ADD_INT(d, DB_LOG_DSYNC); |
| ADD_INT(d, DB_LOG_IN_MEMORY); |
| ADD_INT(d, DB_LOG_AUTO_REMOVE); |
| ADD_INT(d, DB_LOG_ZERO); |
| #endif |
| |
| #if (DBVER >= 44) |
| ADD_INT(d, DB_DSYNC_DB); |
| #endif |
| |
| #if (DBVER >= 45) |
| ADD_INT(d, DB_TXN_SNAPSHOT); |
| #endif |
| |
| 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); |
| |
| #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 |
| |
| ADD_INT(d, DB_REP_DUPMASTER); |
| ADD_INT(d, DB_REP_HOLDELECTION); |
| #if (DBVER >= 44) |
| ADD_INT(d, DB_REP_IGNORE); |
| ADD_INT(d, DB_REP_JOIN_FAILURE); |
| #endif |
| #if (DBVER >= 42) |
| ADD_INT(d, DB_REP_ISPERM); |
| ADD_INT(d, DB_REP_NOTPERM); |
| #endif |
| ADD_INT(d, DB_REP_NEWSITE); |
| |
| 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 |
| |
| #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_BUFFER_SMALL); |
| ADD_INT(d, DB_SEQ_DEC); |
| ADD_INT(d, DB_SEQ_INC); |
| ADD_INT(d, DB_SEQ_WRAP); |
| #endif |
| |
| #if (DBVER >= 43) && (DBVER < 47) |
| ADD_INT(d, DB_LOG_INMEMORY); |
| ADD_INT(d, DB_DSYNC_LOG); |
| #endif |
| |
| #if (DBVER >= 41) |
| ADD_INT(d, DB_ENCRYPT_AES); |
| ADD_INT(d, DB_AUTO_COMMIT); |
| #else |
| /* allow Berkeley DB 4.1 aware apps to run on older versions */ |
| _addIntToDict(d, "DB_AUTO_COMMIT", 0); |
| #endif |
| |
| ADD_INT(d, EINVAL); |
| ADD_INT(d, EACCES); |
| ADD_INT(d, ENOSPC); |
| ADD_INT(d, ENOMEM); |
| ADD_INT(d, EAGAIN); |
| ADD_INT(d, EBUSY); |
| ADD_INT(d, EEXIST); |
| ADD_INT(d, ENOENT); |
| ADD_INT(d, EPERM); |
| |
| ADD_INT(d, DB_SET_LOCK_TIMEOUT); |
| ADD_INT(d, DB_SET_TXN_TIMEOUT); |
| |
| /* The exception name must be correct for pickled exception * |
| * objects to unpickle properly. */ |
| #ifdef PYBSDDB_STANDALONE /* different value needed for standalone pybsddb */ |
| #define PYBSDDB_EXCEPTION_BASE "bsddb3.db." |
| #else |
| #define PYBSDDB_EXCEPTION_BASE "bsddb.db." |
| #endif |
| |
| /* All the rest of the exceptions derive only from DBError */ |
| #define MAKE_EX(name) name = PyErr_NewException(PYBSDDB_EXCEPTION_BASE #name, DBError, NULL); \ |
| PyDict_SetItemString(d, #name, name) |
| |
| /* The base exception class is DBError */ |
| DBError = NULL; /* used in MAKE_EX so that it derives from nothing */ |
| MAKE_EX(DBError); |
| |
| #if (PY_VERSION_HEX < 0x03000000) |
| /* Some magic to make DBNotFoundError and DBKeyEmptyError derive |
| * from both DBError and KeyError, since the API only supports |
| * using one base class. */ |
| PyDict_SetItemString(d, "KeyError", PyExc_KeyError); |
| PyRun_String("class DBNotFoundError(DBError, KeyError): pass\n" |
| "class DBKeyEmptyError(DBError, KeyError): pass", |
| Py_file_input, d, d); |
| DBNotFoundError = PyDict_GetItemString(d, "DBNotFoundError"); |
| DBKeyEmptyError = PyDict_GetItemString(d, "DBKeyEmptyError"); |
| PyDict_DelItemString(d, "KeyError"); |
| #else |
| /* Since Python 2.5, PyErr_NewException() accepts a tuple, to be able to |
| ** derive from several classes. We use this new API only for Python 3.0, |
| ** though. |
| */ |
| { |
| PyObject* bases; |
| |
| bases = PyTuple_Pack(2, DBError, PyExc_KeyError); |
| |
| #define MAKE_EX2(name) name = PyErr_NewException(PYBSDDB_EXCEPTION_BASE #name, bases, NULL); \ |
| PyDict_SetItemString(d, #name, name) |
| MAKE_EX2(DBNotFoundError); |
| MAKE_EX2(DBKeyEmptyError); |
| |
| #undef MAKE_EX2 |
| |
| Py_XDECREF(bases); |
| } |
| #endif |
| |
| |
| #if !INCOMPLETE_IS_WARNING |
| MAKE_EX(DBIncompleteError); |
| #endif |
| MAKE_EX(DBCursorClosedError); |
| MAKE_EX(DBKeyEmptyError); |
| MAKE_EX(DBKeyExistError); |
| MAKE_EX(DBLockDeadlockError); |
| MAKE_EX(DBLockNotGrantedError); |
| MAKE_EX(DBOldVersionError); |
| MAKE_EX(DBRunRecoveryError); |
| MAKE_EX(DBVerifyBadError); |
| MAKE_EX(DBNoServerError); |
| MAKE_EX(DBNoServerHomeError); |
| MAKE_EX(DBNoServerIDError); |
| MAKE_EX(DBPageNotFoundError); |
| MAKE_EX(DBSecondaryBadError); |
| |
| MAKE_EX(DBInvalidArgError); |
| MAKE_EX(DBAccessError); |
| MAKE_EX(DBNoSpaceError); |
| MAKE_EX(DBNoMemoryError); |
| MAKE_EX(DBAgainError); |
| MAKE_EX(DBBusyError); |
| MAKE_EX(DBFileExistsError); |
| MAKE_EX(DBNoSuchFileError); |
| MAKE_EX(DBPermissionsError); |
| |
| #if (DBVER >= 42) |
| MAKE_EX(DBRepHandleDeadError); |
| #endif |
| |
| MAKE_EX(DBRepUnavailError); |
| |
| #undef MAKE_EX |
| |
| /* Initiliase the C API structure and add it to the module */ |
| bsddb_api.db_type = &DB_Type; |
| bsddb_api.dbcursor_type = &DBCursor_Type; |
| bsddb_api.dbenv_type = &DBEnv_Type; |
| bsddb_api.dbtxn_type = &DBTxn_Type; |
| bsddb_api.dblock_type = &DBLock_Type; |
| #if (DBVER >= 43) |
| bsddb_api.dbsequence_type = &DBSequence_Type; |
| #endif |
| bsddb_api.makeDBError = makeDBError; |
| |
| py_api = PyCObject_FromVoidPtr((void*)&bsddb_api, NULL); |
| PyDict_SetItemString(d, "api", py_api); |
| Py_DECREF(py_api); |
| |
| /* Check for errors */ |
| if (PyErr_Occurred()) { |
| PyErr_Print(); |
| Py_FatalError("can't initialize module _bsddb/_pybsddb"); |
| Py_DECREF(m); |
| m = NULL; |
| } |
| #if (PY_VERSION_HEX < 0x03000000) |
| return; |
| #else |
| return m; |
| #endif |
| } |
| |
| /* allow this module to be named _pybsddb so that it can be installed |
| * and imported on top of python >= 2.3 that includes its own older |
| * copy of the library named _bsddb without importing the old version. */ |
| #if (PY_VERSION_HEX < 0x03000000) |
| DL_EXPORT(void) init_pybsddb(void) |
| #else |
| PyMODINIT_FUNC PyInit__pybsddb(void) /* Note the two underscores */ |
| #endif |
| { |
| strncpy(_bsddbModuleName, "_pybsddb", MODULE_NAME_MAX_LEN); |
| #if (PY_VERSION_HEX < 0x03000000) |
| init_bsddb(); |
| #else |
| return PyInit__bsddb(); /* Note the two underscores */ |
| #endif |
| } |
| |