From ba45631d66502600034f3d4803e35909f29d8e7c Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 12 Sep 2017 22:09:21 -0400 Subject: [PATCH] Improve type conversion of SPI_processed in Python The previous code converted SPI_processed to a Python float if it didn't fit into a Python int. But Python longs have unlimited precision, so use that instead. Refactor the code a bit to avoid having to repeat this logic three times. --- src/pl/plpython/plpy_cursorobject.c | 4 +--- src/pl/plpython/plpy_spi.c | 8 ++------ src/pl/plpython/plpy_util.c | 25 +++++++++++++++++++++++++ src/pl/plpython/plpy_util.h | 2 ++ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/pl/plpython/plpy_cursorobject.c b/src/pl/plpython/plpy_cursorobject.c index 9467f64808..37baf5fafd 100644 --- a/src/pl/plpython/plpy_cursorobject.c +++ b/src/pl/plpython/plpy_cursorobject.c @@ -437,9 +437,7 @@ PLy_cursor_fetch(PyObject *self, PyObject *args) ret->status = PyInt_FromLong(SPI_OK_FETCH); Py_DECREF(ret->nrows); - ret->nrows = (SPI_processed > (uint64) LONG_MAX) ? - PyFloat_FromDouble((double) SPI_processed) : - PyInt_FromLong((long) SPI_processed); + ret->nrows = PLyObject_FromUint64(SPI_processed); if (SPI_processed != 0) { diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c index 0c623a9458..c6b6f73498 100644 --- a/src/pl/plpython/plpy_spi.c +++ b/src/pl/plpython/plpy_spi.c @@ -371,9 +371,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status) if (status > 0 && tuptable == NULL) { Py_DECREF(result->nrows); - result->nrows = (rows > (uint64) LONG_MAX) ? - PyFloat_FromDouble((double) rows) : - PyInt_FromLong((long) rows); + result->nrows = PLyObject_FromUint64(rows); } else if (status > 0 && tuptable != NULL) { @@ -381,9 +379,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status) MemoryContext cxt; Py_DECREF(result->nrows); - result->nrows = (rows > (uint64) LONG_MAX) ? - PyFloat_FromDouble((double) rows) : - PyInt_FromLong((long) rows); + result->nrows = PLyObject_FromUint64(rows); cxt = AllocSetContextCreate(CurrentMemoryContext, "PL/Python temp context", diff --git a/src/pl/plpython/plpy_util.c b/src/pl/plpython/plpy_util.c index 35d57a9e80..0bb5150de9 100644 --- a/src/pl/plpython/plpy_util.c +++ b/src/pl/plpython/plpy_util.c @@ -133,3 +133,28 @@ PLyUnicode_FromString(const char *s) } #endif /* PY_MAJOR_VERSION >= 3 */ + +/* + * Return a suitable Python object containing a uint64. + */ +PyObject * +PLyObject_FromUint64(uint64 ival) +{ +#if PY_MAJOR_VERSION < 3 + /* In Python 2, return int if it fits. */ + if (ival <= (uint64) LONG_MAX) + return PyInt_FromLong((long) ival); + else +#endif + { + /* + * Convert to Python long, picking the conversion function that + * corresponds to the underlying definition of our uint64. + */ +#ifdef HAVE_LONG_LONG + return PyLong_FromUnsignedLongLong(ival); +#else + return PyLong_FromUnsignedLong(ival); +#endif + } +} diff --git a/src/pl/plpython/plpy_util.h b/src/pl/plpython/plpy_util.h index f990bb0890..1c7e109617 100644 --- a/src/pl/plpython/plpy_util.h +++ b/src/pl/plpython/plpy_util.h @@ -14,4 +14,6 @@ extern PyObject *PLyUnicode_FromString(const char *s); extern PyObject *PLyUnicode_FromStringAndSize(const char *s, Py_ssize_t size); #endif +extern PyObject *PLyObject_FromUint64(uint64 ival); + #endif /* PLPY_UTIL_H */ -- 2.15.1