Return input tuple in cur.callproc, factor code to use PQescapeIdentifier in single place

This commit is contained in:
mrmilosz 2015-12-13 01:10:03 -05:00
parent 92109e4bba
commit 0772d187e9
4 changed files with 42 additions and 44 deletions

View File

@ -1015,35 +1015,6 @@ exit:
#define psyco_curs_callproc_doc \ #define psyco_curs_callproc_doc \
"callproc(procname, parameters=None) -- Execute stored procedure." "callproc(procname, parameters=None) -- Execute stored procedure."
/* Call PQescapeIdentifier.
*
* In case of error set a Python exception.
*
* TODO: this function can become more generic and go into utils
*/
static char *
_escape_identifier(PGconn *pgconn, const char *str, size_t length)
{
char *rv = NULL;
#if PG_VERSION_NUM >= 90000
rv = PQescapeIdentifier(pgconn, str, length);
if (!rv) {
char *msg;
msg = PQerrorMessage(pgconn);
if (!msg || !msg[0]) {
msg = "no message provided";
}
PyErr_Format(InterfaceError, "failed to escape identifier: %s", msg);
}
#else
PyErr_Format(PyExc_NotImplementedError,
"named parameters require psycopg2 compiled against libpq 9.0+");
#endif
return rv;
}
static PyObject * static PyObject *
psyco_curs_callproc(cursorObject *self, PyObject *args) psyco_curs_callproc(cursorObject *self, PyObject *args)
{ {
@ -1107,7 +1078,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args)
if (!(pname = psycopg_ensure_bytes(pname))) { goto exit; } if (!(pname = psycopg_ensure_bytes(pname))) { goto exit; }
if (!(cpname = Bytes_AsString(pname))) { goto exit; } if (!(cpname = Bytes_AsString(pname))) { goto exit; }
if (!(scpnames[i] = _escape_identifier( if (!(scpnames[i] = psycopg_escape_identifier(
self->conn->pgconn, cpname, strlen(cpname)))) { self->conn->pgconn, cpname, strlen(cpname)))) {
goto exit; goto exit;
} }
@ -1158,11 +1129,15 @@ psyco_curs_callproc(cursorObject *self, PyObject *args)
if (0 <= _psyco_curs_execute( if (0 <= _psyco_curs_execute(
self, operation, pvals, self->conn->async, 0)) { self, operation, pvals, self->conn->async, 0)) {
/* The dict case is outside DBAPI scope anyway, so simply return None */
/* return None from this until it's DBAPI compliant... */ if (using_dict) {
Py_INCREF(Py_None); Py_INCREF(Py_None);
res = Py_None; res = Py_None;
} }
else {
res = pvals;
}
}
exit: exit:
if (scpnames != NULL) { if (scpnames != NULL) {

View File

@ -124,6 +124,7 @@ RAISES HIDDEN PyObject *psyco_set_error(PyObject *exc, cursorObject *curs, const
HIDDEN char *psycopg_escape_string(connectionObject *conn, HIDDEN char *psycopg_escape_string(connectionObject *conn,
const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen); const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen);
HIDDEN char *psycopg_escape_identifier_easy(const char *from, Py_ssize_t len); HIDDEN char *psycopg_escape_identifier_easy(const char *from, Py_ssize_t len);
HIDDEN char *psycopg_escape_identifier(PGconn *pgconn, const char *str, size_t length);
HIDDEN int psycopg_strdup(char **to, const char *from, Py_ssize_t len); HIDDEN int psycopg_strdup(char **to, const char *from, Py_ssize_t len);
HIDDEN int psycopg_is_text_file(PyObject *f); HIDDEN int psycopg_is_text_file(PyObject *f);

View File

@ -59,7 +59,6 @@
HIDDEN PyObject *pyDateTimeModuleP = NULL; HIDDEN PyObject *pyDateTimeModuleP = NULL;
HIDDEN PyObject *psycoEncodings = NULL; HIDDEN PyObject *psycoEncodings = NULL;
#ifdef PSYCOPG_DEBUG #ifdef PSYCOPG_DEBUG
HIDDEN int psycopg_debug_enabled = 0; HIDDEN int psycopg_debug_enabled = 0;
#endif #endif
@ -175,7 +174,6 @@ exit:
static PyObject * static PyObject *
psyco_quote_ident(PyObject *self, PyObject *args, PyObject *kwargs) psyco_quote_ident(PyObject *self, PyObject *args, PyObject *kwargs)
{ {
#if PG_VERSION_NUM >= 90000
PyObject *ident = NULL, *obj = NULL, *result = NULL; PyObject *ident = NULL, *obj = NULL, *result = NULL;
connectionObject *conn; connectionObject *conn;
const char *str; const char *str;
@ -203,9 +201,8 @@ psyco_quote_ident(PyObject *self, PyObject *args, PyObject *kwargs)
str = Bytes_AS_STRING(ident); str = Bytes_AS_STRING(ident);
quoted = PQescapeIdentifier(conn->pgconn, str, strlen(str)); quoted = psycopg_escape_identifier(conn->pgconn, str, strlen(str));
if (!quoted) { if (!quoted) {
PyErr_NoMemory();
goto exit; goto exit;
} }
result = conn_text_from_chars(conn, quoted); result = conn_text_from_chars(conn, quoted);
@ -215,10 +212,6 @@ exit:
Py_XDECREF(ident); Py_XDECREF(ident);
return result; return result;
#else
PyErr_SetString(NotSupportedError, "PQescapeIdentifier not available in libpq < 9.0");
return NULL;
#endif
} }
/** type registration **/ /** type registration **/

View File

@ -95,8 +95,8 @@ psycopg_escape_string(connectionObject *conn, const char *from, Py_ssize_t len,
* The returned string doesn't include quotes. * The returned string doesn't include quotes.
* *
* WARNING: this function is not so safe to allow untrusted input: it does no * WARNING: this function is not so safe to allow untrusted input: it does no
* check for multibyte chars. Such a function should be built on * check for multibyte chars. Functions otherwise reliant on PostgreSQL 9.0
* PQescapeIdentifier, which is only available from PostgreSQL 9.0. * and above should use the below function psycopg_escape_identifier instead.
*/ */
char * char *
psycopg_escape_identifier_easy(const char *from, Py_ssize_t len) psycopg_escape_identifier_easy(const char *from, Py_ssize_t len)
@ -124,6 +124,35 @@ psycopg_escape_identifier_easy(const char *from, Py_ssize_t len)
return rv; return rv;
} }
/* Call PostgreSQL 9.0+ function PQescapeIdentifier.
*
* In case of error set a Python exception.
*/
char *
psycopg_escape_identifier(PGconn *pgconn, const char *str, size_t length)
{
char *rv = NULL;
#if PG_VERSION_NUM >= 90000
rv = PQescapeIdentifier(pgconn, str, length);
if (!rv) {
char *msg;
msg = PQerrorMessage(pgconn);
if (!msg || !msg[0]) {
msg = "no message provided";
}
PyErr_Format(InterfaceError, "failed to escape identifier: %s", msg);
}
#else
PyErr_Format(PyExc_NotImplementedError,
"PQescapeIdentifier requires psycopg2 compiled against libpq 9.0+");
#endif
return rv;
}
/* Duplicate a string. /* Duplicate a string.
* *
* Allocate a new buffer on the Python heap containing the new string. * Allocate a new buffer on the Python heap containing the new string.