From a53b39efe8f8bef6f574de24a28fb27b143e890a Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Mon, 26 Dec 2016 02:37:36 +0100 Subject: [PATCH] Dropped internal escape identifier function Using libpq one as now it's guaranteed to be present. --- psycopg/cursor.h | 1 + psycopg/cursor_type.c | 48 +++++++++++++++++++++++-------------------- psycopg/psycopg.h | 3 ++- psycopg/utils.c | 40 ++++++++++++++++-------------------- 4 files changed, 47 insertions(+), 45 deletions(-) diff --git a/psycopg/cursor.h b/psycopg/cursor.h index e291d45f..3c94fe3d 100644 --- a/psycopg/cursor.h +++ b/psycopg/cursor.h @@ -80,6 +80,7 @@ struct cursorObject { char *qattr; /* quoting attr, used when quoting strings */ char *notice; /* a notice from the backend */ char *name; /* this cursor name */ + char *qname; /* this cursor name, quoted */ PyObject *string_types; /* a set of typecasters for string types */ PyObject *binary_types; /* a set of typecasters for binary types */ diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index fe79bbf9..6b66217c 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -55,7 +55,7 @@ psyco_curs_close(cursorObject *self) goto exit; } - if (self->name != NULL) { + if (self->qname != NULL) { char buffer[128]; PGTransactionStatusType status; @@ -68,7 +68,7 @@ psyco_curs_close(cursorObject *self) if (!(status == PQTRANS_UNKNOWN || status == PQTRANS_INERROR)) { EXC_IF_NO_MARK(self); - PyOS_snprintf(buffer, 127, "CLOSE \"%s\"", self->name); + PyOS_snprintf(buffer, 127, "CLOSE %s", self->qname); if (pq_execute(self, buffer, 0, 0, 1) == -1) return NULL; } else { @@ -422,10 +422,10 @@ _psyco_curs_execute(cursorObject *self, goto exit; } - if (self->name != NULL) { + if (self->qname != NULL) { self->query = Bytes_FromFormat( - "DECLARE \"%s\" %sCURSOR %s HOLD FOR %s", - self->name, + "DECLARE %s %sCURSOR %s HOLD FOR %s", + self->qname, scroll, self->withhold ? "WITH" : "WITHOUT", Bytes_AS_STRING(fquery)); @@ -436,10 +436,10 @@ _psyco_curs_execute(cursorObject *self, } } else { - if (self->name != NULL) { + if (self->qname != NULL) { self->query = Bytes_FromFormat( - "DECLARE \"%s\" %sCURSOR %s HOLD FOR %s", - self->name, + "DECLARE %s %sCURSOR %s HOLD FOR %s", + self->qname, scroll, self->withhold ? "WITH" : "WITHOUT", Bytes_AS_STRING(operation)); @@ -768,13 +768,13 @@ psyco_curs_fetchone(cursorObject *self) if (_psyco_curs_prefetch(self) < 0) return NULL; EXC_IF_NO_TUPLES(self); - if (self->name != NULL) { + if (self->qname != NULL) { char buffer[128]; EXC_IF_NO_MARK(self); EXC_IF_ASYNC_IN_PROGRESS(self, fetchone); EXC_IF_TPC_PREPARED(self->conn, fetchone); - PyOS_snprintf(buffer, 127, "FETCH FORWARD 1 FROM \"%s\"", self->name); + PyOS_snprintf(buffer, 127, "FETCH FORWARD 1 FROM %s", self->qname); if (pq_execute(self, buffer, 0, 0, self->withhold) == -1) return NULL; if (_psyco_curs_prefetch(self) < 0) return NULL; } @@ -823,8 +823,8 @@ psyco_curs_next_named(cursorObject *self) if (self->row >= self->rowcount) { char buffer[128]; - PyOS_snprintf(buffer, 127, "FETCH FORWARD %ld FROM \"%s\"", - self->itersize, self->name); + PyOS_snprintf(buffer, 127, "FETCH FORWARD %ld FROM %s", + self->itersize, self->qname); if (pq_execute(self, buffer, 0, 0, self->withhold) == -1) return NULL; if (_psyco_curs_prefetch(self) < 0) return NULL; } @@ -886,14 +886,14 @@ psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords) if (_psyco_curs_prefetch(self) < 0) return NULL; EXC_IF_NO_TUPLES(self); - if (self->name != NULL) { + if (self->qname != NULL) { char buffer[128]; EXC_IF_NO_MARK(self); EXC_IF_ASYNC_IN_PROGRESS(self, fetchmany); EXC_IF_TPC_PREPARED(self->conn, fetchone); - PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM \"%s\"", - (int)size, self->name); + PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM %s", + (int)size, self->qname); if (pq_execute(self, buffer, 0, 0, self->withhold) == -1) { goto exit; } if (_psyco_curs_prefetch(self) < 0) { goto exit; } } @@ -962,13 +962,13 @@ psyco_curs_fetchall(cursorObject *self) if (_psyco_curs_prefetch(self) < 0) return NULL; EXC_IF_NO_TUPLES(self); - if (self->name != NULL) { + if (self->qname != NULL) { char buffer[128]; EXC_IF_NO_MARK(self); EXC_IF_ASYNC_IN_PROGRESS(self, fetchall); EXC_IF_TPC_PREPARED(self->conn, fetchall); - PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM \"%s\"", self->name); + PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM %s", self->qname); if (pq_execute(self, buffer, 0, 0, self->withhold) == -1) { goto exit; } if (_psyco_curs_prefetch(self) < 0) { goto exit; } } @@ -1153,7 +1153,7 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs) /* if the cursor is not named we have the full result set and we can do our own calculations to scroll; else we just delegate the scrolling to the MOVE SQL statement */ - if (self->name == NULL) { + if (self->qname == NULL) { if (strcmp(mode, "relative") == 0) { newpos = self->row + value; } else if (strcmp( mode, "absolute") == 0) { @@ -1181,11 +1181,11 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs) EXC_IF_TPC_PREPARED(self->conn, scroll); if (strcmp(mode, "absolute") == 0) { - PyOS_snprintf(buffer, 127, "MOVE ABSOLUTE %d FROM \"%s\"", - value, self->name); + PyOS_snprintf(buffer, 127, "MOVE ABSOLUTE %d FROM %s", + value, self->qname); } else { - PyOS_snprintf(buffer, 127, "MOVE %d FROM \"%s\"", value, self->name); + PyOS_snprintf(buffer, 127, "MOVE %d FROM %s", value, self->qname); } if (pq_execute(self, buffer, 0, 0, self->withhold) == -1) return NULL; if (_psyco_curs_prefetch(self) < 0) return NULL; @@ -1815,7 +1815,10 @@ cursor_setup(cursorObject *self, connectionObject *conn, const char *name) Dprintf("cursor_setup: parameters: name = %s, conn = %p", name, conn); if (name) { - if (!(self->name = psycopg_escape_identifier_easy(name, 0))) { + if (0 > psycopg_strdup(&self->name, name, 0)) { + return -1; + } + if (!(self->qname = psycopg_escape_identifier(conn, name, 0))) { return -1; } } @@ -1891,6 +1894,7 @@ cursor_dealloc(PyObject* obj) cursor_clear(self); PyMem_Free(self->name); + PQfreemem(self->qname); CLEARPGRES(self->pgres); diff --git a/psycopg/psycopg.h b/psycopg/psycopg.h index 82b4293c..438d7636 100644 --- a/psycopg/psycopg.h +++ b/psycopg/psycopg.h @@ -128,7 +128,8 @@ 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(connectionObject *conn, + const char *str, size_t len); 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/utils.c b/psycopg/utils.c index 631b8394..c518cc57 100644 --- a/psycopg/utils.c +++ b/psycopg/utils.c @@ -90,40 +90,36 @@ psycopg_escape_string(connectionObject *conn, const char *from, Py_ssize_t len, return to; } -/* Escape a string to build a valid PostgreSQL identifier. +/* Escape a string for inclusion in a query as identifier. * - * Allocate a new buffer on the Python heap containing the new string. * 'len' is optional: if 0 the length is calculated. * - * 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. + * Return a string allocated by Postgres: free it using PQfreemem + * In case of error set a Python exception. */ char * -psycopg_escape_identifier_easy(const char *from, Py_ssize_t len) +psycopg_escape_identifier(connectionObject *conn, const char *str, size_t len) { - char *rv; - const char *src; - char *dst; + char *rv = NULL; - if (!len) { len = strlen(from); } - if (!(rv = PyMem_New(char, 1 + 2 * len))) { - PyErr_NoMemory(); - return NULL; + if (!conn || !conn->pgconn) { + PyErr_SetString(InterfaceError, "connection not valid"); + goto exit; } - /* The only thing to do is double quotes */ - for (src = from, dst = rv; *src; ++src, ++dst) { - *dst = *src; - if ('"' == *src) { - *++dst = '"'; + if (!len) { len = strlen(str); } + + rv = PQescapeIdentifier(conn->pgconn, str, len); + if (!rv) { + char *msg; + msg = PQerrorMessage(conn->pgconn); + if (!msg || !msg[0]) { + msg = "no message provided"; } + PyErr_Format(InterfaceError, "failed to escape identifier: %s", msg); } - *dst = '\0'; - +exit: return rv; }