cursor.callproc now also accepts dict for PostgreSQL 9+ "named notation"

This commit is contained in:
mrmilosz 2014-05-24 23:47:09 -04:00
parent fe4cb0d493
commit 23d279945f
2 changed files with 47 additions and 11 deletions

View File

@ -1024,6 +1024,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args)
PyObject *parameters = Py_None; PyObject *parameters = Py_None;
PyObject *operation = NULL; PyObject *operation = NULL;
PyObject *res = NULL; PyObject *res = NULL;
PyObject *parameter_names = NULL;
if (!PyArg_ParseTuple(args, "s#|O", if (!PyArg_ParseTuple(args, "s#|O",
&procname, &procname_len, &parameters &procname, &procname_len, &parameters
@ -1045,19 +1046,52 @@ psyco_curs_callproc(cursorObject *self, PyObject *args)
} }
/* allocate some memory, build the SQL and create a PyString from it */ /* allocate some memory, build the SQL and create a PyString from it */
sl = procname_len + 17 + nparameters*3 - (nparameters ? 1 : 0);
sql = (char*)PyMem_Malloc(sl);
if (sql == NULL) {
PyErr_NoMemory();
goto exit;
}
sprintf(sql, "SELECT * FROM %s(", procname); if (nparameters > 0 && PyDict_Check(parameters)) {
for(i=0; i<nparameters; i++) { /* for a dict, we put the parameter names into the SQL */
strcat(sql, "%s,"); parameter_names = PyDict_Keys(parameters);
/* first we need to figure out how much space we need for the SQL */
sl = procname_len + 17 + nparameters*5 - (nparameters ? 1 : 0);
for(i=0; i<nparameters; i++) {
sl += strlen(Text_AsUTF8(PyList_GetItem(parameter_names, i)));
}
sql = (char*)PyMem_Malloc(sl);
if (sql == NULL) {
PyErr_NoMemory();
goto exit;
}
sprintf(sql, "SELECT * FROM %s(", procname);
for(i=0; i<nparameters; i++) {
/* like procname, param names are not sanitized. don't SQL inject yourself. */
strcat(sql, Text_AsUTF8(PyList_GetItem(parameter_names, i)));
strcat(sql, ":=%s,");
}
sql[sl-2] = ')';
sql[sl-1] = '\0';
Py_DECREF(parameter_names);
/* now that we have the query string we can discard the keys and proceed normally */
parameters = PyDict_Values(parameters);
}
else {
sl = procname_len + 17 + nparameters*3 - (nparameters ? 1 : 0);
sql = (char*)PyMem_Malloc(sl);
if (sql == NULL) {
PyErr_NoMemory();
goto exit;
}
sprintf(sql, "SELECT * FROM %s(", procname);
for(i=0; i<nparameters; i++) {
strcat(sql, "%s,");
}
sql[sl-2] = ')';
sql[sl-1] = '\0';
} }
sql[sl-2] = ')';
sql[sl-1] = '\0';
if (!(operation = Bytes_FromString(sql))) { goto exit; } if (!(operation = Bytes_FromString(sql))) { goto exit; }

View File

@ -71,12 +71,14 @@ typedef unsigned long Py_uhash_t;
#define Text_Format(f,a) PyString_Format(f,a) #define Text_Format(f,a) PyString_Format(f,a)
#define Text_FromUTF8(s) PyString_FromString(s) #define Text_FromUTF8(s) PyString_FromString(s)
#define Text_FromUTF8AndSize(s,n) PyString_FromStringAndSize(s,n) #define Text_FromUTF8AndSize(s,n) PyString_FromStringAndSize(s,n)
#define Text_AsUTF8(s) PyString_AsString(s)
#else #else
#define Text_Type PyUnicode_Type #define Text_Type PyUnicode_Type
#define Text_Check(s) PyUnicode_Check(s) #define Text_Check(s) PyUnicode_Check(s)
#define Text_Format(f,a) PyUnicode_Format(f,a) #define Text_Format(f,a) PyUnicode_Format(f,a)
#define Text_FromUTF8(s) PyUnicode_FromString(s) #define Text_FromUTF8(s) PyUnicode_FromString(s)
#define Text_FromUTF8AndSize(s,n) PyUnicode_FromStringAndSize(s,n) #define Text_FromUTF8AndSize(s,n) PyUnicode_FromStringAndSize(s,n)
#define Text_AsUTF8(s) PyUnicode_AsUTF8(s)
#endif #endif
#if PY_MAJOR_VERSION > 2 #if PY_MAJOR_VERSION > 2