diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index 0a785c05..e205ba2a 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -1015,35 +1015,6 @@ exit: #define psyco_curs_callproc_doc \ "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 * 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 (!(cpname = Bytes_AsString(pname))) { goto exit; } - if (!(scpnames[i] = _escape_identifier( + if (!(scpnames[i] = psycopg_escape_identifier( self->conn->pgconn, cpname, strlen(cpname)))) { goto exit; } @@ -1158,10 +1129,14 @@ psyco_curs_callproc(cursorObject *self, PyObject *args) if (0 <= _psyco_curs_execute( self, operation, pvals, self->conn->async, 0)) { - - /* return None from this until it's DBAPI compliant... */ - Py_INCREF(Py_None); - res = Py_None; + /* The dict case is outside DBAPI scope anyway, so simply return None */ + if (using_dict) { + Py_INCREF(Py_None); + res = Py_None; + } + else { + res = pvals; + } } exit: diff --git a/psycopg/psycopg.h b/psycopg/psycopg.h index eb406fd2..1a16e8af 100644 --- a/psycopg/psycopg.h +++ b/psycopg/psycopg.h @@ -124,6 +124,7 @@ RAISES HIDDEN PyObject *psyco_set_error(PyObject *exc, cursorObject *curs, const HIDDEN char *psycopg_escape_string(connectionObject *conn, 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(PGconn *pgconn, const char *str, size_t length); HIDDEN int psycopg_strdup(char **to, const char *from, Py_ssize_t len); HIDDEN int psycopg_is_text_file(PyObject *f); diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c index cf70a4ad..0ecfcc9c 100644 --- a/psycopg/psycopgmodule.c +++ b/psycopg/psycopgmodule.c @@ -59,7 +59,6 @@ HIDDEN PyObject *pyDateTimeModuleP = NULL; HIDDEN PyObject *psycoEncodings = NULL; - #ifdef PSYCOPG_DEBUG HIDDEN int psycopg_debug_enabled = 0; #endif @@ -175,7 +174,6 @@ exit: static PyObject * psyco_quote_ident(PyObject *self, PyObject *args, PyObject *kwargs) { -#if PG_VERSION_NUM >= 90000 PyObject *ident = NULL, *obj = NULL, *result = NULL; connectionObject *conn; const char *str; @@ -203,9 +201,8 @@ psyco_quote_ident(PyObject *self, PyObject *args, PyObject *kwargs) str = Bytes_AS_STRING(ident); - quoted = PQescapeIdentifier(conn->pgconn, str, strlen(str)); + quoted = psycopg_escape_identifier(conn->pgconn, str, strlen(str)); if (!quoted) { - PyErr_NoMemory(); goto exit; } result = conn_text_from_chars(conn, quoted); @@ -215,10 +212,6 @@ exit: Py_XDECREF(ident); return result; -#else - PyErr_SetString(NotSupportedError, "PQescapeIdentifier not available in libpq < 9.0"); - return NULL; -#endif } /** type registration **/ diff --git a/psycopg/utils.c b/psycopg/utils.c index ec8e47c8..e224a0d5 100644 --- a/psycopg/utils.c +++ b/psycopg/utils.c @@ -95,8 +95,8 @@ psycopg_escape_string(connectionObject *conn, const char *from, Py_ssize_t len, * The returned string doesn't include quotes. * * 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 - * PQescapeIdentifier, which is only available from PostgreSQL 9.0. + * check for multibyte chars. Functions otherwise reliant on PostgreSQL 9.0 + * and above should use the below function psycopg_escape_identifier instead. */ char * 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; } + +/* 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. * * Allocate a new buffer on the Python heap containing the new string.