diff --git a/.travis.yml b/.travis.yml index 79032aa4..ddb1252a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,10 +70,6 @@ env: matrix: allow_failures: - - env: TOXENV=py27-postgres-pygresql - - env: TOXENV=py34-postgres-pygresql - - env: TOXENV=py35-postgres-pygresql - - env: TOXENV=py36-postgres-pygresql - env: TOXENV=py27-firebird-fdb - env: TOXENV=py34-firebird-fdb - env: TOXENV=py35-firebird-fdb diff --git a/docs/News.rst b/docs/News.rst index e2a430ce..b5ba3fff 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -28,7 +28,16 @@ Drivers (work in progress) * Encode binary values for py-postgresql driver. This fixes the last remaining problems with the driver. -* Encode/decode binary values for PyGreSQL driver. +* Encode binary values for PyGreSQL driver using the same encoding as for + py-postgresql driver. This fixes the last remaining problems with the driver. + + Our own encoding is needed because unescape_bytea(escape_bytea()) is not + idempotent. See the comment for PQunescapeBytea at + https://www.postgresql.org/docs/9.6/static/libpq-exec.html: + +| This conversion is not exactly the inverse of PQescapeBytea, because the +| string is not expected to be "escaped" when received from PQgetvalue. In +| particular this means there is no need for string quoting considerations. * List all drivers in extras_require in setup.py. diff --git a/sqlobject/col.py b/sqlobject/col.py index 6ee5e98b..0f358628 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1770,9 +1770,6 @@ def to_python(self, value, state): if isinstance(value, str): if not PY2 and dbName == "mysql": value = value.encode('ascii', errors='surrogateescape') - if dbName == "postgres" and connection.driver == 'pygresql': - from pg import unescape_bytea - value = unescape_bytea(value) if dbName == "sqlite": if not PY2: value = bytes(value, 'ascii') diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 4e331855..494ff092 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -85,14 +85,9 @@ def __init__(self, dsn=None, host=None, port=None, db=None, # Register a converter for psycopg Binary type. registerConverter(type(self.module.Binary('')), PsycoBinaryConverter) - elif driver == 'pygresql': - from pg import escape_bytea as pg_escape_bytea - self.createBinary = \ - lambda value, pg_escape_bytea=pg_escape_bytea: \ - pg_escape_bytea(value) - elif driver in ('py-postgresql', 'pypostgresql'): + elif driver in ('pygresql', 'py-postgresql', 'pypostgresql'): registerConverter(type(self.module.Binary(b'')), - PypostgresBinaryConverter) + PostgresBinaryConverter) elif driver in ('odbc', 'pyodbc', 'pypyodbc'): registerConverter(bytearray, OdbcBinaryConverter) @@ -541,15 +536,23 @@ def PsycoBinaryConverter(value, db): return str(value) -def escape_bytea(value): - return ''.join( - ['\\' + (x[2:].rjust(3, '0')) for x in (oct(ord(c)) for c in value)] - ) +if PY2: + def escape_bytea(value): + return ''.join( + ['\\' + (x[1:].rjust(3, '0')) + for x in (oct(ord(c)) for c in value)] + ) +else: + def escape_bytea(value): + return ''.join( + ['\\' + (x[2:].rjust(3, '0')) + for x in (oct(ord(c)) for c in value.decode('latin1'))] + ) -def PypostgresBinaryConverter(value, db): +def PostgresBinaryConverter(value, db): assert db == 'postgres' - return sqlrepr(escape_bytea(value.decode('latin1')), db) + return sqlrepr(escape_bytea(value), db) def OdbcBinaryConverter(value, db):