Skip to content

Commit 80df055

Browse files
committed
Fixed handling large Oid values
Oid is defined as unsigned 32. On some Python implementations (probably the ones where maxint = 2 ** 31) this can cause int overflow for large values (see psycopg#961). On my 64 box it doesn't seem the case. Oid handling was sloppy here and there (messages, casts...): trying to use uint everywhere, and added a couple of helper macros to treat Oid consistently. Close psycopg#961.
1 parent 4d10f12 commit 80df055

File tree

7 files changed

+25
-13
lines changed

7 files changed

+25
-13
lines changed

NEWS

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ Current release
44
What's new in psycopg 2.8.4
55
^^^^^^^^^^^^^^^^^^^^^^^^^^^
66

7-
Don't swallow keyboard interrupts on connect when a password is specified
8-
in the connection string (:ticket:`#898`).
7+
- Don't swallow keyboard interrupts on connect when a password is specified
8+
in the connection string (:ticket:`#898`).
9+
- Fixed int overflow for large values in `~psycopg2.extensions.Column.table_oid`
10+
and `~psycopg2.extensions.Column.type_code` (:ticket:`961).
911

1012

1113
What's new in psycopg 2.8.3

psycopg/connection_type.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,7 @@ psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds)
968968
Dprintf("psyco_conn_lobject: new lobject for connection at %p", self);
969969
Dprintf("psyco_conn_lobject: parameters: oid = %u, mode = %s",
970970
oid, smode);
971-
Dprintf("psyco_conn_lobject: parameters: new_oid = %d, new_file = %s",
971+
Dprintf("psyco_conn_lobject: parameters: new_oid = %u, new_file = %s",
972972
new_oid, new_file);
973973

974974
if (new_file)

psycopg/cursor_type.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1827,7 +1827,7 @@ static struct PyMemberDef cursorObject_members[] = {
18271827
"Number of records ``iter(cur)`` must fetch per network roundtrip."},
18281828
{"description", T_OBJECT, OFFSETOF(description), READONLY,
18291829
"Cursor description as defined in DBAPI-2.0."},
1830-
{"lastrowid", T_LONG, OFFSETOF(lastoid), READONLY,
1830+
{"lastrowid", T_OID, OFFSETOF(lastoid), READONLY,
18311831
"The ``oid`` of the last row inserted by the cursor."},
18321832
/* DBAPI-2.0 extensions */
18331833
{"rownumber", T_LONG, OFFSETOF(row), READONLY,

psycopg/lobject_int.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ lobject_open(lobjectObject *self, connectionObject *conn,
176176
self->oid = lo_creat(self->conn->pgconn, INV_READ | INV_WRITE);
177177
}
178178

179-
Dprintf("lobject_open: large object created with oid = %d",
179+
Dprintf("lobject_open: large object created with oid = %u",
180180
self->oid);
181181

182182
if (self->oid == InvalidOid) {

psycopg/lobject_type.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ static struct PyMethodDef lobjectObject_methods[] = {
327327
/* object member list */
328328

329329
static struct PyMemberDef lobjectObject_members[] = {
330-
{"oid", T_UINT, offsetof(lobjectObject, oid), READONLY,
330+
{"oid", T_OID, offsetof(lobjectObject, oid), READONLY,
331331
"The backend OID associated to this lobject."},
332332
{"mode", T_STRING, offsetof(lobjectObject, smode), READONLY,
333333
"Open mode."},
@@ -368,7 +368,7 @@ lobject_setup(lobjectObject *self, connectionObject *conn,
368368

369369
Dprintf("lobject_setup: good lobject object at %p, refcnt = "
370370
FORMAT_CODE_PY_SSIZE_T, self, Py_REFCNT(self));
371-
Dprintf("lobject_setup: oid = %d, fd = %d", self->oid, self->fd);
371+
Dprintf("lobject_setup: oid = %u, fd = %d", self->oid, self->fd);
372372
return 0;
373373
}
374374

psycopg/pqpath.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -995,9 +995,9 @@ _get_cast(cursorObject *curs, PGresult *pgres, int i)
995995
PyObject *rv = NULL;
996996

997997
Oid ftype = PQftype(pgres, i);
998-
if (!(type = PyInt_FromLong(ftype))) { goto exit; }
998+
if (!(type = PyLong_FromOid(ftype))) { goto exit; }
999999

1000-
Dprintf("_pq_fetch_tuples: looking for cast %d:", ftype);
1000+
Dprintf("_pq_fetch_tuples: looking for cast %u:", ftype);
10011001
if (!(cast = curs_get_cast(curs, type))) { goto exit; }
10021002

10031003
/* else if we got binary tuples and if we got a field that
@@ -1006,11 +1006,11 @@ _get_cast(cursorObject *curs, PGresult *pgres, int i)
10061006
*/
10071007
if (cast == psyco_default_binary_cast && PQbinaryTuples(pgres)) {
10081008
Dprintf("_pq_fetch_tuples: Binary cursor and "
1009-
"binary field: %i using default cast", ftype);
1009+
"binary field: %u using default cast", ftype);
10101010
cast = psyco_default_cast;
10111011
}
10121012

1013-
Dprintf("_pq_fetch_tuples: using cast at %p for type %d", cast, ftype);
1013+
Dprintf("_pq_fetch_tuples: using cast at %p for type %u", cast, ftype);
10141014

10151015
/* success */
10161016
Py_INCREF(cast);
@@ -1041,7 +1041,7 @@ _make_column(connectionObject *conn, PGresult *pgres, int i)
10411041
/* fill the type and name fields */
10421042
{
10431043
PyObject *tmp;
1044-
if (!(tmp = PyInt_FromLong(ftype))) {
1044+
if (!(tmp = PyLong_FromOid(ftype))) {
10451045
goto exit;
10461046
}
10471047
column->type_code = tmp;
@@ -1099,7 +1099,7 @@ _make_column(connectionObject *conn, PGresult *pgres, int i)
10991099
/* table_oid, table_column */
11001100
if (ftable != InvalidOid) {
11011101
PyObject *tmp;
1102-
if (!(tmp = PyInt_FromLong((long)ftable))) { goto exit; }
1102+
if (!(tmp = PyLong_FromOid(ftable))) { goto exit; }
11031103
column->table_oid = tmp;
11041104
}
11051105

psycopg/python.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ typedef unsigned long Py_uhash_t;
9191

9292
#define INIT_MODULE(m) init ## m
9393

94+
/* fix #961, but don't change all types to longs. Sure someone will complain. */
95+
#define PyLong_FromOid(x) (((x) & 0x80000000) ? \
96+
PyLong_FromUnsignedLong((unsigned long)(x)) : \
97+
PyInt_FromLong((x)))
98+
9499
#endif /* PY_2 */
95100

96101
#if PY_3
@@ -133,6 +138,11 @@ typedef unsigned long Py_uhash_t;
133138

134139
#define INIT_MODULE(m) PyInit_ ## m
135140

141+
#define PyLong_FromOid(x) (PyLong_FromUnsignedLong((unsigned long)(x)))
142+
136143
#endif /* PY_3 */
137144

145+
/* expose Oid attributes in Python C objects */
146+
#define T_OID T_UINT
147+
138148
#endif /* !defined(PSYCOPG_PYTHON_H) */

0 commit comments

Comments
 (0)