Don't limit the hstore search to the public schema only

Looks like there is a case for installing hstore somewhere else (see
ticket #45). And after all the typecaster can be registered on a list of
OIDs, so let's grab them all.
This commit is contained in:
Daniele Varrazzo 2011-02-25 00:19:49 +00:00
parent 29ac03ef04
commit 5211e1474b
4 changed files with 21 additions and 10 deletions

2
NEWS
View File

@ -28,6 +28,8 @@ What's new in psycopg 2.4
- Adapt types 'bytearray' (from Python 2.6), 'memoryview' (from Python 2.7)
and other objects implementing the "Revised Buffer Protocol" to 'bytea'
data type.
- The 'hstore' adapter can work even when the data type is not installed
in the 'public' namespace.
- Raise a clean exception instead of returning bad data when receiving bytea
in 'hex' format and the client libpq can't parse them.
- Empty lists correctly roundtrip Python -> PostgreSQL -> Python.

View File

@ -145,9 +145,9 @@ key/value pairs as well as regular BTree indexes for equality, uniqueness etc.
Psycopg can convert Python `!dict` objects to and from |hstore| structures.
Only dictionaries with string/unicode keys and values are supported. `!None`
is also allowed as value. Psycopg uses a more efficient |hstore|
is also allowed as value but not as a key. Psycopg uses a more efficient |hstore|
representation when dealing with PostgreSQL 9.0 but previous server versions
are supportes as well. By default the adapter/typecaster are disabled: they
are supported as well. By default the adapter/typecaster are disabled: they
can be enabled using the `register_hstore()` function.
.. autofunction:: register_hstore

View File

@ -663,7 +663,7 @@ class HstoreAdapter(object):
@classmethod
def get_oids(self, conn_or_curs):
"""Return the oid of the hstore and hstore[] types.
"""Return the lists of OID of the hstore and hstore[] types.
Return None if hstore is not available.
"""
@ -680,28 +680,32 @@ class HstoreAdapter(object):
# column typarray not available before PG 8.3
typarray = conn.server_version >= 80300 and "typarray" or "NULL"
rv0, rv1 = [], []
# get the oid for the hstore
curs.execute("""\
SELECT t.oid, %s
FROM pg_type t JOIN pg_namespace ns
ON typnamespace = ns.oid
WHERE typname = 'hstore' and nspname = 'public';
WHERE typname = 'hstore';
""" % typarray)
oids = curs.fetchone()
for oids in curs:
rv0.append(oids[0])
rv1.append(oids[1])
# revert the status of the connection as before the command
if (conn_status != _ext.STATUS_IN_TRANSACTION
and conn.isolation_level != _ext.ISOLATION_LEVEL_AUTOCOMMIT):
conn.rollback()
return oids
return tuple(rv0), tuple(rv1)
def register_hstore(conn_or_curs, globally=False, unicode=False, oid=None):
"""Register adapter and typecaster for `!dict`\-\ |hstore| conversions.
:param conn_or_curs: a connection or cursor: the typecaster will be
registered only on this object unless *globally* is set to `!True`
:param globally: register the adapter globally not only on *conn_or_curs*
:param globally: register the adapter globally, not only on *conn_or_curs*
:param unicode: if `!True`, keys and values returned from the database
will be `!unicode` instead of `!str`. The option is not available on
Python 3
@ -724,7 +728,9 @@ def register_hstore(conn_or_curs, globally=False, unicode=False, oid=None):
Raise `~psycopg2.ProgrammingError` if the type is not found.
.. versionchanged:: 2.4
added the *oid* parameter.
added the *oid* parameter. If not specified, the typecaster is
installed also if |hstore| is not installed in the :sql:`public`
schema.
"""
if oid is None:
oid = HstoreAdapter.get_oids(conn_or_curs)
@ -735,13 +741,16 @@ def register_hstore(conn_or_curs, globally=False, unicode=False, oid=None):
else:
oid = oid[0] # for the moment we don't have a HSTOREARRAY
if isinstance(oid, int):
oid = (oid,)
# create and register the typecaster
if sys.version_info[0] < 3 and unicode:
cast = HstoreAdapter.parse_unicode
else:
cast = HstoreAdapter.parse
HSTORE = _ext.new_type((oid,), "HSTORE", cast)
HSTORE = _ext.new_type(oid, "HSTORE", cast)
_ext.register_type(HSTORE, not globally and conn_or_curs or None)
_ext.register_adapter(dict, HstoreAdapter)

View File

@ -276,7 +276,7 @@ class HstoreTestCase(unittest.TestCase):
finally:
conn2.close()
finally:
psycopg2.extensions.string_types.pop(oids[0])
psycopg2.extensions.string_types.pop(oids[0][0])
# verify the caster is not around anymore
cur = self.conn.cursor()