summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-08-29 19:07:27 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2014-08-29 19:07:27 -0400
commit5eff49e08d547536a0ea87be2a64d8aed2335c61 (patch)
tree70f309c2a32bc56fa394e5e2f2f5a874fd8d68c5
parentab5a1a7f4a87e6e74335986a571b03e2fb6c15ee (diff)
downloadsqlalchemy-attempt_c_loading.tar.gz
- attempt to write part of _populate_full in C. Performance differenceattempt_c_loading
is pretty much zippo! 1%. to use C code here would require a much more fundamental rewrite of everything so that we aren't just calling python functions.
-rw-r--r--lib/sqlalchemy/cextension/loader.c256
-rw-r--r--lib/sqlalchemy/orm/loading.py3
-rw-r--r--setup.py4
3 files changed, 261 insertions, 2 deletions
diff --git a/lib/sqlalchemy/cextension/loader.c b/lib/sqlalchemy/cextension/loader.c
new file mode 100644
index 000000000..743d61632
--- /dev/null
+++ b/lib/sqlalchemy/cextension/loader.c
@@ -0,0 +1,256 @@
+/*
+loader.c
+Copyright (C) 2014 the SQLAlchemy authors and contributors <see AUTHORS file>
+
+This module is part of SQLAlchemy and is released under
+the MIT License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+#include <Python.h>
+#include <stdio.h>
+
+#define MODULE_NAME "cloader"
+#define MODULE_DOC "Module containing C versions of ORM loading."
+
+
+static PyObject * populate_full(PyObject *self, PyObject *args) {
+
+ PyObject *context;
+ PyObject *load_path;
+ PyObject *row;
+ PyObject *state;
+ PyObject *dict_;
+ PyObject *isnew;
+ PyObject *loaded_instance;
+ PyObject *populate_existing;
+ PyObject *populators;
+
+ int isnew_bool;
+ PyObject *runid;
+ PyObject *propagate_options;
+ int propagate_options_bool;
+ PyObject *load_options;
+ int load_options_bool;
+
+ PyObject *populator_collection;
+
+ PyObject *seq;
+ PyObject *seq_item;
+ PyObject *key;
+ PyObject *getter;
+ int len;
+ int i;
+
+ PyObject *arglist;
+ PyObject *retvalue;
+
+ if (!PyArg_UnpackTuple(args, "populate_full", 9, 9,
+ &context, &load_path, &row,
+ &state, &dict_, &isnew,
+ &loaded_instance, &populate_existing,
+ &populators
+ )) {
+ return NULL;
+ }
+
+
+ isnew_bool = PyObject_IsTrue(isnew);
+ if (isnew_bool == -1) {
+ return NULL;
+ }
+ /* if isnew:
+ # first time we are seeing a row with this identity.
+ */
+
+ else if (isnew_bool == 1) {
+
+ /* state.runid = context.runid */
+
+ runid = PyObject_GetAttrString(context, "runid");
+ if (runid == NULL)
+ return NULL;
+
+ if (PyObject_SetAttrString(state, "runid", runid) == -1) {
+ Py_DECREF(runid);
+ return NULL;
+ }
+
+ /* if context.propagate_options:
+ state.load_options = context.propagate_options */
+
+ propagate_options = PyObject_GetAttrString(context, "propagate_options");
+ if (propagate_options == NULL)
+ return NULL;
+ propagate_options_bool = PyObject_IsTrue(propagate_options);
+ if (propagate_options_bool == -1)
+ return NULL;
+ else if (propagate_options_bool == 1) {
+ if (PyObject_SetAttrString(state, "load_options", propagate_options) == -1) {
+ Py_DECREF(propagate_options);
+ return NULL;
+ }
+ }
+ else {
+ Py_DECREF(propagate_options);
+ }
+
+ /* if state.load_options:
+ state.load_path = load_path */
+
+ load_options = PyObject_GetAttrString(state, "load_options");
+ if (load_options == NULL)
+ return NULL;
+ load_options_bool = PyObject_IsTrue(load_options);
+ if (load_options_bool == -1)
+ return NULL;
+ else if (load_options_bool == 1) {
+ if (PyObject_SetAttrString(state, "load_path", load_path) == -1) {
+ Py_DECREF(load_options);
+ return NULL;
+ }
+ }
+ Py_DECREF(load_options);
+
+ /*for key, getter in populators["quick"]: */
+ populator_collection = PyDict_GetItemString(populators, "quick");
+ if (populator_collection == NULL)
+ return NULL;
+ seq = PySequence_Fast(populator_collection, "expected a sequence");
+ if (seq == NULL)
+ return NULL;
+
+
+ len = PySequence_Fast_GET_SIZE(seq);
+ for (i = 0; i < len; i++) {
+ seq_item = PySequence_Fast_GET_ITEM(seq, i);
+ key = PyTuple_GET_ITEM(seq_item, 0);
+ getter = PyTuple_GET_ITEM(seq_item, 1);
+
+ if (key == NULL || getter == NULL) {
+ Py_DECREF(seq);
+ return NULL;
+ }
+
+ arglist = Py_BuildValue("(O)", row);
+ if (arglist == NULL) {
+ Py_DECREF(seq);
+ return NULL;
+ }
+ retvalue = PyObject_CallObject(getter, arglist);
+ Py_DECREF(arglist);
+ if (retvalue == NULL) {
+ Py_DECREF(seq);
+ return NULL;
+ }
+
+ /* dict_[key] = getter(row) */
+ PyDict_SetItem(dict_, key, retvalue);
+ }
+ Py_DECREF(seq);
+
+ /* if populate_existing: */
+ /* for key, set_callable in populators["expire"]:
+ dict_.pop(key, None) */
+ /* if set_callable:
+ state.callables[key] = state */
+ /* else: */
+ /* for key, set_callable in populators["expire"]: */
+ /* if set_callable:
+ state.callables[key] = state */
+ /* for key, populator in populators["new"]:
+ populator(state, dict_, row) */
+ /* for key, populator in populators["delayed"]:
+ populator(state, dict_, row) */
+
+
+ }
+ else {
+
+
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*
+def _populate_full(
+ context, load_path, row, state, dict_, isnew,
+ loaded_instance, populate_existing, populators):
+ if isnew:
+ # first time we are seeing a row with this identity.
+ state.runid = context.runid
+ if context.propagate_options:
+ state.load_options = context.propagate_options
+ if state.load_options:
+ state.load_path = load_path
+
+ for key, getter in populators["quick"]:
+ dict_[key] = getter(row)
+ if populate_existing:
+ for key, set_callable in populators["expire"]:
+ dict_.pop(key, None)
+ if set_callable:
+ state.callables[key] = state
+ else:
+ for key, set_callable in populators["expire"]:
+ if set_callable:
+ state.callables[key] = state
+ for key, populator in populators["new"]:
+ populator(state, dict_, row)
+ for key, populator in populators["delayed"]:
+ populator(state, dict_, row)
+
+ else:
+ # have already seen rows with this identity.
+ for key, populator in populators["existing"]:
+ populator(state, dict_, row)
+*/
+
+static PyMethodDef module_methods[] = {
+ {"_populate_full", populate_full, METH_VARARGS,
+ "Run ORM population for a new row."},
+ {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
+ };
+#endif
+
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC
+PyInit_cloader(void)
+#else
+PyMODINIT_FUNC
+initcloader(void)
+#endif
+{
+ PyObject *m;
+
+#if PY_MAJOR_VERSION >= 3
+ m = PyModule_Create(&module_def);
+#else
+ m = Py_InitModule3(MODULE_NAME, module_methods, MODULE_DOC);
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+ if (m == NULL)
+ return NULL;
+ return m;
+#else
+ if (m == NULL)
+ return;
+#endif
+}
+
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py
index 28843a528..bc51b021b 100644
--- a/lib/sqlalchemy/orm/loading.py
+++ b/lib/sqlalchemy/orm/loading.py
@@ -416,8 +416,9 @@ def instance_processor(mapper, context, result, path, adapter,
return instance
return _instance
+from sqlalchemy.cloader import _populate_full
-def _populate_full(
+def _dont_populate_full(
context, load_path, row, state, dict_, isnew,
loaded_instance, populate_existing, populators):
if isnew:
diff --git a/setup.py b/setup.py
index 09b524cd2..cb2dd006b 100644
--- a/setup.py
+++ b/setup.py
@@ -43,7 +43,9 @@ ext_modules = [
Extension('sqlalchemy.cresultproxy',
sources=['lib/sqlalchemy/cextension/resultproxy.c']),
Extension('sqlalchemy.cutils',
- sources=['lib/sqlalchemy/cextension/utils.c'])
+ sources=['lib/sqlalchemy/cextension/utils.c']),
+ Extension('sqlalchemy.cloader',
+ sources=['lib/sqlalchemy/cextension/loader.c'])
]
ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)