diff options
author | mrmilosz <milosz@milosz.ca> | 2014-05-29 04:31:43 -0400 |
---|---|---|
committer | mrmilosz <milosz@milosz.ca> | 2015-12-12 17:49:44 -0500 |
commit | 3948e909e46bab420d0c40bda21a32bfa501bd19 (patch) | |
tree | bdc3a7ecacaa9c107347725cffff3963f72ce6b3 | |
parent | e9bb4a86f93836f8f6c1233c45507e58c159ef1f (diff) | |
download | psycopg2-3948e909e46bab420d0c40bda21a32bfa501bd19.tar.gz |
callproc: now more compliant with local coding standards.
-rw-r--r-- | psycopg/cursor_type.c | 182 |
1 files changed, 97 insertions, 85 deletions
diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index 5f70ce6..d6875a7 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -1024,17 +1024,18 @@ psyco_curs_callproc(cursorObject *self, PyObject *args) PyObject *parameters = Py_None; PyObject *operation = NULL; PyObject *res = NULL; - PyObject *parameter_name = NULL; - PyObject *parameter_name_bytes = NULL; - char *parameter_name_cstr = NULL; - char *parameter_name_cstr_sanitized = NULL; - char **parameter_name_cstr_sanitized_CACHE = NULL; - PyObject *parameter_names = NULL; - - if (!PyArg_ParseTuple(args, "s#|O", - &procname, &procname_len, ¶meters - )) - { goto exit; } + + int using_dict; + PyObject *pname = NULL; + PyObject *bpname = NULL; + PyObject *pnames = NULL; + char *cpname = NULL; + char **scpnames = NULL; + + if (!PyArg_ParseTuple(args, "s#|O", &procname, &procname_len, + ¶meters)) { + goto exit; + } EXC_IF_CURS_CLOSED(self); EXC_IF_ASYNC_IN_PROGRESS(self, callproc); @@ -1042,7 +1043,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args) if (self->name != NULL) { psyco_set_error(ProgrammingError, self, - "can't call .callproc() on named cursors"); + "can't call .callproc() on named cursors"); goto exit; } @@ -1050,106 +1051,117 @@ psyco_curs_callproc(cursorObject *self, PyObject *args) if (-1 == (nparameters = PyObject_Length(parameters))) { goto exit; } } - /* allocate some memory, build the SQL and create a PyString from it */ - - /* a dict requires special handling: we put the parameter names into the SQL */ - if (nparameters > 0 && PyDict_Check(parameters)) { + using_dict = nparameters > 0 && PyDict_Check(parameters); - parameter_names = PyDict_Keys(parameters); - - /* first we need to ensure the dict's keys are text */ - for(i=0; i<nparameters; i++) { - if (!Text_Check(PyList_GetItem(parameter_names, i))) { - PyErr_SetString(PyExc_TypeError, "argument 2 must have only string keys if Dict"); - Py_DECREF(parameter_names); - goto exit; + /* A Dict is complicated. The parameter names go into the query */ + if (using_dict) { + if (!(pnames = PyDict_Keys(parameters))) { + PyErr_SetString(PyExc_RuntimeError, + "built-in 'keys' failed on a Dict!"); + goto exit; } - } - /* we need one extra pass to determine the amount of memory to allocate for the SQL */ - sl = procname_len + 17 + nparameters*5 - (nparameters ? 1 : 0); + sl = procname_len + 17 + nparameters * 5 - (nparameters ? 1 : 0); - /* we will throw the sanitized C strings into a cache to not redo the work later */ - parameter_name_cstr_sanitized_CACHE = PyMem_New(char *, nparameters); - - if (parameter_name_cstr_sanitized_CACHE == NULL) { - PyErr_NoMemory(); - PyMem_Del(parameter_name_cstr_sanitized_CACHE); - Py_DECREF(parameter_names); - goto exit; - } + if (!(scpnames = PyMem_New(char *, nparameters))) { + PyErr_NoMemory(); + goto exit; + } - for(i=0; i<nparameters; i++) { - parameter_name = PyList_GetItem(parameter_names, i); + memset(scpnames, 0, sizeof(char *) * nparameters); - Py_INCREF(parameter_name); - parameter_name_bytes = psycopg_ensure_bytes(parameter_name); - parameter_name_cstr = Bytes_AsString(parameter_name_bytes); - parameter_name_cstr_sanitized = PQescapeIdentifier(self->conn->pgconn, parameter_name_cstr, strlen(parameter_name_cstr)); - Py_DECREF(parameter_name); + /* Each parameter has to be processed. It's a few steps. */ + for (i = 0; i < nparameters; i++) { + if (!(pname = PyList_GetItem(pnames, i))) { + PyErr_SetString(PyExc_RuntimeError, + "built-in 'values' did not return List!"); + goto exit; + } - /* must add the length of the sanitized string to the length of the SQL string */ - sl += strlen(parameter_name_cstr_sanitized); + if (!(bpname = psycopg_ensure_bytes(pname))) { + PyErr_SetString(PyExc_TypeError, + "argument 2 must have only string keys if Dict"); + goto exit; + } - parameter_name_cstr_sanitized_CACHE[i] = parameter_name_cstr_sanitized; - } + if (!(cpname = Bytes_AsString(bpname))) { + PyErr_SetString(PyExc_RuntimeError, + "failed to get Bytes from String!"); + goto exit; + } - Py_DECREF(parameter_names); + if (!(scpnames[i] = PQescapeIdentifier(self->conn->pgconn, cpname, + strlen(cpname)))) { + PyErr_SetString(PyExc_RuntimeError, + "libpq failed to escape identifier!"); + goto exit; + } - sql = (char*)PyMem_Malloc(sl); - if (sql == NULL) { - PyErr_NoMemory(); - for(i=0; i<nparameters; i++) { - PQfreemem(parameter_name_cstr_sanitized_CACHE[i]); + sl += strlen(scpnames[i]); } - PyMem_Del(parameter_name_cstr_sanitized_CACHE); - goto exit; - } - sprintf(sql, "SELECT * FROM %s(", procname); - for(i=0; i<nparameters; i++) { - parameter_name_cstr_sanitized = parameter_name_cstr_sanitized_CACHE[i]; - /* like procname, param names are not sanitized. don't SQL inject yourself. */ - strcat(sql, parameter_name_cstr_sanitized); - strcat(sql, ":=%s,"); + sql = (char*)PyMem_Malloc(sl); + if (sql == NULL) { + PyErr_NoMemory(); + goto exit; + } - PQfreemem(parameter_name_cstr_sanitized); - } - PyMem_Del(parameter_name_cstr_sanitized_CACHE); - sql[sl-2] = ')'; - sql[sl-1] = '\0'; + sprintf(sql, "SELECT * FROM %s(", procname); + for (i = 0; i < nparameters; i++) { + strcat(sql, scpnames[i]); + strcat(sql, ":=%s,"); + } + sql[sl-2] = ')'; + sql[sl-1] = '\0'; - /* now that we have the query string we can discard the keys and proceed normally */ - parameters = PyDict_Values(parameters); + if (!(parameters = PyDict_Values(parameters))) { + PyErr_SetString(PyExc_RuntimeError, + "built-in 'values' failed on a Dict!"); + goto exit; + } } - /* a list (or None) is a little bit simpler */ + /* a list (or None, or empty data structure) is a little bit simpler */ else { - sl = procname_len + 17 + nparameters*3 - (nparameters ? 1 : 0); + sl = procname_len + 17 + nparameters * 3 - (nparameters ? 1 : 0); - sql = (char*)PyMem_Malloc(sl); - if (sql == NULL) { - PyErr_NoMemory(); - goto exit; - } + 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'; + sprintf(sql, "SELECT * FROM %s(", procname); + for (i = 0; i < nparameters; i++) { + strcat(sql, "%s,"); + } + sql[sl-2] = ')'; + sql[sl-1] = '\0'; } - if (!(operation = Bytes_FromString(sql))) { goto exit; } + if (!(operation = Bytes_FromString(sql))) { + goto exit; + } if (0 <= _psyco_curs_execute(self, operation, parameters, - self->conn->async, 0)) { - Py_INCREF(parameters); + self->conn->async, 0)) { + /* In the dict case, the parameters are already a new reference */ + if (!using_dict) { + Py_INCREF(parameters); + } res = parameters; } exit: + if (scpnames != NULL) { + for (i = 0; i < nparameters; i++) { + if (scpnames[i] != NULL) { + PQfreemem(scpnames[i]); + } + } + } + PyMem_Del(scpnames); + Py_XDECREF(pnames); Py_XDECREF(operation); PyMem_Free((void*)sql); return res; |