Files
mongo/lang/python/wiredtiger.i
Susan LoVerso d6a6c0506d Merge branch 'develop' into encryption-api
Conflicts:
	dist/api_data.py
	src/config/config_def.c
	src/include/config.h
2015-04-28 10:44:39 -04:00

1236 lines
31 KiB
OpenEdge ABL

/*-
* Public Domain 2014-2015 MongoDB, Inc.
* Public Domain 2008-2014 WiredTiger, Inc.
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* wiredtiger.i
* The SWIG interface file defining the wiredtiger python API.
*/
%define DOCSTRING
"Python wrappers around the WiredTiger C API
This provides an API similar to the C API, with the following modifications:
- Many C functions are exposed as OO methods. See the Python examples and test suite
- Errors are handled in a Pythonic way; wrap calls in try/except blocks
- Cursors have extra accessor methods and iterators that are higher-level than the C API
- Statistics cursors behave a little differently and are best handled using the C-like functions
- C Constants starting with WT_STAT_DSRC are instead exposed under wiredtiger.stat.dsrc
- C Constants starting with WT_STAT_CONN are instead exposed under wiredtiger.stat.conn
"
%enddef
%module(docstring=DOCSTRING) wiredtiger
%feature("autodoc", "0");
%pythoncode %{
from packing import pack, unpack
## @endcond
%}
/* Set the input argument to point to a temporary variable */
%typemap(in, numinputs=0) WT_CONNECTION ** (WT_CONNECTION *temp = NULL) {
$1 = &temp;
}
%typemap(in, numinputs=0) WT_SESSION ** (WT_SESSION *temp = NULL) {
$1 = &temp;
}
%typemap(in, numinputs=0) WT_ASYNC_OP ** (WT_ASYNC_OP *temp = NULL) {
$1 = &temp;
}
%typemap(in, numinputs=0) WT_CURSOR ** (WT_CURSOR *temp = NULL) {
$1 = &temp;
}
%typemap(in) WT_ASYNC_CALLBACK * (PyObject *callback_obj = NULL) %{
callback_obj = $input;
$1 = &pyApiAsyncCallback;
%}
%typemap(in, numinputs=0) WT_EVENT_HANDLER * %{
$1 = &pyApiEventHandler;
%}
/* Set the return value to the returned connection, session, or cursor */
%typemap(argout) WT_CONNECTION ** {
$result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
SWIGTYPE_p___wt_connection, 0);
}
%typemap(argout) WT_SESSION ** {
$result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
SWIGTYPE_p___wt_session, 0);
if (*$1 != NULL) {
PY_CALLBACK *pcb;
if (__wt_calloc_def((WT_SESSION_IMPL *)(*$1), 1, &pcb) != 0)
SWIG_exception_fail(SWIG_MemoryError, "WT calloc failed");
else {
Py_XINCREF($result);
pcb->pyobj = $result;
((WT_SESSION_IMPL *)(*$1))->lang_private = pcb;
}
}
}
%typemap(argout) WT_ASYNC_OP ** {
$result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
SWIGTYPE_p___wt_async_op, 0);
if (*$1 != NULL) {
PY_CALLBACK *pcb;
(*$1)->c.flags |= WT_CURSTD_RAW;
PyObject_SetAttrString($result, "is_column",
PyBool_FromLong(strcmp((*$1)->key_format, "r") == 0));
PyObject_SetAttrString($result, "key_format",
PyString_InternFromString((*$1)->key_format));
PyObject_SetAttrString($result, "value_format",
PyString_InternFromString((*$1)->value_format));
if (__wt_calloc_def((WT_ASYNC_OP_IMPL *)(*$1), 1, &pcb) != 0)
SWIG_exception_fail(SWIG_MemoryError, "WT calloc failed");
else {
pcb->pyobj = $result;
Py_XINCREF(pcb->pyobj);
/* XXX Is there a way to avoid SWIG's numbering? */
pcb->pyasynccb = callback_obj5;
Py_XINCREF(pcb->pyasynccb);
(*$1)->c.lang_private = pcb;
}
}
}
%typemap(argout) WT_CURSOR ** {
$result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
SWIGTYPE_p___wt_cursor, 0);
if (*$1 != NULL) {
PY_CALLBACK *pcb;
uint32_t json;
json = (*$1)->flags & WT_CURSTD_DUMP_JSON;
if (!json)
(*$1)->flags |= WT_CURSTD_RAW;
PyObject_SetAttrString($result, "is_json",
PyBool_FromLong(json != 0));
PyObject_SetAttrString($result, "is_column",
PyBool_FromLong(strcmp((*$1)->key_format, "r") == 0));
PyObject_SetAttrString($result, "key_format",
PyString_InternFromString((*$1)->key_format));
PyObject_SetAttrString($result, "value_format",
PyString_InternFromString((*$1)->value_format));
if (__wt_calloc_def((WT_SESSION_IMPL *)(*$1)->session, 1, &pcb) != 0)
SWIG_exception_fail(SWIG_MemoryError, "WT calloc failed");
else {
Py_XINCREF($result);
pcb->pyobj = $result;
(*$1)->lang_private = pcb;
}
}
}
/* 64 bit typemaps. */
%typemap(in) uint64_t {
$1 = PyLong_AsUnsignedLongLong($input);
}
%typemap(out) uint64_t {
$result = PyLong_FromUnsignedLongLong($1);
}
/* Throw away references after close. */
%define DESTRUCTOR(class, method)
%feature("shadow") class::method %{
def method(self, *args):
'''method(self, config) -> int
@copydoc class::method'''
try:
self._freecb()
return $action(self, *args)
finally:
self.this = None
%}
%enddef
DESTRUCTOR(__wt_connection, close)
DESTRUCTOR(__wt_cursor, close)
DESTRUCTOR(__wt_session, close)
/*
* OVERRIDE_METHOD must be used when overriding or extending an existing
* method in the C interface. It creates Python method() that calls
* _method(), which is the extended version of the method. This works
* around potential naming conflicts. Without this technique, for example,
* defining __wt_cursor::equals() creates the wrapper function
* __wt_cursor_equals(), which may be defined in the WT library.
*/
%define OVERRIDE_METHOD(cclass, pyclass, method, pyargs)
%extend cclass {
%pythoncode %{
def method(self, *args):
'''method pyargs -> int
@copydoc class::method'''
return self._##method(*args)
%}
};
%enddef
/* Don't require empty config strings. */
%typemap(default) const char *config { $1 = NULL; }
%typemap(default) WT_CURSOR *to_dup { $1 = NULL; }
/*
* Error returns other than WT_NOTFOUND generate an exception.
* Use our own exception type, in future tailored to the kind
* of error.
*/
%header %{
#include "src/include/wt_internal.h"
/*
* Closed handle checking:
*
* The typedef WT_CURSOR_NULLABLE used in wiredtiger.h is only made
* visible to the SWIG parser and is used to identify arguments of
* Cursor type that are permitted to be null. Likewise, typedefs
* WT_{CURSOR,SESSION,CONNECTION}_CLOSED identify 'close' calls that
* need explicit nulling of the swigCPtr. We do not match the *_CLOSED
* typedefs in Python SWIG, as we already have special cased 'close' methods.
*
* We want SWIG to see these 'fake' typenames, but not the compiler.
*/
#define WT_CURSOR_NULLABLE WT_CURSOR
#define WT_CURSOR_CLOSED WT_CURSOR
#define WT_SESSION_CLOSED WT_SESSION
#define WT_CONNECTION_CLOSED WT_CONNECTION
/*
* For Connections, Sessions and Cursors created in Python, each of
* WT_CONNECTION_IMPL, WT_SESSION_IMPL and WT_CURSOR have a
* lang_private field that store a pointer to a PY_CALLBACK, alloced
* during the various open calls. {conn,session,cursor}CloseHandler()
* functions reach into the associated Python object, set the 'this'
* asttribute to None, and free the PY_CALLBACK.
*/
typedef struct {
PyObject *pyobj; /* the python Session/Cursor/AsyncOp object */
PyObject *pyasynccb; /* the callback to use for AsyncOp */
} PY_CALLBACK;
static PyObject *wtError;
static int sessionFreeHandler(WT_SESSION *session_arg);
static int cursorFreeHandler(WT_CURSOR *cursor_arg);
%}
%init %{
/*
* Create an exception type and put it into the _wiredtiger module.
* First increment the reference count because PyModule_AddObject
* decrements it. Then note that "m" is the local variable for the
* module in the SWIG generated code. If there is a SWIG variable for
* this, I haven't found it.
*/
wtError = PyErr_NewException("_wiredtiger.WiredTigerError", NULL, NULL);
Py_INCREF(wtError);
PyModule_AddObject(m, "WiredTigerError", wtError);
%}
%pythoncode %{
WiredTigerError = _wiredtiger.WiredTigerError
## @cond DISABLE
# Implements the iterable contract
class IterableCursor:
def __init__(self, cursor):
self.cursor = cursor
def __iter__(self):
return self
def next(self):
if self.cursor.next() == WT_NOTFOUND:
raise StopIteration
return self.cursor.get_keys() + self.cursor.get_values()
## @endcond
# An abstract class, which must be subclassed with notify() overridden.
class AsyncCallback:
def __init__(self):
raise NotImplementedError
def notify(self, op, op_ret, flags):
raise NotImplementedError
%}
/* Bail out if arg or arg.this is None, else set res to the C pointer. */
%define CONVERT_WITH_NULLCHECK(argp, res)
if ($input == Py_None) {
SWIG_exception_fail(SWIG_NullReferenceError,
"in method '$symname', "
"argument $argnum of type '$type' is None");
} else {
res = SWIG_ConvertPtr($input, &argp, $descriptor, $disown | 0);
if (!SWIG_IsOK(res)) {
if (SWIG_Python_GetSwigThis($input) == 0) {
SWIG_exception_fail(SWIG_NullReferenceError,
"in method '$symname', "
"argument $argnum of type '$type' is None");
} else {
SWIG_exception_fail(SWIG_ArgError(res),
"in method '$symname', "
"argument $argnum of type '$type'");
}
}
}
%enddef
/*
* Extra 'self' elimination.
* The methods we're wrapping look like this:
* struct __wt_xxx {
* int method(WT_XXX *, ...otherargs...);
* };
* To SWIG, that is equivalent to:
* int method(struct __wt_xxx *self, WT_XXX *, ...otherargs...);
* and we use consecutive argument matching of typemaps to convert two args to
* one.
*/
%define SELFHELPER(type, name)
%typemap(in) (type *self, type *name) (void *argp = 0, int res = 0) %{
CONVERT_WITH_NULLCHECK(argp, res)
$2 = $1 = ($ltype)(argp);
%}
%typemap(in) type ## _NULLABLE * {
$1 = *(type **)&$input;
}
%enddef
SELFHELPER(struct __wt_connection, connection)
SELFHELPER(struct __wt_async_op, op)
SELFHELPER(struct __wt_session, session)
SELFHELPER(struct __wt_cursor, cursor)
/*
* Create an error exception if it has not already
* been done.
*/
%define SWIG_ERROR_IF_NOT_SET(result)
do {
if (PyErr_Occurred() == NULL) {
/* We could use PyErr_SetObject for more complex reporting. */
SWIG_SetErrorMsg(wtError, wiredtiger_strerror(result));
}
SWIG_fail;
} while(0)
%enddef
/* Error handling. Default case: a non-zero return is an error. */
%exception {
$action
if (result != 0)
SWIG_ERROR_IF_NOT_SET(result);
}
/* Async operations can return EBUSY when no ops are available. */
%define EBUSY_OK(m)
%exception m {
retry:
$action
if (result != 0 && result != EBUSY)
SWIG_ERROR_IF_NOT_SET(result);
else if (result == EBUSY) {
SWIG_PYTHON_THREAD_BEGIN_ALLOW;
__wt_sleep(0, 10000);
SWIG_PYTHON_THREAD_END_ALLOW;
goto retry;
}
}
%enddef
/* Any API that returns an enum type uses this. */
%define ENUM_OK(m)
%exception m {
$action
}
%enddef
/* Cursor positioning methods can also return WT_NOTFOUND. */
%define NOTFOUND_OK(m)
%exception m {
$action
if (result != 0 && result != WT_NOTFOUND)
SWIG_ERROR_IF_NOT_SET(result);
}
%enddef
/* Cursor compare can return any of -1, 0, 1. */
%define COMPARE_OK(m)
%exception m {
$action
if (result < -1 || result > 1)
SWIG_ERROR_IF_NOT_SET(result);
}
%enddef
/* Cursor compare can return any of -1, 0, 1 or WT_NOTFOUND. */
%define COMPARE_NOTFOUND_OK(m)
%exception m {
$action
if ((result < -1 || result > 1) && result != WT_NOTFOUND)
SWIG_ERROR_IF_NOT_SET(result);
}
%enddef
EBUSY_OK(__wt_connection::async_new_op)
ENUM_OK(__wt_async_op::get_type)
NOTFOUND_OK(__wt_cursor::next)
NOTFOUND_OK(__wt_cursor::prev)
NOTFOUND_OK(__wt_cursor::remove)
NOTFOUND_OK(__wt_cursor::search)
NOTFOUND_OK(__wt_cursor::update)
COMPARE_OK(__wt_cursor::_compare)
COMPARE_OK(__wt_cursor::_equals)
COMPARE_NOTFOUND_OK(__wt_cursor::_search_near)
/* Lastly, some methods need no (additional) error checking. */
%exception __wt_connection::get_home;
%exception __wt_connection::is_new;
%exception __wt_connection::search_near;
%exception __wt_async_op::_set_key;
%exception __wt_async_op::_set_value;
%exception __wt_cursor::_set_key;
%exception __wt_cursor::_set_key_str;
%exception __wt_cursor::_set_value;
%exception __wt_cursor::_set_value_str;
%exception wiredtiger_strerror;
%exception wiredtiger_version;
%exception diagnostic_build;
%exception verbose_build;
/* WT_ASYNC_OP customization. */
/* First, replace the varargs get / set methods with Python equivalents. */
%ignore __wt_async_op::get_key;
%ignore __wt_async_op::get_value;
%ignore __wt_async_op::set_key;
%ignore __wt_async_op::set_value;
%immutable __wt_async_op::connection;
/* WT_CURSOR customization. */
/* First, replace the varargs get / set methods with Python equivalents. */
%ignore __wt_cursor::get_key;
%ignore __wt_cursor::get_value;
%ignore __wt_cursor::set_key;
%ignore __wt_cursor::set_value;
/* Next, override methods that return integers via arguments. */
%ignore __wt_cursor::compare(WT_CURSOR *, WT_CURSOR *, int *);
%ignore __wt_cursor::equals(WT_CURSOR *, WT_CURSOR *, int *);
%ignore __wt_cursor::search_near(WT_CURSOR *, int *);
OVERRIDE_METHOD(__wt_cursor, WT_CURSOR, compare, (self, other))
OVERRIDE_METHOD(__wt_cursor, WT_CURSOR, equals, (self, other))
OVERRIDE_METHOD(__wt_cursor, WT_CURSOR, search_near, (self))
/* SWIG magic to turn Python byte strings into data / size. */
%apply (char *STRING, int LENGTH) { (char *data, int size) };
/* Handle binary data returns from get_key/value -- avoid cstring.i: it creates a list of returns. */
%typemap(in,numinputs=0) (char **datap, int *sizep) (char *data, int size) { $1 = &data; $2 = &size; }
%typemap(frearg) (char **datap, int *sizep) "";
%typemap(argout) (char **datap, int *sizep) {
if (*$1)
$result = SWIG_FromCharPtrAndSize(*$1, *$2);
}
/* Handle record number returns from get_recno */
%typemap(in,numinputs=0) (uint64_t *recnop) (uint64_t recno) { $1 = &recno; }
%typemap(frearg) (uint64_t *recnop) "";
%typemap(argout) (uint64_t *recnop) { $result = PyLong_FromUnsignedLongLong(*$1); }
%{
typedef int int_void;
%}
typedef int int_void;
%typemap(out) int_void { $result = VOID_Object; }
%extend __wt_async_op {
/* Get / set keys and values */
void _set_key(char *data, int size) {
WT_ITEM k;
k.data = data;
k.size = (uint32_t)size;
$self->set_key($self, &k);
}
int_void _set_recno(uint64_t recno) {
WT_ITEM k;
uint8_t recno_buf[20];
size_t size;
int ret;
if ((ret = wiredtiger_struct_size(NULL,
&size, "r", recno)) != 0 ||
(ret = wiredtiger_struct_pack(NULL,
recno_buf, sizeof (recno_buf), "r", recno)) != 0)
return (ret);
k.data = recno_buf;
k.size = (uint32_t)size;
$self->set_key($self, &k);
return (ret);
}
void _set_value(char *data, int size) {
WT_ITEM v;
v.data = data;
v.size = (uint32_t)size;
$self->set_value($self, &v);
}
/* Don't return values, just throw exceptions on failure. */
int_void _get_key(char **datap, int *sizep) {
WT_ITEM k;
int ret = $self->get_key($self, &k);
if (ret == 0) {
*datap = (char *)k.data;
*sizep = (int)k.size;
}
return (ret);
}
int_void _get_recno(uint64_t *recnop) {
WT_ITEM k;
int ret = $self->get_key($self, &k);
if (ret == 0)
ret = wiredtiger_struct_unpack(NULL,
k.data, k.size, "q", recnop);
return (ret);
}
int_void _get_value(char **datap, int *sizep) {
WT_ITEM v;
int ret = $self->get_value($self, &v);
if (ret == 0) {
*datap = (char *)v.data;
*sizep = (int)v.size;
}
return (ret);
}
int _freecb() {
return (cursorFreeHandler($self));
}
%pythoncode %{
def get_key(self):
'''get_key(self) -> object
@copydoc WT_ASYNC_OP::get_key
Returns only the first column.'''
k = self.get_keys()
if len(k) == 1:
return k[0]
return k
def get_keys(self):
'''get_keys(self) -> (object, ...)
@copydoc WT_ASYNC_OP::get_key'''
if self.is_column:
return [self._get_recno(),]
else:
return unpack(self.key_format, self._get_key())
def get_value(self):
'''get_value(self) -> object
@copydoc WT_ASYNC_OP::get_value
Returns only the first column.'''
v = self.get_values()
if len(v) == 1:
return v[0]
return v
def get_values(self):
'''get_values(self) -> (object, ...)
@copydoc WT_ASYNC_OP::get_value'''
return unpack(self.value_format, self._get_value())
def set_key(self, *args):
'''set_key(self) -> None
@copydoc WT_ASYNC_OP::set_key'''
if len(args) == 1 and type(args[0]) == tuple:
args = args[0]
if self.is_column:
self._set_recno(long(args[0]))
else:
# Keep the Python string pinned
self._key = pack(self.key_format, *args)
self._set_key(self._key)
def set_value(self, *args):
'''set_value(self) -> None
@copydoc WT_ASYNC_OP::set_value'''
if len(args) == 1 and type(args[0]) == tuple:
args = args[0]
# Keep the Python string pinned
self._value = pack(self.value_format, *args)
self._set_value(self._value)
def __getitem__(self, key):
'''Python convenience for searching'''
self.set_key(key)
if self.search() != 0:
raise KeyError
return self.get_value()
def __setitem__(self, key, value):
'''Python convenience for inserting'''
self.set_key(key)
self.set_key(value)
self.insert()
%}
};
%extend __wt_cursor {
/* Get / set keys and values */
void _set_key(char *data, int size) {
WT_ITEM k;
k.data = data;
k.size = (uint32_t)size;
$self->set_key($self, &k);
}
/* Get / set keys and values */
void _set_key_str(char *str) {
$self->set_key($self, str);
}
int_void _set_recno(uint64_t recno) {
WT_ITEM k;
uint8_t recno_buf[20];
size_t size;
int ret;
if ((ret = wiredtiger_struct_size($self->session,
&size, "r", recno)) != 0 ||
(ret = wiredtiger_struct_pack($self->session,
recno_buf, sizeof (recno_buf), "r", recno)) != 0)
return (ret);
k.data = recno_buf;
k.size = (uint32_t)size;
$self->set_key($self, &k);
return (ret);
}
void _set_value(char *data, int size) {
WT_ITEM v;
v.data = data;
v.size = (uint32_t)size;
$self->set_value($self, &v);
}
/* Get / set keys and values */
void _set_value_str(char *str) {
$self->set_value($self, str);
}
/* Don't return values, just throw exceptions on failure. */
int_void _get_key(char **datap, int *sizep) {
WT_ITEM k;
int ret = $self->get_key($self, &k);
if (ret == 0) {
*datap = (char *)k.data;
*sizep = (int)k.size;
}
return (ret);
}
int_void _get_json_key(char **datap, int *sizep) {
const char *k;
int ret = $self->get_key($self, &k);
if (ret == 0) {
*datap = (char *)k;
*sizep = strlen(k);
}
return (ret);
}
int_void _get_recno(uint64_t *recnop) {
WT_ITEM k;
int ret = $self->get_key($self, &k);
if (ret == 0)
ret = wiredtiger_struct_unpack($self->session,
k.data, k.size, "q", recnop);
return (ret);
}
int_void _get_value(char **datap, int *sizep) {
WT_ITEM v;
int ret = $self->get_value($self, &v);
if (ret == 0) {
*datap = (char *)v.data;
*sizep = (int)v.size;
}
return (ret);
}
int_void _get_json_value(char **datap, int *sizep) {
const char *k;
int ret = $self->get_value($self, &k);
if (ret == 0) {
*datap = (char *)k;
*sizep = strlen(k);
}
return (ret);
}
/* compare: special handling. */
int _compare(WT_CURSOR *other) {
int cmp = 0;
int ret = 0;
if (other == NULL) {
SWIG_Error(SWIG_NullReferenceError,
"in method 'Cursor_compare', "
"argument 1 of type 'struct __wt_cursor *' "
"is None");
ret = EINVAL; /* any non-zero value will do. */
}
else {
ret = $self->compare($self, other, &cmp);
/*
* Map less-than-zero to -1 and greater-than-zero to 1
* to avoid colliding with other errors.
*/
ret = (ret != 0) ? ret :
((cmp < 0) ? -1 : (cmp == 0) ? 0 : 1);
}
return (ret);
}
/* equals: special handling. */
int _equals(WT_CURSOR *other) {
int cmp = 0;
int ret = 0;
if (other == NULL) {
SWIG_Error(SWIG_NullReferenceError,
"in method 'Cursor_equals', "
"argument 1 of type 'struct __wt_cursor *' "
"is None");
ret = EINVAL; /* any non-zero value will do. */
}
else {
ret = $self->equals($self, other, &cmp);
if (ret == 0)
ret = cmp;
}
return (ret);
}
/* search_near: special handling. */
int _search_near() {
int cmp = 0;
int ret = $self->search_near($self, &cmp);
/*
* Map less-than-zero to -1 and greater-than-zero to 1 to avoid
* colliding with other errors.
*/
return ((ret != 0) ? ret : (cmp < 0) ? -1 : (cmp == 0) ? 0 : 1);
}
int _freecb() {
return (cursorFreeHandler($self));
}
%pythoncode %{
def get_key(self):
'''get_key(self) -> object
@copydoc WT_CURSOR::get_key
Returns only the first column.'''
k = self.get_keys()
if len(k) == 1:
return k[0]
return k
def get_keys(self):
'''get_keys(self) -> (object, ...)
@copydoc WT_CURSOR::get_key'''
if self.is_json:
return [self._get_json_key()]
elif self.is_column:
return [self._get_recno(),]
else:
return unpack(self.key_format, self._get_key())
def get_value(self):
'''get_value(self) -> object
@copydoc WT_CURSOR::get_value
Returns only the first column.'''
v = self.get_values()
if len(v) == 1:
return v[0]
return v
def get_values(self):
'''get_values(self) -> (object, ...)
@copydoc WT_CURSOR::get_value'''
if self.is_json:
return [self._get_json_value()]
else:
return unpack(self.value_format, self._get_value())
def set_key(self, *args):
'''set_key(self) -> None
@copydoc WT_CURSOR::set_key'''
if len(args) == 1 and type(args[0]) == tuple:
args = args[0]
if self.is_column:
self._set_recno(long(args[0]))
elif self.is_json:
self._set_key_str(args[0])
else:
# Keep the Python string pinned
self._key = pack(self.key_format, *args)
self._set_key(self._key)
def set_value(self, *args):
'''set_value(self) -> None
@copydoc WT_CURSOR::set_value'''
if self.is_json:
self._set_value_str(args[0])
else:
if len(args) == 1 and type(args[0]) == tuple:
args = args[0]
# Keep the Python string pinned
self._value = pack(self.value_format, *args)
self._set_value(self._value)
def __iter__(self):
'''Cursor objects support iteration, equivalent to calling
WT_CURSOR::next until it returns ::WT_NOTFOUND.'''
if not hasattr(self, '_iterable'):
self._iterable = IterableCursor(self)
return self._iterable
def __delitem__(self, key):
'''Python convenience for removing'''
self.set_key(key)
if self.remove() != 0:
raise KeyError
def __getitem__(self, key):
'''Python convenience for searching'''
self.set_key(key)
if self.search() != 0:
raise KeyError
return self.get_value()
def __setitem__(self, key, value):
'''Python convenience for inserting'''
self.set_key(key)
self.set_value(value)
if self.insert() != 0:
raise KeyError
%}
};
%extend __wt_session {
int _log_printf(const char *msg) {
return self->log_printf(self, "%s", msg);
}
int _freecb() {
return (sessionFreeHandler(self));
}
};
%extend __wt_connection {
int _freecb() {
return (0);
}
};
%{
int diagnostic_build() {
#ifdef HAVE_DIAGNOSTIC
return 1;
#else
return 0;
#endif
}
int verbose_build() {
#ifdef HAVE_VERBOSE
return 1;
#else
return 0;
#endif
}
%}
int diagnostic_build();
int verbose_build();
/* Remove / rename parts of the C API that we don't want in Python. */
%immutable __wt_cursor::session;
%immutable __wt_cursor::uri;
%ignore __wt_cursor::key_format;
%ignore __wt_cursor::value_format;
%immutable __wt_session::connection;
%immutable __wt_async_op::connection;
%immutable __wt_async_op::uri;
%immutable __wt_async_op::config;
%ignore __wt_async_op::key_format;
%ignore __wt_async_op::value_format;
%ignore __wt_async_callback;
%ignore __wt_collator;
%ignore __wt_compressor;
%ignore __wt_config_item;
%ignore __wt_data_source;
%ignore __wt_encryptor;
%ignore __wt_event_handler;
%ignore __wt_extractor;
%ignore __wt_item;
%ignore __wt_lsn;
%ignore __wt_connection::add_collator;
%ignore __wt_connection::add_compressor;
%ignore __wt_connection::add_data_source;
%ignore __wt_connection::add_encryptor;
%ignore __wt_connection::add_extractor;
%ignore __wt_connection::get_extension_api;
%ignore __wt_session::log_printf;
OVERRIDE_METHOD(__wt_session, WT_SESSION, log_printf, (self, msg))
%ignore wiredtiger_struct_pack;
%ignore wiredtiger_struct_size;
%ignore wiredtiger_struct_unpack;
%ignore wiredtiger_extension_init;
%ignore wiredtiger_extension_terminate;
/* Convert 'int *' to output args for wiredtiger_version */
%apply int *OUTPUT { int * };
%rename(AsyncOp) __wt_async_op;
%rename(Cursor) __wt_cursor;
%rename(Session) __wt_session;
%rename(Connection) __wt_connection;
%include "wiredtiger.h"
/* Add event handler support. */
%{
/* Write to and flush the stream. */
static int
writeToPythonStream(const char *streamname, const char *message)
{
PyObject *sys, *se, *write_method, *flush_method, *written,
*arglist, *arglist2;
char *msg;
int ret;
size_t msglen;
sys = NULL;
se = NULL;
write_method = flush_method = NULL;
written = NULL;
arglist = arglist2 = NULL;
msglen = strlen(message);
msg = malloc(msglen + 2);
strcpy(msg, message);
strcpy(&msg[msglen], "\n");
/* Acquire python Global Interpreter Lock. Otherwise can segfault. */
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
ret = 1;
if ((sys = PyImport_ImportModule("sys")) == NULL)
goto err;
if ((se = PyObject_GetAttrString(sys, streamname)) == NULL)
goto err;
if ((write_method = PyObject_GetAttrString(se, "write")) == NULL)
goto err;
if ((flush_method = PyObject_GetAttrString(se, "flush")) == NULL)
goto err;
if ((arglist = Py_BuildValue("(s)", msg)) == NULL)
goto err;
if ((arglist2 = Py_BuildValue("()")) == NULL)
goto err;
written = PyObject_CallObject(write_method, arglist);
(void)PyObject_CallObject(flush_method, arglist2);
ret = 0;
err: Py_XDECREF(arglist2);
Py_XDECREF(arglist);
Py_XDECREF(flush_method);
Py_XDECREF(write_method);
Py_XDECREF(se);
Py_XDECREF(sys);
Py_XDECREF(written);
/* Release python Global Interpreter Lock */
SWIG_PYTHON_THREAD_END_BLOCK;
if (msg)
free(msg);
return (ret);
}
static int
pythonErrorCallback(WT_EVENT_HANDLER *handler, WT_SESSION *session, int err,
const char *message)
{
return writeToPythonStream("stderr", message);
}
static int
pythonMessageCallback(WT_EVENT_HANDLER *handler, WT_SESSION *session,
const char *message)
{
return writeToPythonStream("stdout", message);
}
/* Zero out SWIG's pointer to the C object,
* equivalent to 'pyobj.this = None' in Python.
*/
static int
pythonClose(PY_CALLBACK *pcb)
{
int ret;
/*
* Ensure the global interpreter lock is held - so that Python
* doesn't shut down threads while we use them.
*/
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
ret = 0;
if (PyObject_SetAttrString(pcb->pyobj, "this", Py_None) == -1) {
SWIG_Error(SWIG_RuntimeError, "WT SetAttr failed");
ret = EINVAL; /* any non-zero value will do. */
}
Py_XDECREF(pcb->pyobj);
Py_XDECREF(pcb->pyasynccb);
SWIG_PYTHON_THREAD_END_BLOCK;
return (ret);
}
/* Session specific close handler. */
static int
sessionCloseHandler(WT_SESSION *session_arg)
{
int ret;
PY_CALLBACK *pcb;
WT_SESSION_IMPL *session;
ret = 0;
session = (WT_SESSION_IMPL *)session_arg;
pcb = (PY_CALLBACK *)session->lang_private;
session->lang_private = NULL;
if (pcb != NULL)
ret = pythonClose(pcb);
__wt_free(session, pcb);
return (ret);
}
/* Cursor specific close handler. */
static int
cursorCloseHandler(WT_CURSOR *cursor)
{
int ret;
PY_CALLBACK *pcb;
ret = 0;
pcb = (PY_CALLBACK *)cursor->lang_private;
cursor->lang_private = NULL;
if (pcb != NULL)
ret = pythonClose(pcb);
__wt_free((WT_SESSION_IMPL *)cursor->session, pcb);
return (ret);
}
/* Session specific close handler. */
static int
sessionFreeHandler(WT_SESSION *session_arg)
{
PY_CALLBACK *pcb;
WT_SESSION_IMPL *session;
session = (WT_SESSION_IMPL *)session_arg;
pcb = (PY_CALLBACK *)session->lang_private;
session->lang_private = NULL;
__wt_free(session, pcb);
return (0);
}
/* Cursor specific close handler. */
static int
cursorFreeHandler(WT_CURSOR *cursor)
{
PY_CALLBACK *pcb;
pcb = (PY_CALLBACK *)cursor->lang_private;
cursor->lang_private = NULL;
__wt_free((WT_SESSION_IMPL *)cursor->session, pcb);
return (0);
}
static int
pythonCloseCallback(WT_EVENT_HANDLER *handler, WT_SESSION *session,
WT_CURSOR *cursor)
{
int ret;
WT_UNUSED(handler);
if (cursor != NULL)
ret = cursorCloseHandler(cursor);
else
ret = sessionCloseHandler(session);
return (ret);
}
static WT_EVENT_HANDLER pyApiEventHandler = {
pythonErrorCallback, pythonMessageCallback, NULL, pythonCloseCallback
};
%}
/* Add async callback support. */
%{
static int
pythonAsyncCallback(WT_ASYNC_CALLBACK *cb, WT_ASYNC_OP *asyncop, int opret,
uint32_t flags)
{
int ret, t_ret;
PY_CALLBACK *pcb;
PyObject *arglist, *notify_method, *pyresult;
WT_ASYNC_OP_IMPL *op;
WT_SESSION_IMPL *session;
/*
* Ensure the global interpreter lock is held since we'll be
* making Python calls now.
*/
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
op = (WT_ASYNC_OP_IMPL *)asyncop;
session = O2S(op);
pcb = (PY_CALLBACK *)asyncop->c.lang_private;
asyncop->c.lang_private = NULL;
ret = 0;
if (pcb->pyasynccb == NULL)
goto err;
if ((arglist = Py_BuildValue("(Oii)", pcb->pyobj,
opret, flags)) == NULL)
goto err;
if ((notify_method = PyObject_GetAttrString(pcb->pyasynccb,
"notify")) == NULL)
goto err;
pyresult = PyEval_CallObject(notify_method, arglist);
if (pyresult == NULL || !PyArg_Parse(pyresult, "i", &ret))
goto err;
if (0) {
if (ret == 0)
ret = EINVAL;
err: __wt_err(session, ret, "python async callback error");
}
Py_XDECREF(pyresult);
Py_XDECREF(notify_method);
Py_XDECREF(arglist);
SWIG_PYTHON_THREAD_END_BLOCK;
if (pcb != NULL) {
if ((t_ret = pythonClose(pcb) != 0) && ret == 0)
ret = t_ret;
}
__wt_free(session, pcb);
if (ret == 0 && (opret == 0 || opret == WT_NOTFOUND))
return (0);
else
return (1);
}
static WT_ASYNC_CALLBACK pyApiAsyncCallback = { pythonAsyncCallback };
%}
%pythoncode %{
class stat:
'''keys for statistics cursors'''
class conn:
'''keys for cursors on connection statistics'''
pass
class dsrc:
'''keys for cursors on data source statistics'''
pass
## @}
import sys
# All names starting with 'WT_STAT_DSRC_' are renamed to
# the wiredtiger.stat.dsrc class, those starting with 'WT_STAT_CONN' are
# renamed to wiredtiger.stat.conn class.
def _rename_with_prefix(prefix, toclass):
curmodule = sys.modules[__name__]
for name in dir(curmodule):
if name.startswith(prefix):
shortname = name[len(prefix):].lower()
setattr(toclass, shortname, getattr(curmodule, name))
delattr(curmodule, name)
_rename_with_prefix('WT_STAT_CONN_', stat.conn)
_rename_with_prefix('WT_STAT_DSRC_', stat.dsrc)
del _rename_with_prefix
%}