mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-25 18:33:44 +03:00
Merge branch 'fix-558'
This commit is contained in:
commit
2b5e131831
1
NEWS
1
NEWS
|
@ -21,6 +21,7 @@ What's new in psycopg 2.7.2
|
||||||
- Fixed `~psycopg2.extras.ReplicationCursor.consume_stream()`
|
- Fixed `~psycopg2.extras.ReplicationCursor.consume_stream()`
|
||||||
*keepalive_interval* argument (:ticket:`#547`).
|
*keepalive_interval* argument (:ticket:`#547`).
|
||||||
- Fixed random `!SystemError` upon receiving abort signal (:ticket:`#551`).
|
- Fixed random `!SystemError` upon receiving abort signal (:ticket:`#551`).
|
||||||
|
- Parse intervals returned as microseconds from Redshift (:ticket:`#558`).
|
||||||
- Added `~psycopg2.extras.Json` `!prepare()` method to consider connection
|
- Added `~psycopg2.extras.Json` `!prepare()` method to consider connection
|
||||||
params when adapting (:ticket:`#562`).
|
params when adapting (:ticket:`#562`).
|
||||||
- `~psycopg2.errorcodes` map updated to PostgreSQL 10 beta 1.
|
- `~psycopg2.errorcodes` map updated to PostgreSQL 10 beta 1.
|
||||||
|
|
|
@ -276,6 +276,44 @@ typecast_PYTIME_cast(const char *str, Py_ssize_t len, PyObject *curs)
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Attempt parsing a number as microseconds
|
||||||
|
* Redshift is reported returning this stuff, see #558
|
||||||
|
*
|
||||||
|
* Return a new `timedelta()` object in case of success or NULL and set an error
|
||||||
|
*/
|
||||||
|
static PyObject *
|
||||||
|
interval_from_usecs(const char *str)
|
||||||
|
{
|
||||||
|
PyObject *us = NULL;
|
||||||
|
char *pend;
|
||||||
|
PyObject *rv = NULL;
|
||||||
|
|
||||||
|
Dprintf("interval_from_usecs: %s", str);
|
||||||
|
|
||||||
|
if (!(us = PyLong_FromString((char *)str, &pend, 0))) {
|
||||||
|
Dprintf("interval_from_usecs: parsing long failed");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*pend != '\0') {
|
||||||
|
/* there are trailing chars, it's not just micros. Barf. */
|
||||||
|
Dprintf("interval_from_usecs: spurious chars %s", pend);
|
||||||
|
PyErr_Format(PyExc_ValueError,
|
||||||
|
"expected number of microseconds, got %s", str);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = PyObject_CallFunction(
|
||||||
|
(PyObject*)PyDateTimeAPI->DeltaType, "LLO",
|
||||||
|
0L, 0L, us);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
Py_XDECREF(us);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** INTERVAL - parse an interval into a timedelta object **/
|
/** INTERVAL - parse an interval into a timedelta object **/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -284,6 +322,7 @@ typecast_PYINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs)
|
||||||
long v = 0, years = 0, months = 0, hours = 0, minutes = 0, micros = 0;
|
long v = 0, years = 0, months = 0, hours = 0, minutes = 0, micros = 0;
|
||||||
PY_LONG_LONG days = 0, seconds = 0;
|
PY_LONG_LONG days = 0, seconds = 0;
|
||||||
int sign = 1, denom = 1, part = 0;
|
int sign = 1, denom = 1, part = 0;
|
||||||
|
const char *orig = str;
|
||||||
|
|
||||||
if (str == NULL) { Py_RETURN_NONE; }
|
if (str == NULL) { Py_RETURN_NONE; }
|
||||||
|
|
||||||
|
@ -305,6 +344,16 @@ typecast_PYINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs)
|
||||||
* or too big value. On Win where long == int the 2nd check
|
* or too big value. On Win where long == int the 2nd check
|
||||||
* is useless. */
|
* is useless. */
|
||||||
if (v1 < v || v1 > (long)INT_MAX) {
|
if (v1 < v || v1 > (long)INT_MAX) {
|
||||||
|
/* uhm, oops... but before giving up, maybe it's redshift
|
||||||
|
* returning microseconds? See #558 */
|
||||||
|
PyObject *rv;
|
||||||
|
if ((rv = interval_from_usecs(orig))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
|
||||||
PyErr_SetString(
|
PyErr_SetString(
|
||||||
PyExc_OverflowError, "interval component too big");
|
PyExc_OverflowError, "interval component too big");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -384,6 +433,10 @@ typecast_PYINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs)
|
||||||
micros = (long)round((double)micros / denom * 1000000.0);
|
micros = (long)round((double)micros / denom * 1000000.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (part == 0) {
|
||||||
|
/* Parsing failed, maybe it's just an integer? Assume usecs */
|
||||||
|
return interval_from_usecs(orig);
|
||||||
|
}
|
||||||
|
|
||||||
/* add hour, minutes, seconds together and include the sign */
|
/* add hour, minutes, seconds together and include the sign */
|
||||||
seconds += 60 * (PY_LONG_LONG)minutes + 3600 * (PY_LONG_LONG)hours;
|
seconds += 60 * (PY_LONG_LONG)minutes + 3600 * (PY_LONG_LONG)hours;
|
||||||
|
|
|
@ -411,6 +411,27 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin):
|
||||||
self.assert_(t.tzinfo is not None)
|
self.assert_(t.tzinfo is not None)
|
||||||
self.assert_(t < datetime(1000, 1, 1, tzinfo=FixedOffsetTimezone()))
|
self.assert_(t < datetime(1000, 1, 1, tzinfo=FixedOffsetTimezone()))
|
||||||
|
|
||||||
|
def test_redshift_day(self):
|
||||||
|
# Redshift is reported returning 1 day interval as microsec (bug #558)
|
||||||
|
cur = self.conn.cursor()
|
||||||
|
psycopg2.extensions.register_type(
|
||||||
|
psycopg2.extensions.new_type(
|
||||||
|
psycopg2.STRING.values, 'WAT', psycopg2.extensions.INTERVAL),
|
||||||
|
cur)
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
for s, v in [
|
||||||
|
('0', timedelta(0)),
|
||||||
|
('1', timedelta(microseconds=1)),
|
||||||
|
('-1', timedelta(microseconds=-1)),
|
||||||
|
('1000000', timedelta(seconds=1)),
|
||||||
|
('86400000000', timedelta(days=1)),
|
||||||
|
('-86400000000', timedelta(days=-1)),
|
||||||
|
]:
|
||||||
|
cur.execute("select %s::text", (s,))
|
||||||
|
r = cur.fetchone()[0]
|
||||||
|
self.assertEqual(r, v, "%s -> %s != %s" % (s, r, v))
|
||||||
|
|
||||||
|
|
||||||
# Only run the datetime tests if psycopg was compiled with support.
|
# Only run the datetime tests if psycopg was compiled with support.
|
||||||
if not hasattr(psycopg2.extensions, 'PYDATETIME'):
|
if not hasattr(psycopg2.extensions, 'PYDATETIME'):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user