summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/cextension/resultproxy.c
diff options
context:
space:
mode:
authorFederico Caselli <cfederico87@gmail.com>2021-01-01 16:09:01 +0100
committerFederico Caselli <cfederico87@gmail.com>2021-12-17 21:29:05 +0100
commit76fa211620de167b76846f0e5db5b64b8756ad48 (patch)
treec435dbf6585b3758dc78ee82bf114e162a25d0e1 /lib/sqlalchemy/cextension/resultproxy.c
parent3543fcc9c9601e81560d055ceadaea05c75815c0 (diff)
downloadsqlalchemy-workflow_test_cython.tar.gz
Replace c extension with cython versions.workflow_test_cython
Re-implement c version immutabledict / processors / resultproxy / utils with cython. Performance is in general in par or better than the c version Added a collection module that has cython version of OrderedSet and IdentitySet Added a new test/perf file to compare the implementations. Run ``python test/perf/compiled_extensions.py all`` to execute the comparison test. See results here: https://docs.google.com/document/d/1nOcDGojHRtXEkuy4vNXcW_XOJd9gqKhSeALGG3kYr6A/edit?usp=sharing Fixes: #7256 Change-Id: I2930ef1894b5048210384728118e586e813f6a76 Signed-off-by: Federico Caselli <cfederico87@gmail.com>
Diffstat (limited to 'lib/sqlalchemy/cextension/resultproxy.c')
-rw-r--r--lib/sqlalchemy/cextension/resultproxy.c1033
1 files changed, 0 insertions, 1033 deletions
diff --git a/lib/sqlalchemy/cextension/resultproxy.c b/lib/sqlalchemy/cextension/resultproxy.c
deleted file mode 100644
index 99b2d36f3..000000000
--- a/lib/sqlalchemy/cextension/resultproxy.c
+++ /dev/null
@@ -1,1033 +0,0 @@
-/*
-resultproxy.c
-Copyright (C) 2010-2021 the SQLAlchemy authors and contributors <see AUTHORS file>
-Copyright (C) 2010-2011 Gaetan de Menten gdementen@gmail.com
-
-This module is part of SQLAlchemy and is released under
-the MIT License: https://www.opensource.org/licenses/mit-license.php
-*/
-
-#include <Python.h>
-
-#define MODULE_NAME "cresultproxy"
-#define MODULE_DOC "Module containing C versions of core ResultProxy classes."
-
-#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
-typedef int Py_ssize_t;
-#define PY_SSIZE_T_MAX INT_MAX
-#define PY_SSIZE_T_MIN INT_MIN
-typedef Py_ssize_t (*lenfunc)(PyObject *);
-#define PyInt_FromSsize_t(x) PyInt_FromLong(x)
-typedef intargfunc ssizeargfunc;
-#endif
-
-#if PY_MAJOR_VERSION < 3
-
-// new typedef in Python 3
-typedef long Py_hash_t;
-
-// from pymacro.h, new in Python 3.2
-#if defined(__GNUC__) || defined(__clang__)
-# define Py_UNUSED(name) _unused_ ## name __attribute__((unused))
-#else
-# define Py_UNUSED(name) _unused_ ## name
-#endif
-
-#endif
-
-
-/***********
- * Structs *
- ***********/
-
-typedef struct {
- PyObject_HEAD
- PyObject *parent;
- PyObject *row;
- PyObject *keymap;
- long key_style;
-} BaseRow;
-
-
-static PyObject *sqlalchemy_engine_row = NULL;
-static PyObject *sqlalchemy_engine_result = NULL;
-
-
-static int KEY_INTEGER_ONLY = 0;
-static int KEY_OBJECTS_ONLY = 1;
-
-/****************
- * BaseRow *
- ****************/
-
-static PyObject *
-safe_rowproxy_reconstructor(PyObject *self, PyObject *args)
-{
- PyObject *cls, *state, *tmp;
- BaseRow *obj;
-
- if (!PyArg_ParseTuple(args, "OO", &cls, &state))
- return NULL;
-
- obj = (BaseRow *)PyObject_CallMethod(cls, "__new__", "O", cls);
- if (obj == NULL)
- return NULL;
-
- tmp = PyObject_CallMethod((PyObject *)obj, "__setstate__", "O", state);
- if (tmp == NULL) {
- Py_DECREF(obj);
- return NULL;
- }
- Py_DECREF(tmp);
-
- if (obj->parent == NULL || obj->row == NULL ||
- obj->keymap == NULL) {
- PyErr_SetString(PyExc_RuntimeError,
- "__setstate__ for BaseRow subclasses must set values "
- "for parent, row, and keymap");
- Py_DECREF(obj);
- return NULL;
- }
-
- return (PyObject *)obj;
-}
-
-static int
-BaseRow_init(BaseRow *self, PyObject *args, PyObject *kwds)
-{
- PyObject *parent, *keymap, *row, *processors, *key_style;
- Py_ssize_t num_values, num_processors;
- PyObject **valueptr, **funcptr, **resultptr;
- PyObject *func, *result, *processed_value, *values_fastseq;
-
- if (!PyArg_UnpackTuple(args, "BaseRow", 5, 5,
- &parent, &processors, &keymap, &key_style, &row))
- return -1;
-
- Py_INCREF(parent);
- self->parent = parent;
-
- values_fastseq = PySequence_Fast(row, "row must be a sequence");
- if (values_fastseq == NULL)
- return -1;
-
- num_values = PySequence_Length(values_fastseq);
-
-
- if (processors != Py_None) {
- num_processors = PySequence_Size(processors);
- if (num_values != num_processors) {
- PyErr_Format(PyExc_RuntimeError,
- "number of values in row (%d) differ from number of column "
- "processors (%d)",
- (int)num_values, (int)num_processors);
- return -1;
- }
-
- } else {
- num_processors = -1;
- }
-
- result = PyTuple_New(num_values);
- if (result == NULL)
- return -1;
-
- if (num_processors != -1) {
- valueptr = PySequence_Fast_ITEMS(values_fastseq);
- funcptr = PySequence_Fast_ITEMS(processors);
- resultptr = PySequence_Fast_ITEMS(result);
- while (--num_values >= 0) {
- func = *funcptr;
- if (func != Py_None) {
- processed_value = PyObject_CallFunctionObjArgs(
- func, *valueptr, NULL);
- if (processed_value == NULL) {
- Py_DECREF(values_fastseq);
- Py_DECREF(result);
- return -1;
- }
- *resultptr = processed_value;
- } else {
- Py_INCREF(*valueptr);
- *resultptr = *valueptr;
- }
- valueptr++;
- funcptr++;
- resultptr++;
- }
- } else {
- valueptr = PySequence_Fast_ITEMS(values_fastseq);
- resultptr = PySequence_Fast_ITEMS(result);
- while (--num_values >= 0) {
- Py_INCREF(*valueptr);
- *resultptr = *valueptr;
- valueptr++;
- resultptr++;
- }
- }
-
- Py_DECREF(values_fastseq);
- self->row = result;
-
- if (!PyDict_CheckExact(keymap)) {
- PyErr_SetString(PyExc_TypeError, "keymap must be a dict");
- return -1;
- }
- Py_INCREF(keymap);
- self->keymap = keymap;
- self->key_style = PyLong_AsLong(key_style);
-
- // observation: because we have not implemented our own new method,
- // cPython is apparently already calling PyObject_GC_Track for us.
- // We assume it also called PyObject_GC_New since prior to #5348 we
- // were already relying upon it to call PyObject_New, and we have now
- // set Py_TPFLAGS_HAVE_GC.
-
- return 0;
-}
-
-static int
-BaseRow_traverse(BaseRow *self, visitproc visit, void *arg)
-{
- Py_VISIT(self->parent);
- Py_VISIT(self->row);
- Py_VISIT(self->keymap);
- return 0;
-}
-
-/* We need the reduce method because otherwise the default implementation
- * does very weird stuff for pickle protocol 0 and 1. It calls
- * BaseRow.__new__(Row_instance) upon *pickling*.
- */
-static PyObject *
-BaseRow_reduce(PyObject *self)
-{
- PyObject *method, *state;
- PyObject *module, *reconstructor, *cls;
-
- method = PyObject_GetAttrString(self, "__getstate__");
- if (method == NULL)
- return NULL;
-
- state = PyObject_CallObject(method, NULL);
- Py_DECREF(method);
- if (state == NULL)
- return NULL;
-
- if (sqlalchemy_engine_row == NULL) {
- module = PyImport_ImportModule("sqlalchemy.engine.row");
- if (module == NULL)
- return NULL;
- sqlalchemy_engine_row = module;
- }
-
- reconstructor = PyObject_GetAttrString(sqlalchemy_engine_row, "rowproxy_reconstructor");
- if (reconstructor == NULL) {
- Py_DECREF(state);
- return NULL;
- }
-
- cls = PyObject_GetAttrString(self, "__class__");
- if (cls == NULL) {
- Py_DECREF(reconstructor);
- Py_DECREF(state);
- return NULL;
- }
-
- return Py_BuildValue("(N(NN))", reconstructor, cls, state);
-}
-
-static PyObject *
-BaseRow_filter_on_values(BaseRow *self, PyObject *filters)
-{
- PyObject *module, *row_class, *new_obj, *key_style;
-
- if (sqlalchemy_engine_row == NULL) {
- module = PyImport_ImportModule("sqlalchemy.engine.row");
- if (module == NULL)
- return NULL;
- sqlalchemy_engine_row = module;
- }
-
- // TODO: do we want to get self.__class__ instead here? I'm not sure
- // how to use METH_VARARGS and then also get the BaseRow struct
- // at the same time
- row_class = PyObject_GetAttrString(sqlalchemy_engine_row, "Row");
-
- key_style = PyLong_FromLong(self->key_style);
-
- new_obj = PyObject_CallFunction(
- row_class, "OOOOO", self->parent, filters, self->keymap,
- key_style, self->row);
- Py_DECREF(key_style);
- Py_DECREF(row_class);
- if (new_obj == NULL) {
- return NULL;
- }
-
- return new_obj;
-
-}
-
-static void
-BaseRow_dealloc(BaseRow *self)
-{
- PyObject_GC_UnTrack(self);
- Py_XDECREF(self->parent);
- Py_XDECREF(self->row);
- Py_XDECREF(self->keymap);
- PyObject_GC_Del(self);
-
-}
-
-static PyObject *
-BaseRow_valuescollection(PyObject *values, int astuple)
-{
- PyObject *result;
-
- if (astuple) {
- result = PySequence_Tuple(values);
- } else {
- result = PySequence_List(values);
- }
- if (result == NULL)
- return NULL;
-
- return result;
-}
-
-static PyListObject *
-BaseRow_values_impl(BaseRow *self)
-{
- return (PyListObject *)BaseRow_valuescollection(self->row, 0);
-}
-
-static Py_hash_t
-BaseRow_hash(BaseRow *self)
-{
- return PyObject_Hash(self->row);
-}
-
-static PyObject *
-BaseRow_iter(BaseRow *self)
-{
- PyObject *values, *result;
-
- values = BaseRow_valuescollection(self->row, 1);
- if (values == NULL)
- return NULL;
-
- result = PyObject_GetIter(values);
- Py_DECREF(values);
- if (result == NULL)
- return NULL;
-
- return result;
-}
-
-static Py_ssize_t
-BaseRow_length(BaseRow *self)
-{
- return PySequence_Length(self->row);
-}
-
-static PyObject *
-BaseRow_getitem(BaseRow *self, Py_ssize_t i)
-{
- PyObject *value;
- PyObject *row;
-
- row = self->row;
-
- // row is a Tuple
- value = PyTuple_GetItem(row, i);
-
- if (value == NULL)
- return NULL;
-
- Py_INCREF(value);
-
- return value;
-}
-
-static PyObject *
-BaseRow_getitem_by_object(BaseRow *self, PyObject *key, int asmapping)
-{
- PyObject *record, *indexobject;
- long index;
- int key_fallback = 0;
-
- // we want to raise TypeError for slice access on a mapping.
- // Py3 will do this with PyDict_GetItemWithError, Py2 will do it
- // with PyObject_GetItem. However in the Python2 case the object
- // protocol gets in the way for reasons not entirely clear, so
- // detect slice we have a key error and raise directly.
-
- record = PyDict_GetItem((PyObject *)self->keymap, key);
-
- if (record == NULL) {
- if (PySlice_Check(key)) {
- PyErr_Format(PyExc_TypeError, "can't use slices for mapping access");
- return NULL;
- }
- record = PyObject_CallMethod(self->parent, "_key_fallback",
- "OO", key, Py_None);
- if (record == NULL)
- return NULL;
-
- key_fallback = 1; // boolean to indicate record is a new reference
- }
-
- indexobject = PyTuple_GetItem(record, 0);
- if (indexobject == NULL)
- return NULL;
-
- if (key_fallback) {
- Py_DECREF(record);
- }
-
- if (indexobject == Py_None) {
- PyObject *tmp;
-
- tmp = PyObject_CallMethod(self->parent, "_raise_for_ambiguous_column_name", "(O)", record);
- if (tmp == NULL) {
- return NULL;
- }
- Py_DECREF(tmp);
-
- return NULL;
- }
-
-#if PY_MAJOR_VERSION >= 3
- index = PyLong_AsLong(indexobject);
-#else
- index = PyInt_AsLong(indexobject);
-#endif
- if ((index == -1) && PyErr_Occurred())
- /* -1 can be either the actual value, or an error flag. */
- return NULL;
-
- return BaseRow_getitem(self, index);
-
-}
-
-static PyObject *
-BaseRow_subscript_impl(BaseRow *self, PyObject *key, int asmapping)
-{
- PyObject *values;
- PyObject *result;
- long index;
- PyObject *tmp;
-
-#if PY_MAJOR_VERSION < 3
- if (PyInt_CheckExact(key)) {
- if (self->key_style == KEY_OBJECTS_ONLY) {
- // TODO: being very lazy with error catching here
- PyErr_Format(PyExc_KeyError, "%s", PyString_AsString(PyObject_Repr(key)));
- return NULL;
- }
- index = PyInt_AS_LONG(key);
-
- // support negative indexes. We can also call PySequence_GetItem,
- // but here we can stay with the simpler tuple protocol
- // rather than the sequence protocol which has to check for
- // __getitem__ methods etc.
- if (index < 0)
- index += (long)BaseRow_length(self);
- return BaseRow_getitem(self, index);
- } else
-#endif
-
- if (PyLong_CheckExact(key)) {
- if (self->key_style == KEY_OBJECTS_ONLY) {
-#if PY_MAJOR_VERSION < 3
- // TODO: being very lazy with error catching here
- PyErr_Format(PyExc_KeyError, "%s", PyString_AsString(PyObject_Repr(key)));
-#else
- PyErr_Format(PyExc_KeyError, "%R", key);
-#endif
- return NULL;
- }
- index = PyLong_AsLong(key);
- if ((index == -1) && PyErr_Occurred() != NULL)
- /* -1 can be either the actual value, or an error flag. */
- return NULL;
-
- // support negative indexes. We can also call PySequence_GetItem,
- // but here we can stay with the simpler tuple protocol
- // rather than the sequence protocol which has to check for
- // __getitem__ methods etc.
- if (index < 0)
- index += (long)BaseRow_length(self);
- return BaseRow_getitem(self, index);
-
- } else if (PySlice_Check(key) && self->key_style != KEY_OBJECTS_ONLY) {
- values = PyObject_GetItem(self->row, key);
- if (values == NULL)
- return NULL;
-
- result = BaseRow_valuescollection(values, 1);
- Py_DECREF(values);
- return result;
- }
- else if (!asmapping && self->key_style == KEY_INTEGER_ONLY) {
- tmp = PyObject_CallMethod(self->parent, "_raise_for_nonint", "(O)", key);
- if (tmp == NULL) {
- return NULL;
- }
- Py_DECREF(tmp);
- return NULL;
- } else {
- return BaseRow_getitem_by_object(self, key, asmapping);
- }
-}
-
-static PyObject *
-BaseRow_subscript(BaseRow *self, PyObject *key)
-{
- return BaseRow_subscript_impl(self, key, 0);
-}
-
-static PyObject *
-BaseRow_subscript_mapping(BaseRow *self, PyObject *key)
-{
- if (self->key_style == KEY_INTEGER_ONLY) {
- return BaseRow_subscript_impl(self, key, 0);
- }
- else {
- return BaseRow_subscript_impl(self, key, 1);
- }
-}
-
-
-static PyObject *
-BaseRow_getattro(BaseRow *self, PyObject *name)
-{
- PyObject *tmp;
-#if PY_MAJOR_VERSION >= 3
- PyObject *err_bytes;
-#endif
-
- if (!(tmp = PyObject_GenericGetAttr((PyObject *)self, name))) {
- if (!PyErr_ExceptionMatches(PyExc_AttributeError))
- return NULL;
- PyErr_Clear();
- }
- else
- return tmp;
-
- tmp = BaseRow_subscript_impl(self, name, 1);
-
- if (tmp == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
-
-#if PY_MAJOR_VERSION >= 3
- err_bytes = PyUnicode_AsASCIIString(name);
- if (err_bytes == NULL)
- return NULL;
- PyErr_Format(
- PyExc_AttributeError,
- "Could not locate column in row for column '%.200s'",
- PyBytes_AS_STRING(err_bytes)
- );
-#else
- PyErr_Format(
- PyExc_AttributeError,
- "Could not locate column in row for column '%.200s'",
- PyString_AsString(name)
- );
-#endif
- return NULL;
- }
- return tmp;
-}
-
-/***********************
- * getters and setters *
- ***********************/
-
-static PyObject *
-BaseRow_getparent(BaseRow *self, void *closure)
-{
- Py_INCREF(self->parent);
- return self->parent;
-}
-
-static int
-BaseRow_setparent(BaseRow *self, PyObject *value, void *closure)
-{
- PyObject *module, *cls;
-
- if (value == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Cannot delete the 'parent' attribute");
- return -1;
- }
-
- if (sqlalchemy_engine_result == NULL) {
- module = PyImport_ImportModule("sqlalchemy.engine.result");
- if (module == NULL)
- return -1;
- sqlalchemy_engine_result = module;
- }
-
- cls = PyObject_GetAttrString(sqlalchemy_engine_result, "ResultMetaData");
- if (cls == NULL)
- return -1;
-
- if (PyObject_IsInstance(value, cls) != 1) {
- PyErr_SetString(PyExc_TypeError,
- "The 'parent' attribute value must be an instance of "
- "ResultMetaData");
- return -1;
- }
- Py_DECREF(cls);
- Py_XDECREF(self->parent);
- Py_INCREF(value);
- self->parent = value;
-
- return 0;
-}
-
-static PyObject *
-BaseRow_getrow(BaseRow *self, void *closure)
-{
- Py_INCREF(self->row);
- return self->row;
-}
-
-static int
-BaseRow_setrow(BaseRow *self, PyObject *value, void *closure)
-{
- if (value == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Cannot delete the 'row' attribute");
- return -1;
- }
-
- if (!PySequence_Check(value)) {
- PyErr_SetString(PyExc_TypeError,
- "The 'row' attribute value must be a sequence");
- return -1;
- }
-
- Py_XDECREF(self->row);
- Py_INCREF(value);
- self->row = value;
-
- return 0;
-}
-
-
-
-static PyObject *
-BaseRow_getkeymap(BaseRow *self, void *closure)
-{
- Py_INCREF(self->keymap);
- return self->keymap;
-}
-
-static int
-BaseRow_setkeymap(BaseRow *self, PyObject *value, void *closure)
-{
- if (value == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Cannot delete the 'keymap' attribute");
- return -1;
- }
-
- if (!PyDict_CheckExact(value)) {
- PyErr_SetString(PyExc_TypeError,
- "The 'keymap' attribute value must be a dict");
- return -1;
- }
-
- Py_XDECREF(self->keymap);
- Py_INCREF(value);
- self->keymap = value;
-
- return 0;
-}
-
-static PyObject *
-BaseRow_getkeystyle(BaseRow *self, void *closure)
-{
- PyObject *result;
-
- result = PyLong_FromLong(self->key_style);
- Py_INCREF(result);
- return result;
-}
-
-
-static int
-BaseRow_setkeystyle(BaseRow *self, PyObject *value, void *closure)
-{
- if (value == NULL) {
-
- PyErr_SetString(
- PyExc_TypeError,
- "Cannot delete the 'key_style' attribute");
- return -1;
- }
-
- if (!PyLong_CheckExact(value)) {
- PyErr_SetString(
- PyExc_TypeError,
- "The 'key_style' attribute value must be an integer");
- return -1;
- }
-
- self->key_style = PyLong_AsLong(value);
-
- return 0;
-}
-
-static PyGetSetDef BaseRow_getseters[] = {
- {"_parent",
- (getter)BaseRow_getparent, (setter)BaseRow_setparent,
- "ResultMetaData",
- NULL},
- {"_data",
- (getter)BaseRow_getrow, (setter)BaseRow_setrow,
- "processed data list",
- NULL},
- {"_keymap",
- (getter)BaseRow_getkeymap, (setter)BaseRow_setkeymap,
- "Key to (obj, index) dict",
- NULL},
- {"_key_style",
- (getter)BaseRow_getkeystyle, (setter)BaseRow_setkeystyle,
- "Return the key style",
- NULL},
- {NULL}
-};
-
-static PyMethodDef BaseRow_methods[] = {
- {"_values_impl", (PyCFunction)BaseRow_values_impl, METH_NOARGS,
- "Return the values represented by this BaseRow as a list."},
- {"__reduce__", (PyCFunction)BaseRow_reduce, METH_NOARGS,
- "Pickle support method."},
- {"_get_by_key_impl", (PyCFunction)BaseRow_subscript, METH_O,
- "implement mapping-like getitem as well as sequence getitem"},
- {"_get_by_key_impl_mapping", (PyCFunction)BaseRow_subscript_mapping, METH_O,
- "implement mapping-like getitem as well as sequence getitem"},
- {"_filter_on_values", (PyCFunction)BaseRow_filter_on_values, METH_O,
- "return a new Row with per-value filters applied to columns"},
-
- {NULL} /* Sentinel */
-};
-
-// currently, the sq_item hook is not used by Python except for slices,
-// because we also implement subscript_mapping which seems to intercept
-// integers. Ideally, when there
-// is a complete separation of "row" from "mapping", we can make
-// two separate types here so that one has only sq_item and the other
-// has only mp_subscript.
-static PySequenceMethods BaseRow_as_sequence = {
- (lenfunc)BaseRow_length, /* sq_length */
- 0, /* sq_concat */
- 0, /* sq_repeat */
- (ssizeargfunc)BaseRow_getitem, /* sq_item */
- 0, /* sq_slice */
- 0, /* sq_ass_item */
- 0, /* sq_ass_slice */
- 0, /* sq_contains */
- 0, /* sq_inplace_concat */
- 0, /* sq_inplace_repeat */
-};
-
-static PyMappingMethods BaseRow_as_mapping = {
- (lenfunc)BaseRow_length, /* mp_length */
- (binaryfunc)BaseRow_subscript_mapping, /* mp_subscript */
- 0 /* mp_ass_subscript */
-};
-
-static PyTypeObject BaseRowType = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "sqlalchemy.cresultproxy.BaseRow", /* tp_name */
- sizeof(BaseRow), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)BaseRow_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- &BaseRow_as_sequence, /* tp_as_sequence */
- &BaseRow_as_mapping, /* tp_as_mapping */
- (hashfunc)BaseRow_hash, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- (getattrofunc)BaseRow_getattro,/* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- "BaseRow is a abstract base class for Row", /* tp_doc */
- (traverseproc)BaseRow_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- (getiterfunc)BaseRow_iter, /* tp_iter */
- 0, /* tp_iternext */
- BaseRow_methods, /* tp_methods */
- 0, /* tp_members */
- BaseRow_getseters, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)BaseRow_init, /* tp_init */
- 0, /* tp_alloc */
- 0 /* tp_new */
-};
-
-
-
-/* _tuplegetter function ************************************************/
-/*
-retrieves segments of a row as tuples.
-
-mostly like operator.itemgetter but calls a fixed method instead,
-returns tuple every time.
-
-*/
-
-typedef struct {
- PyObject_HEAD
- Py_ssize_t nitems;
- PyObject *item;
-} tuplegetterobject;
-
-static PyTypeObject tuplegetter_type;
-
-static PyObject *
-tuplegetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- tuplegetterobject *tg;
- PyObject *item;
- Py_ssize_t nitems;
-
- if (!_PyArg_NoKeywords("tuplegetter", kwds))
- return NULL;
-
- nitems = PyTuple_GET_SIZE(args);
- item = args;
-
- tg = PyObject_GC_New(tuplegetterobject, &tuplegetter_type);
- if (tg == NULL)
- return NULL;
-
- Py_INCREF(item);
- tg->item = item;
- tg->nitems = nitems;
- PyObject_GC_Track(tg);
- return (PyObject *)tg;
-}
-
-static void
-tuplegetter_dealloc(tuplegetterobject *tg)
-{
- PyObject_GC_UnTrack(tg);
- Py_XDECREF(tg->item);
- PyObject_GC_Del(tg);
-}
-
-static int
-tuplegetter_traverse(tuplegetterobject *tg, visitproc visit, void *arg)
-{
- Py_VISIT(tg->item);
- return 0;
-}
-
-static PyObject *
-tuplegetter_call(tuplegetterobject *tg, PyObject *args, PyObject *kw)
-{
- PyObject *row_or_tuple, *result;
- Py_ssize_t i, nitems=tg->nitems;
- int has_row_method;
-
- assert(PyTuple_CheckExact(args));
-
- // this is a tuple, however if its a BaseRow subclass we want to
- // call specific methods to bypass the pure python LegacyRow.__getitem__
- // method for now
- row_or_tuple = PyTuple_GET_ITEM(args, 0);
-
- has_row_method = PyObject_HasAttrString(row_or_tuple, "_get_by_key_impl_mapping");
-
- assert(PyTuple_Check(tg->item));
- assert(PyTuple_GET_SIZE(tg->item) == nitems);
-
- result = PyTuple_New(nitems);
- if (result == NULL)
- return NULL;
-
- for (i=0 ; i < nitems ; i++) {
- PyObject *item, *val;
- item = PyTuple_GET_ITEM(tg->item, i);
-
- if (has_row_method) {
- val = PyObject_CallMethod(row_or_tuple, "_get_by_key_impl_mapping", "O", item);
- }
- else {
- val = PyObject_GetItem(row_or_tuple, item);
- }
-
- if (val == NULL) {
- Py_DECREF(result);
- return NULL;
- }
- PyTuple_SET_ITEM(result, i, val);
- }
- return result;
-}
-
-static PyObject *
-tuplegetter_repr(tuplegetterobject *tg)
-{
- PyObject *repr;
- const char *reprfmt;
-
- int status = Py_ReprEnter((PyObject *)tg);
- if (status != 0) {
- if (status < 0)
- return NULL;
- return PyUnicode_FromFormat("%s(...)", Py_TYPE(tg)->tp_name);
- }
-
- reprfmt = tg->nitems == 1 ? "%s(%R)" : "%s%R";
- repr = PyUnicode_FromFormat(reprfmt, Py_TYPE(tg)->tp_name, tg->item);
- Py_ReprLeave((PyObject *)tg);
- return repr;
-}
-
-static PyObject *
-tuplegetter_reduce(tuplegetterobject *tg, PyObject *Py_UNUSED(ignored))
-{
- return PyTuple_Pack(2, Py_TYPE(tg), tg->item);
-}
-
-PyDoc_STRVAR(reduce_doc, "Return state information for pickling");
-
-static PyMethodDef tuplegetter_methods[] = {
- {"__reduce__", (PyCFunction)tuplegetter_reduce, METH_NOARGS,
- reduce_doc},
- {NULL}
-};
-
-PyDoc_STRVAR(tuplegetter_doc,
-"tuplegetter(item, ...) --> tuplegetter object\n\
-\n\
-Return a callable object that fetches the given item(s) from its operand\n\
-and returns them as a tuple.\n");
-
-static PyTypeObject tuplegetter_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "sqlalchemy.engine.util.tuplegetter", /* tp_name */
- sizeof(tuplegetterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)tuplegetter_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)tuplegetter_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- (ternaryfunc)tuplegetter_call, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- tuplegetter_doc, /* tp_doc */
- (traverseproc)tuplegetter_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- tuplegetter_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- tuplegetter_new, /* tp_new */
- 0, /* tp_free */
-};
-
-
-
-static PyMethodDef module_methods[] = {
- {"safe_rowproxy_reconstructor", safe_rowproxy_reconstructor, METH_VARARGS,
- "reconstruct a Row instance from its pickled form."},
- {NULL, NULL, 0, NULL} /* Sentinel */
-};
-
-#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
-#define PyMODINIT_FUNC void
-#endif
-
-
-#if PY_MAJOR_VERSION >= 3
-
-static struct PyModuleDef module_def = {
- PyModuleDef_HEAD_INIT,
- MODULE_NAME,
- MODULE_DOC,
- -1,
- module_methods
-};
-
-#define INITERROR return NULL
-
-PyMODINIT_FUNC
-PyInit_cresultproxy(void)
-
-#else
-
-#define INITERROR return
-
-PyMODINIT_FUNC
-initcresultproxy(void)
-
-#endif
-
-{
- PyObject *m;
-
- BaseRowType.tp_new = PyType_GenericNew;
- if (PyType_Ready(&BaseRowType) < 0)
- INITERROR;
-
- if (PyType_Ready(&tuplegetter_type) < 0)
- INITERROR;
-
-#if PY_MAJOR_VERSION >= 3
- m = PyModule_Create(&module_def);
-#else
- m = Py_InitModule3(MODULE_NAME, module_methods, MODULE_DOC);
-#endif
- if (m == NULL)
- INITERROR;
-
- Py_INCREF(&BaseRowType);
- PyModule_AddObject(m, "BaseRow", (PyObject *)&BaseRowType);
-
- Py_INCREF(&tuplegetter_type);
- PyModule_AddObject(m, "tuplegetter", (PyObject *)&tuplegetter_type);
-
-#if PY_MAJOR_VERSION >= 3
- return m;
-#endif
-}