Skip to content

Commit

Permalink
Fix(pg): Encode binary values for PyGreSQL driver
Browse files Browse the repository at this point in the history
Encode binary values for PyGreSQL driver using the same encoding as for
py-postgresql driver. This fixes the last remaining problems with the driver.
  • Loading branch information
phdru committed Jul 30, 2017
1 parent d1876c1 commit ade481a
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 24 deletions.
4 changes: 0 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 10 additions & 1 deletion docs/News.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
6 changes: 3 additions & 3 deletions docs/SQLObject.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1831,9 +1831,9 @@ PostgresConnection supports transactions and all other features.
The user can choose a DB API driver for PostgreSQL by using a ``driver``
parameter in DB URI or PostgresConnection that can be a comma-separated
list of driver names. Possible drivers are: ``psycopg2``, psycopg1,
``psycopg`` (tries psycopg2 and psycopg1), ``pygresql``, ``pygresql``,
``pypostgresql``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and
``pypyodbc``). Default is ``psycopg``.
``psycopg`` (tries psycopg2 and psycopg1), ``pygresql``, ``pypostgresql``,
``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``).
Default is ``psycopg``.

Connection-specific parameters are: ``sslmode``, ``unicodeCols``,
``schema``, ``charset``.
Expand Down
3 changes: 0 additions & 3 deletions sqlobject/col.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
29 changes: 16 additions & 13 deletions sqlobject/postgres/pgconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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):
Expand Down

0 comments on commit ade481a

Please sign in to comment.