mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-11-01 00:07:36 +03:00 
			
		
		
		
	Merge remote branch 'upstream/devel' into devel
Conflicts: setup.py tests/__init__.py tests/testconfig.py
This commit is contained in:
		
						commit
						3fc4dcec06
					
				|  | @ -89,14 +89,33 @@ by the `psycopg2.extensions.adapt()` function. | |||
| The `~cursor.execute()` method adapts its arguments to the | ||||
| `~psycopg2.extensions.ISQLQuote` protocol.  Objects that conform to this | ||||
| protocol expose a `!getquoted()` method returning the SQL representation | ||||
| of the object as a string. | ||||
| of the object as a string (the method must return `!bytes` in Python 3). | ||||
| Optionally the conform object may expose a | ||||
| `~psycopg2.extensions.ISQLQuote.prepare()` method. | ||||
| 
 | ||||
| The easiest way to adapt an object to an SQL string is to register an adapter | ||||
| function via the `~psycopg2.extensions.register_adapter()` function.  The | ||||
| adapter function must take the value to be adapted as argument and return a | ||||
| conform object.  A convenient object is the `~psycopg2.extensions.AsIs` | ||||
| wrapper, whose `!getquoted()` result is simply the `!str()`\ ing | ||||
| conversion of the wrapped object. | ||||
| There are two basic ways to have a Python object adapted to SQL: | ||||
| 
 | ||||
| - the object itself is conform, or knows how to make itself conform. Such | ||||
|   object must expose a `__conform__()` method that will be called with the | ||||
|   protocol object as argument. The object can check that the protocol is | ||||
|   `!ISQLQuote`, in which case it can return `!self` (if the object also | ||||
|   implements `!getquoted()`) or a suitable wrapper object. This option is | ||||
|   viable if you are the author of the object and if the object is specifically | ||||
|   designed for the database (i.e. having Psycopg as a dependency and polluting | ||||
|   its interface with the required methods doesn't bother you). For a simple | ||||
|   example you can take a look to the source code for the | ||||
|   `psycopg2.extras.Inet` object. | ||||
| 
 | ||||
| - If implementing the `!ISQLQuote` interface directly in the object is not an | ||||
|   option, you can use an adaptation function, taking the object to be adapted | ||||
|   as argument and returning a conforming object.  The adapter must be | ||||
|   registered via the `~psycopg2.extensions.register_adapter()` function.  A | ||||
|   simple example wrapper is the `!psycopg2.extras.UUID_adapter` used by the | ||||
|   `~psycopg2.extras.register_uuid()` function. | ||||
| 
 | ||||
| A convenient object to write adapters is the `~psycopg2.extensions.AsIs` | ||||
| wrapper, whose `!getquoted()` result is simply the `!str()`\ ing conversion of | ||||
| the wrapped object. | ||||
| 
 | ||||
| .. index:: | ||||
|     single: Example; Types adaptation | ||||
|  |  | |||
|  | @ -189,8 +189,9 @@ deal with Python objects adaptation: | |||
|     .. method:: getquoted() | ||||
| 
 | ||||
|         Subclasses or other conforming objects should return a valid SQL | ||||
|         string representing the wrapped object. The `!ISQLQuote` | ||||
|         implementation does nothing. | ||||
|         string representing the wrapped object. In Python 3 the SQL must be | ||||
|         returned in a `!bytes` object. The `!ISQLQuote` implementation does | ||||
|         nothing. | ||||
| 
 | ||||
|     .. method:: prepare(conn) | ||||
| 
 | ||||
|  |  | |||
|  | @ -94,6 +94,18 @@ Psycopg converts :sql:`decimal`\/\ :sql:`numeric` database types into Python `!D | |||
|     documentation. If you find `!psycopg2.extensions.DECIMAL` not avalable, use | ||||
|     `!psycopg2._psycopg.DECIMAL` instead. | ||||
| 
 | ||||
| Transferring binary data from PostgreSQL 9.0 doesn't work. | ||||
|     PostgreSQL 9.0 uses by default `the "hex" format`__ to transfer | ||||
|     :sql:`bytea` data: the format can't be parsed by the libpq 8.4 and | ||||
|     earlier. Three options to solve the problem are: | ||||
| 
 | ||||
|     - set the bytea_output__ parameter to ``escape`` in the server; | ||||
|     - use ``SET bytea_output TO escape`` in the client before reading binary | ||||
|       data; | ||||
|     - upgrade the libpq library on the client to at least 9.0. | ||||
| 
 | ||||
|     .. __: http://www.postgresql.org/docs/9.0/static/datatype-binary.html | ||||
|     .. __: http://www.postgresql.org/docs/9.0/static/runtime-config-client.html#GUC-BYTEA-OUTPUT | ||||
| 
 | ||||
| Best practices | ||||
| -------------- | ||||
|  |  | |||
|  | @ -233,15 +233,37 @@ the SQL string that would be sent to the database. | |||
| .. index:: | ||||
|     pair: Strings; Adaptation | ||||
|     single: Unicode; Adaptation | ||||
| 
 | ||||
| - String types: `!str`, `!unicode` are converted in SQL string syntax. | ||||
|   `!unicode` objects (`!str` in Python 3) are encoded in the connection | ||||
|   `~connection.encoding` to be sent to the backend: trying to send a character | ||||
|   not supported by the encoding will result in an error. Received data can be | ||||
|   converted either as `!str` or `!unicode`: see :ref:`unicode-handling` for | ||||
|   received, either `!str` or `!unicode` | ||||
| 
 | ||||
| .. index:: | ||||
|     single: Buffer; Adaptation | ||||
|     single: bytea; Adaptation | ||||
|     single: Binary string | ||||
| 
 | ||||
| - String types: `!str`, `!unicode` are converted in SQL string | ||||
|   syntax.  `!buffer` is converted in PostgreSQL binary string syntax, | ||||
|   suitable for :sql:`bytea` fields. When reading textual fields, either | ||||
|   `!str` or `!unicode` can be received: see | ||||
|   :ref:`unicode-handling`. | ||||
| - Binary types: Python types such as `!bytes`, `!bytearray`, `!buffer`, | ||||
|   `!memoryview` are converted in PostgreSQL binary string syntax, suitable for | ||||
|   :sql:`bytea` fields. Received data is returned as `!buffer` (in Python 2) or | ||||
|   `!memoryview` (in Python 3). | ||||
| 
 | ||||
|   .. warning:: | ||||
| 
 | ||||
|      PostgreSQL 9 uses by default `a new "hex" format`__ to emit :sql:`bytea` | ||||
|      fields. Unfortunately this format can't be parsed by libpq versions | ||||
|      before 9.0. This means that using a library client with version lesser | ||||
|      than 9.0 to talk with a server 9.0 or later you may have problems | ||||
|      receiving :sql:`bytea` data. To work around this problem you can set the | ||||
|      `bytea_output`__ parameter to ``escape``, either in the server | ||||
|      configuration or in the client session using a query such as ``SET | ||||
|      bytea_output TO escape;`` before trying to receive binary data. | ||||
| 
 | ||||
|      .. __: http://www.postgresql.org/docs/9.0/static/datatype-binary.html | ||||
|      .. __: http://www.postgresql.org/docs/9.0/static/runtime-config-client.html#GUC-BYTEA-OUTPUT | ||||
| 
 | ||||
| .. index:: | ||||
|     single: Adaptation; Date/Time objects | ||||
|  | @ -338,8 +360,8 @@ defined on the database connection (the `PostgreSQL encoding`__, available in | |||
| .. __: http://www.postgresql.org/docs/9.0/static/multibyte.html | ||||
| .. __: http://docs.python.org/library/codecs.html#standard-encodings | ||||
| 
 | ||||
| When reading data from the database, the strings returned are usually 8 bit | ||||
| `!str` objects encoded in the database client encoding:: | ||||
| When reading data from the database, in Python 2 the strings returned are | ||||
| usually 8 bit `!str` objects encoded in the database client encoding:: | ||||
| 
 | ||||
|     >>> print conn.encoding | ||||
|     UTF8 | ||||
|  | @ -356,9 +378,10 @@ When reading data from the database, the strings returned are usually 8 bit | |||
|     >>> print type(x), repr(x) | ||||
|     <type 'str'> '\xe0\xe8\xec\xf2\xf9\xa4' | ||||
| 
 | ||||
| In order to obtain `!unicode` objects instead, it is possible to | ||||
| register a typecaster so that PostgreSQL textual types are automatically | ||||
| *decoded* using the current client encoding:: | ||||
| In Python 3 instead the strings are automatically *decoded* in the connection | ||||
| `~connection.encoding`, as the `!str` object can represent Unicode characters. | ||||
| In Python 2 you must register a :ref:`typecaster | ||||
| <type-casting-from-sql-to-python>` in order to receive `!unicode` objects:: | ||||
| 
 | ||||
|     >>> psycopg2.extensions.register_type(psycopg2.extensions.UNICODE, cur) | ||||
| 
 | ||||
|  | @ -375,9 +398,9 @@ the connection or globally: see the function | |||
| 
 | ||||
| .. note:: | ||||
| 
 | ||||
|     If you want to receive uniformly all your database input in Unicode, you | ||||
|     can register the related typecasters globally as soon as Psycopg is | ||||
|     imported:: | ||||
|     In Python 2, if you want to receive uniformly all your database input in | ||||
|     Unicode, you can register the related typecasters globally as soon as | ||||
|     Psycopg is imported:: | ||||
| 
 | ||||
|         import psycopg2 | ||||
|         import psycopg2.extensions | ||||
|  |  | |||
|  | @ -835,14 +835,22 @@ class CompositeCaster(object): | |||
|         # Store the transaction status of the connection to revert it after use | ||||
|         conn_status = conn.status | ||||
| 
 | ||||
|         # Use the correct schema | ||||
|         if '.' in name: | ||||
|             schema, tname = name.split('.', 1) | ||||
|         else: | ||||
|             tname = name | ||||
|             schema = 'public' | ||||
| 
 | ||||
|         # get the type oid and attributes | ||||
|         curs.execute("""\ | ||||
| SELECT t.oid, attname, atttypid | ||||
| FROM pg_type t | ||||
| JOIN pg_namespace ns ON typnamespace = ns.oid | ||||
| JOIN pg_attribute a ON attrelid = typrelid | ||||
| WHERE typname = %s and nspname = 'public'; | ||||
| """, (name, )) | ||||
| WHERE typname = %s and nspname = %s | ||||
| ORDER BY attnum; | ||||
| """, (tname, schema)) | ||||
| 
 | ||||
|         recs = curs.fetchall() | ||||
| 
 | ||||
|  | @ -858,7 +866,7 @@ WHERE typname = %s and nspname = 'public'; | |||
|         type_oid = recs[0][0] | ||||
|         type_attrs = [ (r[1], r[2]) for r in recs ] | ||||
| 
 | ||||
|         return CompositeCaster(name, type_oid, type_attrs) | ||||
|         return CompositeCaster(tname, type_oid, type_attrs) | ||||
| 
 | ||||
| def register_composite(name, conn_or_curs, globally=False): | ||||
|     """Register a typecaster to convert a composite type into a tuple. | ||||
|  |  | |||
|  | @ -525,6 +525,24 @@ class AdaptTypeTestCase(unittest.TestCase): | |||
|             conn1.close() | ||||
|             conn2.close() | ||||
| 
 | ||||
|     @skip_if_no_composite | ||||
|     def test_composite_namespace(self): | ||||
|         curs = self.conn.cursor() | ||||
|         curs.execute(""" | ||||
|             select nspname from pg_namespace | ||||
|             where nspname = 'typens'; | ||||
|             """) | ||||
|         if not curs.fetchone(): | ||||
|             curs.execute("create schema typens;") | ||||
|             self.conn.commit() | ||||
| 
 | ||||
|         self._create_type("typens.typens_ii", | ||||
|             [("a", "integer"), ("b", "integer")]) | ||||
|         t = psycopg2.extras.register_composite( | ||||
|             "typens.typens_ii", self.conn) | ||||
|         curs.execute("select (4,8)::typens.typens_ii") | ||||
|         self.assertEqual(curs.fetchone()[0], (4,8)) | ||||
| 
 | ||||
|     def _create_type(self, name, fields): | ||||
|         curs = self.conn.cursor() | ||||
|         try: | ||||
|  | @ -534,11 +552,16 @@ class AdaptTypeTestCase(unittest.TestCase): | |||
| 
 | ||||
|         curs.execute("create type %s as (%s);" % (name, | ||||
|             ", ".join(["%s %s" % p for p in fields]))) | ||||
|         if '.' in name: | ||||
|             schema, name = name.split('.') | ||||
|         else: | ||||
|             schema = 'public' | ||||
| 
 | ||||
|         curs.execute("""\ | ||||
|             SELECT t.oid | ||||
|             FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid | ||||
|             WHERE typname = %s and nspname = 'public'; | ||||
|             """, (name,)) | ||||
|             WHERE typname = %s and nspname = %s; | ||||
|             """, (name, schema)) | ||||
|         oid = curs.fetchone()[0] | ||||
|         self.conn.commit() | ||||
|         return oid | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user