mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-10-26 13:31:04 +03:00 
			
		
		
		
	Merge remote-tracking branch 'piro/devel' into devel
Conflicts: psycopg/lobject_int.c
This commit is contained in:
		
						commit
						550130b19e
					
				
							
								
								
									
										2
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								INSTALL
									
									
									
									
									
								
							|  | @ -1,7 +1,7 @@ | ||||||
| Compiling and installing psycopg | Compiling and installing psycopg | ||||||
| ******************************** | ******************************** | ||||||
| 
 | 
 | ||||||
| ** Important note: if you plan to use psyopg2 in a multithreaed application | ** Important note: if you plan to use psycopg2 in a multithreaded application, | ||||||
|    make sure that your libpq has been compiled with the --with-thread-safety |    make sure that your libpq has been compiled with the --with-thread-safety | ||||||
|    option. psycopg2 will work correctly even with a non-thread-safe libpq but |    option. psycopg2 will work correctly even with a non-thread-safe libpq but | ||||||
|    libpq will leak memory. |    libpq will leak memory. | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								NEWS
									
									
									
									
									
								
							|  | @ -1,8 +1,24 @@ | ||||||
| What's new in psycopg 2.4.5 | What's new in psycopg 2.4.5 | ||||||
| --------------------------- | --------------------------- | ||||||
| 
 | 
 | ||||||
|  |   - The close() methods on connections and cursors don't raise exceptions | ||||||
|  |     if called on already closed objects. | ||||||
|   - Fixed fetchmany() with no argument in cursor subclasses |   - Fixed fetchmany() with no argument in cursor subclasses | ||||||
|     (ticket #84). |     (ticket #84). | ||||||
|  |   - Use lo_creat() instead of lo_create() when possible for better | ||||||
|  |     interaction with pgpool-II (ticket #88). | ||||||
|  |   - Error and its subclasses are picklable, useful for multiprocessing | ||||||
|  |     interaction (ticket #90). | ||||||
|  |   - Better efficiency and formatting of timezone offset objects thanks | ||||||
|  |     to Menno Smits (tickets #94, #95). | ||||||
|  |   - Fixed 'rownumber' during iteration on cursor subclasses. | ||||||
|  |     Regression introduced in 2.4.4 (ticket #100). | ||||||
|  |   - Added support for 'inet' arrays. | ||||||
|  |   - Fixed 'commit()' concurrency problem (ticket #103). | ||||||
|  |   - Codebase cleaned up using the GCC Python plugin's static analysis | ||||||
|  |     tool, which has revealed several unchecked return values, possible | ||||||
|  |     NULL dereferences, reference counting problems. Many thanks to David | ||||||
|  |     Malcolm for the useful tool and the assistance provided using it. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| What's new in psycopg 2.4.4 | What's new in psycopg 2.4.4 | ||||||
|  |  | ||||||
|  | @ -143,7 +143,7 @@ geometric type: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. |point| replace:: :sql:`point` | .. |point| replace:: :sql:`point` | ||||||
| .. _point: http://www.postgresql.org/docs/9.0/static/datatype-geometric.html#DATATYPE-GEOMETRIC | .. _point: http://www.postgresql.org/docs/current/static/datatype-geometric.html#DATATYPE-GEOMETRIC | ||||||
| 
 | 
 | ||||||
| The above function call results in the SQL command:: | The above function call results in the SQL command:: | ||||||
| 
 | 
 | ||||||
|  | @ -246,9 +246,9 @@ documentation), you should keep the connection in `~connection.autocommit` | ||||||
| mode if you wish to receive or send notifications in a timely manner. | mode if you wish to receive or send notifications in a timely manner. | ||||||
| 
 | 
 | ||||||
| .. |LISTEN| replace:: :sql:`LISTEN` | .. |LISTEN| replace:: :sql:`LISTEN` | ||||||
| .. _LISTEN: http://www.postgresql.org/docs/9.0/static/sql-listen.html | .. _LISTEN: http://www.postgresql.org/docs/current/static/sql-listen.html | ||||||
| .. |NOTIFY| replace:: :sql:`NOTIFY` | .. |NOTIFY| replace:: :sql:`NOTIFY` | ||||||
| .. _NOTIFY: http://www.postgresql.org/docs/9.0/static/sql-notify.html | .. _NOTIFY: http://www.postgresql.org/docs/current/static/sql-notify.html | ||||||
| 
 | 
 | ||||||
| Notifications are received after every query execution. If the user is | Notifications are received after every query execution. If the user is | ||||||
| interested in receiving notifications but not in performing any query, the | interested in receiving notifications but not in performing any query, the | ||||||
|  | @ -356,7 +356,7 @@ completely non-blocking connection attempt: see the libpq documentation for | ||||||
| |PQconnectStart|_. | |PQconnectStart|_. | ||||||
| 
 | 
 | ||||||
| .. |PQconnectStart| replace:: `!PQconnectStart()` | .. |PQconnectStart| replace:: `!PQconnectStart()` | ||||||
| .. _PQconnectStart: http://www.postgresql.org/docs/9.0/static/libpq-connect.html#LIBPQ-PQCONNECTSTART | .. _PQconnectStart: http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS | ||||||
| 
 | 
 | ||||||
| The same loop should be also used to perform nonblocking queries: after | The same loop should be also used to perform nonblocking queries: after | ||||||
| sending a query via `~cursor.execute()` or `~cursor.callproc()`, call | sending a query via `~cursor.execute()` or `~cursor.callproc()`, call | ||||||
|  | @ -472,7 +472,7 @@ resources about the topic. | ||||||
| .. _gevent: http://www.gevent.org/ | .. _gevent: http://www.gevent.org/ | ||||||
| .. _SQLAlchemy: http://www.sqlalchemy.org/ | .. _SQLAlchemy: http://www.sqlalchemy.org/ | ||||||
| .. _psycogreen: http://bitbucket.org/dvarrazzo/psycogreen/ | .. _psycogreen: http://bitbucket.org/dvarrazzo/psycogreen/ | ||||||
| .. __: http://www.postgresql.org/docs/9.0/static/libpq-async.html | .. __: http://www.postgresql.org/docs/current/static/libpq-async.html | ||||||
| 
 | 
 | ||||||
| .. warning:: | .. warning:: | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -111,7 +111,7 @@ rst_epilog = """ | ||||||
| .. _DBAPI: http://www.python.org/dev/peps/pep-0249/ | .. _DBAPI: http://www.python.org/dev/peps/pep-0249/ | ||||||
| 
 | 
 | ||||||
| .. _transaction isolation level: | .. _transaction isolation level: | ||||||
|     http://www.postgresql.org/docs/9.1/static/transaction-iso.html |     http://www.postgresql.org/docs/current/static/transaction-iso.html | ||||||
| 
 | 
 | ||||||
| .. _mx.DateTime: http://www.egenix.com/products/python/mxBase/mxDateTime/ | .. _mx.DateTime: http://www.egenix.com/products/python/mxBase/mxDateTime/ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -185,7 +185,7 @@ The ``connection`` class | ||||||
|         .. seealso:: the |PREPARE TRANSACTION|_ PostgreSQL command. |         .. seealso:: the |PREPARE TRANSACTION|_ PostgreSQL command. | ||||||
| 
 | 
 | ||||||
|         .. |PREPARE TRANSACTION| replace:: :sql:`PREPARE TRANSACTION` |         .. |PREPARE TRANSACTION| replace:: :sql:`PREPARE TRANSACTION` | ||||||
|         .. _PREPARE TRANSACTION: http://www.postgresql.org/docs/9.0/static/sql-prepare-transaction.html |         .. _PREPARE TRANSACTION: http://www.postgresql.org/docs/current/static/sql-prepare-transaction.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     .. index:: |     .. index:: | ||||||
|  | @ -211,7 +211,7 @@ The ``connection`` class | ||||||
|         .. seealso:: the |COMMIT PREPARED|_ PostgreSQL command. |         .. seealso:: the |COMMIT PREPARED|_ PostgreSQL command. | ||||||
| 
 | 
 | ||||||
|         .. |COMMIT PREPARED| replace:: :sql:`COMMIT PREPARED` |         .. |COMMIT PREPARED| replace:: :sql:`COMMIT PREPARED` | ||||||
|         .. _COMMIT PREPARED: http://www.postgresql.org/docs/9.0/static/sql-commit-prepared.html |         .. _COMMIT PREPARED: http://www.postgresql.org/docs/current/static/sql-commit-prepared.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     .. index:: |     .. index:: | ||||||
|  | @ -233,7 +233,7 @@ The ``connection`` class | ||||||
|         .. seealso:: the |ROLLBACK PREPARED|_ PostgreSQL command. |         .. seealso:: the |ROLLBACK PREPARED|_ PostgreSQL command. | ||||||
| 
 | 
 | ||||||
|         .. |ROLLBACK PREPARED| replace:: :sql:`ROLLBACK PREPARED` |         .. |ROLLBACK PREPARED| replace:: :sql:`ROLLBACK PREPARED` | ||||||
|         .. _ROLLBACK PREPARED: http://www.postgresql.org/docs/9.0/static/sql-rollback-prepared.html |         .. _ROLLBACK PREPARED: http://www.postgresql.org/docs/current/static/sql-rollback-prepared.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     .. index:: |     .. index:: | ||||||
|  | @ -264,7 +264,7 @@ The ``connection`` class | ||||||
|         .. seealso:: the |pg_prepared_xacts|_ system view. |         .. seealso:: the |pg_prepared_xacts|_ system view. | ||||||
| 
 | 
 | ||||||
|         .. |pg_prepared_xacts| replace:: `pg_prepared_xacts` |         .. |pg_prepared_xacts| replace:: `pg_prepared_xacts` | ||||||
|         .. _pg_prepared_xacts: http://www.postgresql.org/docs/9.0/static/view-pg-prepared-xacts.html |         .. _pg_prepared_xacts: http://www.postgresql.org/docs/current/static/view-pg-prepared-xacts.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -296,7 +296,7 @@ The ``connection`` class | ||||||
|         |PQcancel|_. |         |PQcancel|_. | ||||||
| 
 | 
 | ||||||
|         .. |PQcancel| replace:: `!PQcancel()` |         .. |PQcancel| replace:: `!PQcancel()` | ||||||
|         .. _PQcancel: http://www.postgresql.org/docs/8.4/static/libpq-cancel.html#AEN34765 |         .. _PQcancel: http://www.postgresql.org/docs/current/static/libpq-cancel.html#LIBPQ-PQCANCEL | ||||||
| 
 | 
 | ||||||
|         .. versionadded:: 2.3 |         .. versionadded:: 2.3 | ||||||
| 
 | 
 | ||||||
|  | @ -312,10 +312,10 @@ The ``connection`` class | ||||||
|         available for recover. |         available for recover. | ||||||
| 
 | 
 | ||||||
|         .. |RESET| replace:: :sql:`RESET` |         .. |RESET| replace:: :sql:`RESET` | ||||||
|         .. _RESET: http://www.postgresql.org/docs/9.0/static/sql-reset.html |         .. _RESET: http://www.postgresql.org/docs/current/static/sql-reset.html | ||||||
| 
 | 
 | ||||||
|         .. |SET SESSION AUTHORIZATION| replace:: :sql:`SET SESSION AUTHORIZATION` |         .. |SET SESSION AUTHORIZATION| replace:: :sql:`SET SESSION AUTHORIZATION` | ||||||
|         .. __: http://www.postgresql.org/docs/9.0/static/sql-set-session-authorization.html |         .. __: http://www.postgresql.org/docs/current/static/sql-set-session-authorization.html | ||||||
| 
 | 
 | ||||||
|         .. versionadded:: 2.0.12 |         .. versionadded:: 2.0.12 | ||||||
| 
 | 
 | ||||||
|  | @ -336,7 +336,7 @@ The ``connection`` class | ||||||
|         the current session. See |SET TRANSACTION|_ for further details. |         the current session. See |SET TRANSACTION|_ for further details. | ||||||
| 
 | 
 | ||||||
|         .. |SET TRANSACTION| replace:: :sql:`SET TRANSACTION` |         .. |SET TRANSACTION| replace:: :sql:`SET TRANSACTION` | ||||||
|         .. _SET TRANSACTION: http://www.postgresql.org/docs/9.1/static/sql-set-transaction.html |         .. _SET TRANSACTION: http://www.postgresql.org/docs/current/static/sql-set-transaction.html | ||||||
| 
 | 
 | ||||||
|         :param isolation_level: set the `isolation level`_ for the next |         :param isolation_level: set the `isolation level`_ for the next | ||||||
|             transactions/statements.  The value can be one of the |             transactions/statements.  The value can be one of the | ||||||
|  | @ -357,7 +357,7 @@ The ``connection`` class | ||||||
|         parameter to the server default. |         parameter to the server default. | ||||||
| 
 | 
 | ||||||
|         .. _isolation level: |         .. _isolation level: | ||||||
|             http://www.postgresql.org/docs/9.1/static/transaction-iso.html |             http://www.postgresql.org/docs/current/static/transaction-iso.html | ||||||
| 
 | 
 | ||||||
|         The function must be invoked with no transaction in progress. At every |         The function must be invoked with no transaction in progress. At every | ||||||
|         function invocation, only the specified parameters are changed. |         function invocation, only the specified parameters are changed. | ||||||
|  | @ -367,11 +367,11 @@ The ``connection`` class | ||||||
|         |default_transaction_read_only|__, |default_transaction_deferrable|__. |         |default_transaction_read_only|__, |default_transaction_deferrable|__. | ||||||
| 
 | 
 | ||||||
|         .. |default_transaction_isolation| replace:: :sql:`default_transaction_isolation` |         .. |default_transaction_isolation| replace:: :sql:`default_transaction_isolation` | ||||||
|         .. __: http://www.postgresql.org/docs/9.1/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-ISOLATION |         .. __: http://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-ISOLATION | ||||||
|         .. |default_transaction_read_only| replace:: :sql:`default_transaction_read_only` |         .. |default_transaction_read_only| replace:: :sql:`default_transaction_read_only` | ||||||
|         .. __: http://www.postgresql.org/docs/9.1/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-READ-ONLY |         .. __: http://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-READ-ONLY | ||||||
|         .. |default_transaction_deferrable| replace:: :sql:`default_transaction_deferrable` |         .. |default_transaction_deferrable| replace:: :sql:`default_transaction_deferrable` | ||||||
|         .. __: http://www.postgresql.org/docs/9.1/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-DEFERRABLE |         .. __: http://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-DEFERRABLE | ||||||
| 
 | 
 | ||||||
|         .. note:: |         .. note:: | ||||||
| 
 | 
 | ||||||
|  | @ -445,7 +445,7 @@ The ``connection`` class | ||||||
|         is the encoding defined by the database. It should be one of the |         is the encoding defined by the database. It should be one of the | ||||||
|         `characters set supported by PostgreSQL`__ |         `characters set supported by PostgreSQL`__ | ||||||
| 
 | 
 | ||||||
|         .. __: http://www.postgresql.org/docs/9.0/static/multibyte.html |         .. __: http://www.postgresql.org/docs/current/static/multibyte.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     .. index:: |     .. index:: | ||||||
|  | @ -471,7 +471,7 @@ The ``connection`` class | ||||||
|         configuration parameters`__ such as ``log_statement``, |         configuration parameters`__ such as ``log_statement``, | ||||||
|         ``client_min_messages``, ``log_min_duration_statement`` etc. |         ``client_min_messages``, ``log_min_duration_statement`` etc. | ||||||
|          |          | ||||||
|         .. __: http://www.postgresql.org/docs/9.0/static/runtime-config-logging.html |         .. __: http://www.postgresql.org/docs/current/static/runtime-config-logging.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     .. attribute:: notifies |     .. attribute:: notifies | ||||||
|  | @ -500,7 +500,7 @@ The ``connection`` class | ||||||
| 
 | 
 | ||||||
|         .. seealso:: libpq docs for `PQbackendPID()`__ for details. |         .. seealso:: libpq docs for `PQbackendPID()`__ for details. | ||||||
| 
 | 
 | ||||||
|             .. __: http://www.postgresql.org/docs/9.0/static/libpq-status.html#LIBPQ-PQBACKENDPID |             .. __: http://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQBACKENDPID | ||||||
| 
 | 
 | ||||||
|         .. versionadded:: 2.0.8 |         .. versionadded:: 2.0.8 | ||||||
| 
 | 
 | ||||||
|  | @ -521,7 +521,7 @@ The ``connection`` class | ||||||
| 
 | 
 | ||||||
|         .. seealso:: libpq docs for `PQparameterStatus()`__ for details. |         .. seealso:: libpq docs for `PQparameterStatus()`__ for details. | ||||||
| 
 | 
 | ||||||
|             .. __: http://www.postgresql.org/docs/9.0/static/libpq-status.html#LIBPQ-PQPARAMETERSTATUS |             .. __: http://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQPARAMETERSTATUS | ||||||
| 
 | 
 | ||||||
|         .. versionadded:: 2.0.12 |         .. versionadded:: 2.0.12 | ||||||
| 
 | 
 | ||||||
|  | @ -538,7 +538,7 @@ The ``connection`` class | ||||||
| 
 | 
 | ||||||
|         .. seealso:: libpq docs for `PQtransactionStatus()`__ for details. |         .. seealso:: libpq docs for `PQtransactionStatus()`__ for details. | ||||||
| 
 | 
 | ||||||
|             .. __: http://www.postgresql.org/docs/9.0/static/libpq-status.html#LIBPQ-PQTRANSACTIONSTATUS |             .. __: http://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQTRANSACTIONSTATUS | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     .. index:: |     .. index:: | ||||||
|  | @ -553,7 +553,7 @@ The ``connection`` class | ||||||
| 
 | 
 | ||||||
|         .. seealso:: libpq docs for `PQprotocolVersion()`__ for details. |         .. seealso:: libpq docs for `PQprotocolVersion()`__ for details. | ||||||
| 
 | 
 | ||||||
|             .. __: http://www.postgresql.org/docs/9.0/static/libpq-status.html#LIBPQ-PQPROTOCOLVERSION |             .. __: http://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQPROTOCOLVERSION | ||||||
| 
 | 
 | ||||||
|         .. versionadded:: 2.0.12 |         .. versionadded:: 2.0.12 | ||||||
| 
 | 
 | ||||||
|  | @ -571,7 +571,7 @@ The ``connection`` class | ||||||
|          |          | ||||||
|         .. seealso:: libpq docs for `PQserverVersion()`__ for details. |         .. seealso:: libpq docs for `PQserverVersion()`__ for details. | ||||||
| 
 | 
 | ||||||
|             .. __: http://www.postgresql.org/docs/9.0/static/libpq-status.html#LIBPQ-PQSERVERVERSION |             .. __: http://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQSERVERVERSION | ||||||
| 
 | 
 | ||||||
|         .. versionadded:: 2.0.12 |         .. versionadded:: 2.0.12 | ||||||
| 
 | 
 | ||||||
|  | @ -606,7 +606,7 @@ The ``connection`` class | ||||||
|             `~psycopg2.extensions.lobject` to be instantiated. |             `~psycopg2.extensions.lobject` to be instantiated. | ||||||
| 
 | 
 | ||||||
|         .. |lo_import| replace:: `!lo_import()` |         .. |lo_import| replace:: `!lo_import()` | ||||||
|         .. _lo_import: http://www.postgresql.org/docs/9.0/static/lo-interfaces.html#LO-IMPORT |         .. _lo_import: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-IMPORT | ||||||
| 
 | 
 | ||||||
|         Available values for *mode* are: |         Available values for *mode* are: | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -67,10 +67,10 @@ The ``cursor`` class | ||||||
|         |execute*|_ methods yet. |         |execute*|_ methods yet. | ||||||
|          |          | ||||||
|         .. |pg_type| replace:: :sql:`pg_type` |         .. |pg_type| replace:: :sql:`pg_type` | ||||||
|         .. _pg_type: http://www.postgresql.org/docs/9.0/static/catalog-pg-type.html |         .. _pg_type: http://www.postgresql.org/docs/current/static/catalog-pg-type.html | ||||||
|         .. _PQgetlength: http://www.postgresql.org/docs/9.0/static/libpq-exec.html#LIBPQ-PQGETLENGTH |         .. _PQgetlength: http://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQGETLENGTH | ||||||
|         .. _PQfsize: http://www.postgresql.org/docs/9.0/static/libpq-exec.html#LIBPQ-PQFSIZE |         .. _PQfsize: http://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQFSIZE | ||||||
|         .. _NUMERIC: http://www.postgresql.org/docs/9.0/static/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL |         .. _NUMERIC: http://www.postgresql.org/docs/current/static/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL | ||||||
|         .. |NUMERIC| replace:: :sql:`NUMERIC` |         .. |NUMERIC| replace:: :sql:`NUMERIC` | ||||||
| 
 | 
 | ||||||
|         .. versionchanged:: 2.4 |         .. versionchanged:: 2.4 | ||||||
|  | @ -378,10 +378,10 @@ The ``cursor`` class | ||||||
|             more flexibility. |             more flexibility. | ||||||
| 
 | 
 | ||||||
|         .. |CREATE-TABLE| replace:: :sql:`CREATE TABLE` |         .. |CREATE-TABLE| replace:: :sql:`CREATE TABLE` | ||||||
|         .. __: http://www.postgresql.org/docs/9.0/static/sql-createtable.html |         .. __: http://www.postgresql.org/docs/current/static/sql-createtable.html | ||||||
| 
 | 
 | ||||||
|         .. |INSERT-RETURNING| replace:: :sql:`INSERT ... RETURNING` |         .. |INSERT-RETURNING| replace:: :sql:`INSERT ... RETURNING` | ||||||
|         .. __: http://www.postgresql.org/docs/9.0/static/sql-insert.html |         .. __: http://www.postgresql.org/docs/current/static/sql-insert.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     .. attribute:: query |     .. attribute:: query | ||||||
|  | @ -467,7 +467,7 @@ The ``cursor`` class | ||||||
|         :param table: name of the table to copy data into. |         :param table: name of the table to copy data into. | ||||||
|         :param sep: columns separator expected in the file. Defaults to a tab. |         :param sep: columns separator expected in the file. Defaults to a tab. | ||||||
|         :param null: textual representation of :sql:`NULL` in the file. |         :param null: textual representation of :sql:`NULL` in the file. | ||||||
|             The default is the two character string ``\N``. |             The default is the two characters string ``\N``. | ||||||
|         :param size: size of the buffer used to read from the file. |         :param size: size of the buffer used to read from the file. | ||||||
|         :param columns: iterable with name of the columns to import. |         :param columns: iterable with name of the columns to import. | ||||||
|             The length and types should match the content of the file to read. |             The length and types should match the content of the file to read. | ||||||
|  | @ -500,7 +500,7 @@ The ``cursor`` class | ||||||
|         :param table: name of the table to copy data from. |         :param table: name of the table to copy data from. | ||||||
|         :param sep: columns separator expected in the file. Defaults to a tab. |         :param sep: columns separator expected in the file. Defaults to a tab. | ||||||
|         :param null: textual representation of :sql:`NULL` in the file. |         :param null: textual representation of :sql:`NULL` in the file. | ||||||
|             The default is the two character string ``\N``. |             The default is the two characters string ``\N``. | ||||||
|         :param columns: iterable with name of the columns to export. |         :param columns: iterable with name of the columns to export. | ||||||
|             If not specified, export all the columns. |             If not specified, export all the columns. | ||||||
| 
 | 
 | ||||||
|  | @ -540,7 +540,7 @@ The ``cursor`` class | ||||||
|             ... |             ... | ||||||
| 
 | 
 | ||||||
|         .. |COPY| replace:: :sql:`COPY` |         .. |COPY| replace:: :sql:`COPY` | ||||||
|         .. __: http://www.postgresql.org/docs/9.0/static/sql-copy.html |         .. __: http://www.postgresql.org/docs/current/static/sql-copy.html | ||||||
| 
 | 
 | ||||||
|         .. versionadded:: 2.0.6 |         .. versionadded:: 2.0.6 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -39,7 +39,7 @@ From PostgreSQL documentation: | ||||||
| 
 | 
 | ||||||
| .. seealso:: `PostgreSQL Error Codes table`__ | .. seealso:: `PostgreSQL Error Codes table`__ | ||||||
| 
 | 
 | ||||||
|     .. __: http://www.postgresql.org/docs/9.0/static/errcodes-appendix.html#ERRCODES-TABLE |     .. __: http://www.postgresql.org/docs/current/static/errcodes-appendix.html#ERRCODES-TABLE | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| An example of the available constants defined in the module: | An example of the available constants defined in the module: | ||||||
|  |  | ||||||
|  | @ -82,7 +82,7 @@ functionalities defined by the |DBAPI|_. | ||||||
|         The method uses the efficient |lo_export|_ libpq function. |         The method uses the efficient |lo_export|_ libpq function. | ||||||
|          |          | ||||||
|         .. |lo_export| replace:: `!lo_export()` |         .. |lo_export| replace:: `!lo_export()` | ||||||
|         .. _lo_export: http://www.postgresql.org/docs/9.0/static/lo-interfaces.html#LO-EXPORT |         .. _lo_export: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-EXPORT | ||||||
| 
 | 
 | ||||||
|     .. method:: seek(offset, whence=0) |     .. method:: seek(offset, whence=0) | ||||||
| 
 | 
 | ||||||
|  | @ -103,7 +103,7 @@ functionalities defined by the |DBAPI|_. | ||||||
|         running these versions. It uses the |lo_truncate|_ libpq function. |         running these versions. It uses the |lo_truncate|_ libpq function. | ||||||
| 
 | 
 | ||||||
|         .. |lo_truncate| replace:: `!lo_truncate()` |         .. |lo_truncate| replace:: `!lo_truncate()` | ||||||
|         .. _lo_truncate: http://www.postgresql.org/docs/9.0/static/lo-interfaces.html#LO-TRUNCATE |         .. _lo_truncate: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-TRUNCATE | ||||||
| 
 | 
 | ||||||
|     .. method:: close() |     .. method:: close() | ||||||
| 
 | 
 | ||||||
|  | @ -325,6 +325,20 @@ details. | ||||||
| 
 | 
 | ||||||
|     .. versionadded:: 2.4.3 |     .. versionadded:: 2.4.3 | ||||||
| 
 | 
 | ||||||
|  |     .. _cast-array-unknown: | ||||||
|  | 
 | ||||||
|  |     .. note:: | ||||||
|  | 
 | ||||||
|  |         The function can be used to create a generic array typecaster, | ||||||
|  |         returning a list of strings: just use the `~psycopg2.STRING` as base | ||||||
|  |         typecaster. For instance, if you want to receive from the database an | ||||||
|  |         array of :sql:`macaddr`, each address represented by string, you can | ||||||
|  |         use:: | ||||||
|  | 
 | ||||||
|  |             psycopg2.extensions.register_type( | ||||||
|  |                 psycopg2.extensions.new_array_type( | ||||||
|  |                     (1040,), 'MACADDR[]', psycopg2.STRING)) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| .. function:: register_type(obj [, scope]) | .. function:: register_type(obj [, scope]) | ||||||
| 
 | 
 | ||||||
|  | @ -349,7 +363,7 @@ details. | ||||||
|     Used by Psycopg when adapting or casting unicode strings. See |     Used by Psycopg when adapting or casting unicode strings. See | ||||||
|     :ref:`unicode-handling`. |     :ref:`unicode-handling`. | ||||||
| 
 | 
 | ||||||
|     .. __: http://www.postgresql.org/docs/9.0/static/multibyte.html |     .. __: http://www.postgresql.org/docs/current/static/multibyte.html | ||||||
|     .. __: http://docs.python.org/library/codecs.html#standard-encodings |     .. __: http://docs.python.org/library/codecs.html#standard-encodings | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -432,7 +446,7 @@ set to one of the following constants: | ||||||
|     .. seealso:: `Read Committed Isolation Level`__ in PostgreSQL |     .. seealso:: `Read Committed Isolation Level`__ in PostgreSQL | ||||||
|         documentation. |         documentation. | ||||||
| 
 | 
 | ||||||
|         .. __: http://www.postgresql.org/docs/9.1/static/transaction-iso.html#XACT-READ-COMMITTED |         .. __: http://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-READ-COMMITTED | ||||||
| 
 | 
 | ||||||
| .. data:: ISOLATION_LEVEL_REPEATABLE_READ | .. data:: ISOLATION_LEVEL_REPEATABLE_READ | ||||||
| 
 | 
 | ||||||
|  | @ -456,7 +470,7 @@ set to one of the following constants: | ||||||
|     .. seealso:: `Repeatable Read Isolation Level`__ in PostgreSQL |     .. seealso:: `Repeatable Read Isolation Level`__ in PostgreSQL | ||||||
|         documentation. |         documentation. | ||||||
| 
 | 
 | ||||||
|         .. __: http://www.postgresql.org/docs/9.1/static/transaction-iso.html#XACT-REPEATABLE-READ |         .. __: http://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-REPEATABLE-READ | ||||||
| 
 | 
 | ||||||
| .. data:: ISOLATION_LEVEL_SERIALIZABLE | .. data:: ISOLATION_LEVEL_SERIALIZABLE | ||||||
| 
 | 
 | ||||||
|  | @ -475,7 +489,7 @@ set to one of the following constants: | ||||||
| 
 | 
 | ||||||
|     .. seealso:: `Serializable Isolation Level`__ in PostgreSQL documentation. |     .. seealso:: `Serializable Isolation Level`__ in PostgreSQL documentation. | ||||||
| 
 | 
 | ||||||
|         .. __: http://www.postgresql.org/docs/9.1/static/transaction-iso.html#XACT-SERIALIZABLE |         .. __: http://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-SERIALIZABLE | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -155,7 +155,7 @@ can be enabled using the `register_hstore()` function. | ||||||
| .. autofunction:: register_hstore | .. autofunction:: register_hstore | ||||||
| 
 | 
 | ||||||
| .. |hstore| replace:: :sql:`hstore` | .. |hstore| replace:: :sql:`hstore` | ||||||
| .. _hstore: http://www.postgresql.org/docs/9.0/static/hstore.html | .. _hstore: http://www.postgresql.org/docs/current/static/hstore.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -177,7 +177,7 @@ after a table row type) into a Python named tuple, or into a regular tuple if | ||||||
| :py:func:`collections.namedtuple` is not found. | :py:func:`collections.namedtuple` is not found. | ||||||
| 
 | 
 | ||||||
| .. |CREATE TYPE| replace:: :sql:`CREATE TYPE` | .. |CREATE TYPE| replace:: :sql:`CREATE TYPE` | ||||||
| .. _CREATE TYPE: http://www.postgresql.org/docs/9.0/static/sql-createtype.html | .. _CREATE TYPE: http://www.postgresql.org/docs/current/static/sql-createtype.html | ||||||
| 
 | 
 | ||||||
| .. doctest:: | .. doctest:: | ||||||
| 
 | 
 | ||||||
|  | @ -250,6 +250,7 @@ UUID data type | ||||||
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^ | ||||||
| 
 | 
 | ||||||
| .. versionadded:: 2.0.9 | .. versionadded:: 2.0.9 | ||||||
|  | .. versionchanged:: 2.4.5 added inet array support. | ||||||
| 
 | 
 | ||||||
| .. doctest:: | .. doctest:: | ||||||
| 
 | 
 | ||||||
|  | @ -264,7 +265,7 @@ UUID data type | ||||||
|     '192.168.0.1/24' |     '192.168.0.1/24' | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. autofunction:: register_inet() | .. autofunction:: register_inet | ||||||
| 
 | 
 | ||||||
| .. autoclass:: Inet | .. autoclass:: Inet | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -33,7 +33,7 @@ I receive the error *current transaction is aborted, commands ignored until end | ||||||
|     PostgreSQL supports nested transactions using the |SAVEPOINT|_ command). |     PostgreSQL supports nested transactions using the |SAVEPOINT|_ command). | ||||||
| 
 | 
 | ||||||
|     .. |SAVEPOINT| replace:: :sql:`SAVEPOINT` |     .. |SAVEPOINT| replace:: :sql:`SAVEPOINT` | ||||||
|     .. _SAVEPOINT: http://www.postgresql.org/docs/9.0/static/sql-savepoint.html |     .. _SAVEPOINT: http://www.postgresql.org/docs/current/static/sql-savepoint.html | ||||||
| 
 | 
 | ||||||
| Why do I get the error *current transaction is aborted, commands ignored until end of transaction block* when I use `!multiprocessing` (or any other forking system) and not when use `!threading`? | Why do I get the error *current transaction is aborted, commands ignored until end of transaction block* when I use `!multiprocessing` (or any other forking system) and not when use `!threading`? | ||||||
|     Psycopg's connections can't be shared across processes (but are thread |     Psycopg's connections can't be shared across processes (but are thread | ||||||
|  | @ -106,8 +106,15 @@ Transferring binary data from PostgreSQL 9.0 doesn't work. | ||||||
|       session before reading binary data; |       session before reading binary data; | ||||||
|     - upgrade the libpq library on the client to at least 9.0. |     - 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/current/static/datatype-binary.html | ||||||
|     .. __: http://www.postgresql.org/docs/9.0/static/runtime-config-client.html#GUC-BYTEA-OUTPUT |     .. __: http://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-BYTEA-OUTPUT | ||||||
|  | 
 | ||||||
|  | Arrays of *TYPE* are not casted to list. | ||||||
|  |     Arrays are only casted to list when their oid is known, and an array | ||||||
|  |     typecaster is registered for them. If there is no typecaster, the array is | ||||||
|  |     returned unparsed from PostgreSQL (e.g. ``{a,b,c}``). It is easy to create | ||||||
|  |     a generic arrays typecaster, returning a list of array: an example is | ||||||
|  |     provided in the `~psycopg2.extensions.new_array_type()` documentation. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Best practices | Best practices | ||||||
|  |  | ||||||
|  | @ -32,9 +32,9 @@ Psycopg 2 is both Unicode and Python 3 friendly. | ||||||
| .. _PostgreSQL: http://www.postgresql.org/ | .. _PostgreSQL: http://www.postgresql.org/ | ||||||
| .. _Python: http://www.python.org/ | .. _Python: http://www.python.org/ | ||||||
| .. _Zope: http://www.zope.org/ | .. _Zope: http://www.zope.org/ | ||||||
| .. _libpq: http://www.postgresql.org/docs/9.0/static/libpq.html | .. _libpq: http://www.postgresql.org/docs/current/static/libpq.html | ||||||
| .. |COPY-TO-FROM| replace:: :sql:`COPY TO/COPY FROM` | .. |COPY-TO-FROM| replace:: :sql:`COPY TO/COPY FROM` | ||||||
| .. __: http://www.postgresql.org/docs/9.0/static/sql-copy.html | .. __: http://www.postgresql.org/docs/current/static/sql-copy.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. rubric:: Contents | .. rubric:: Contents | ||||||
|  |  | ||||||
|  | @ -43,8 +43,8 @@ The module interface respects the standard defined in the |DBAPI|_. | ||||||
|     Also note that the same parameters can be passed to the client library |     Also note that the same parameters can be passed to the client library | ||||||
|     using `environment variables`__. |     using `environment variables`__. | ||||||
| 
 | 
 | ||||||
|     .. __: http://www.postgresql.org/docs/9.1/static/libpq-connect.html#LIBPQ-PQCONNECTDBPARAMS |     .. __: http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PQCONNECTDBPARAMS | ||||||
|     .. __: http://www.postgresql.org/docs/9.1/static/libpq-envars.html |     .. __: http://www.postgresql.org/docs/current/static/libpq-envars.html | ||||||
| 
 | 
 | ||||||
|     Using the *connection_factory* parameter a different class or |     Using the *connection_factory* parameter a different class or | ||||||
|     connections factory can be specified. It should be a callable object |     connections factory can be specified. It should be a callable object | ||||||
|  | @ -117,11 +117,6 @@ available through the following exceptions: | ||||||
|         if not available.  The `~psycopg2.errorcodes` module contains |         if not available.  The `~psycopg2.errorcodes` module contains | ||||||
|         symbolic constants representing PostgreSQL error codes. |         symbolic constants representing PostgreSQL error codes. | ||||||
| 
 | 
 | ||||||
|     .. extension:: |  | ||||||
| 
 |  | ||||||
|         The `~Error.pgerror` and `~Error.pgcode` attributes are |  | ||||||
|         Psycopg extensions. |  | ||||||
| 
 |  | ||||||
|     .. doctest:: |     .. doctest:: | ||||||
|         :options: +NORMALIZE_WHITESPACE |         :options: +NORMALIZE_WHITESPACE | ||||||
| 
 | 
 | ||||||
|  | @ -136,10 +131,14 @@ available through the following exceptions: | ||||||
|         ERROR:  relation "barf" does not exist |         ERROR:  relation "barf" does not exist | ||||||
|         LINE 1: SELECT * FROM barf |         LINE 1: SELECT * FROM barf | ||||||
|                               ^ |                               ^ | ||||||
|  |     .. attribute:: cursor | ||||||
| 
 | 
 | ||||||
|     .. versionchanged:: 2.0.7 added `Error.pgerror` and |         The cursor the exception was raised from; `None` if not applicable. | ||||||
|         `Error.pgcode` attributes. |  | ||||||
| 
 | 
 | ||||||
|  |     .. extension:: | ||||||
|  | 
 | ||||||
|  |         The `~Error.pgerror`, `~Error.pgcode`, and `~Error.cursor` attributes | ||||||
|  |         are Psycopg extensions. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. exception:: InterfaceError | .. exception:: InterfaceError | ||||||
|  |  | ||||||
|  | @ -295,8 +295,8 @@ the SQL string that would be sent to the database. | ||||||
|      server configuration file or in the client session (using a query such as |      server configuration file or in the client session (using a query such as | ||||||
|      ``SET bytea_output TO escape;``) before receiving binary data. |      ``SET bytea_output TO escape;``) before receiving binary data. | ||||||
| 
 | 
 | ||||||
|      .. __: http://www.postgresql.org/docs/9.0/static/datatype-binary.html |      .. __: http://www.postgresql.org/docs/current/static/datatype-binary.html | ||||||
|      .. __: http://www.postgresql.org/docs/9.0/static/runtime-config-client.html#GUC-BYTEA-OUTPUT |      .. __: http://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-BYTEA-OUTPUT | ||||||
| 
 | 
 | ||||||
| .. _adapt-date: | .. _adapt-date: | ||||||
| 
 | 
 | ||||||
|  | @ -334,6 +334,14 @@ the SQL string that would be sent to the database. | ||||||
|     >>> cur.mogrify("SELECT %s;", ([10, 20, 30], )) |     >>> cur.mogrify("SELECT %s;", ([10, 20, 30], )) | ||||||
|     'SELECT ARRAY[10, 20, 30];' |     'SELECT ARRAY[10, 20, 30];' | ||||||
| 
 | 
 | ||||||
|  |   .. note:: | ||||||
|  | 
 | ||||||
|  |     Reading back from PostgreSQL, arrays are converted to list of Python | ||||||
|  |     objects as expected, but only if the types are known one. Arrays of | ||||||
|  |     unknown types are returned as represented by the database (e.g. | ||||||
|  |     ``{a,b,c}``). You can easily create a typecaster for :ref:`array of | ||||||
|  |     unknown types <cast-array-unknown>`. | ||||||
|  | 
 | ||||||
| .. _adapt-tuple: | .. _adapt-tuple: | ||||||
| 
 | 
 | ||||||
| .. index:: | .. index:: | ||||||
|  | @ -378,7 +386,7 @@ the SQL string that would be sent to the database. | ||||||
|   further details. |   further details. | ||||||
| 
 | 
 | ||||||
|   .. |hstore| replace:: :sql:`hstore` |   .. |hstore| replace:: :sql:`hstore` | ||||||
|   .. _hstore: http://www.postgresql.org/docs/9.0/static/hstore.html |   .. _hstore: http://www.postgresql.org/docs/current/static/hstore.html | ||||||
| 
 | 
 | ||||||
|   .. versionadded:: 2.3 |   .. versionadded:: 2.3 | ||||||
|      the :sql:`hstore` adaptation. |      the :sql:`hstore` adaptation. | ||||||
|  | @ -403,7 +411,7 @@ defined on the database connection (the `PostgreSQL encoding`__, available in | ||||||
| 
 | 
 | ||||||
|     >>> cur.execute("INSERT INTO test (num, data) VALUES (%s,%s);", (74, u)) |     >>> cur.execute("INSERT INTO test (num, data) VALUES (%s,%s);", (74, u)) | ||||||
| 
 | 
 | ||||||
| .. __: http://www.postgresql.org/docs/9.0/static/multibyte.html | .. __: http://www.postgresql.org/docs/current/static/multibyte.html | ||||||
| .. __: http://docs.python.org/library/codecs.html#standard-encodings | .. __: http://docs.python.org/library/codecs.html#standard-encodings | ||||||
| 
 | 
 | ||||||
| When reading data from the database, in Python 2 the strings returned are | When reading data from the database, in Python 2 the strings returned are | ||||||
|  | @ -621,7 +629,7 @@ lifetime extends well after `~connection.commit()`, calling | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. |DECLARE| replace:: :sql:`DECLARE` | .. |DECLARE| replace:: :sql:`DECLARE` | ||||||
| .. _DECLARE: http://www.postgresql.org/docs/9.0/static/sql-declare.html | .. _DECLARE: http://www.postgresql.org/docs/current/static/sql-declare.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -651,7 +659,7 @@ forked processes`__, so when using a module such as `multiprocessing` or a | ||||||
| forking web deploy method such as FastCGI make sure to create the connections | forking web deploy method such as FastCGI make sure to create the connections | ||||||
| *after* the fork. | *after* the fork. | ||||||
| 
 | 
 | ||||||
| .. __: http://www.postgresql.org/docs/9.0/static/libpq-connect.html#LIBPQ-CONNECT | .. __: http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNECT | ||||||
| 
 | 
 | ||||||
| Connections shouldn't be shared either by different green threads: see | Connections shouldn't be shared either by different green threads: see | ||||||
| :ref:`green-support` for further details. | :ref:`green-support` for further details. | ||||||
|  | @ -687,7 +695,7 @@ Please refer to the documentation of the single methods for details and | ||||||
| examples. | examples. | ||||||
| 
 | 
 | ||||||
| .. |COPY| replace:: :sql:`COPY` | .. |COPY| replace:: :sql:`COPY` | ||||||
| .. __: http://www.postgresql.org/docs/9.0/static/sql-copy.html | .. __: http://www.postgresql.org/docs/current/static/sql-copy.html | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -704,7 +712,7 @@ access to user data that is stored in a special large-object structure. They | ||||||
| are useful with data values too large to be manipulated conveniently as a | are useful with data values too large to be manipulated conveniently as a | ||||||
| whole. | whole. | ||||||
| 
 | 
 | ||||||
| .. __: http://www.postgresql.org/docs/9.0/static/largeobjects.html | .. __: http://www.postgresql.org/docs/current/static/largeobjects.html | ||||||
| 
 | 
 | ||||||
| Psycopg allows access to the large object using the | Psycopg allows access to the large object using the | ||||||
| `~psycopg2.extensions.lobject` class. Objects are generated using the | `~psycopg2.extensions.lobject` class. Objects are generated using the | ||||||
|  | @ -715,9 +723,9 @@ Psycopg large object support efficient import/export with file system files | ||||||
| using the |lo_import|_ and |lo_export|_ libpq functions. | using the |lo_import|_ and |lo_export|_ libpq functions. | ||||||
| 
 | 
 | ||||||
| .. |lo_import| replace:: `!lo_import()` | .. |lo_import| replace:: `!lo_import()` | ||||||
| .. _lo_import: http://www.postgresql.org/docs/9.0/static/lo-interfaces.html#LO-IMPORT | .. _lo_import: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-IMPORT | ||||||
| .. |lo_export| replace:: `!lo_export()` | .. |lo_export| replace:: `!lo_export()` | ||||||
| .. _lo_export: http://www.postgresql.org/docs/9.0/static/lo-interfaces.html#LO-EXPORT | .. _lo_export: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-EXPORT | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ This module contains symbolic names for all PostgreSQL error codes. | ||||||
| # | # | ||||||
| # Based on: | # Based on: | ||||||
| # | # | ||||||
| #   http://www.postgresql.org/docs/8.4/static/errcodes-appendix.html | #   http://www.postgresql.org/docs/current/static/errcodes-appendix.html | ||||||
| # | # | ||||||
| 
 | 
 | ||||||
| def lookup(code, _cache={}): | def lookup(code, _cache={}): | ||||||
|  |  | ||||||
|  | @ -88,25 +88,17 @@ class DictCursorBase(_cursor): | ||||||
| 
 | 
 | ||||||
|     def __iter__(self): |     def __iter__(self): | ||||||
|         if self._prefetch: |         if self._prefetch: | ||||||
|             res = _cursor.fetchmany(self, self.itersize) |             res = _cursor.__iter__(self) | ||||||
|             if not res: |             first = res.next() | ||||||
|                 return |  | ||||||
|         if self._query_executed: |         if self._query_executed: | ||||||
|             self._build_index() |             self._build_index() | ||||||
|         if not self._prefetch: |         if not self._prefetch: | ||||||
|             res = _cursor.fetchmany(self, self.itersize) |             res = _cursor.__iter__(self) | ||||||
|  |             first = res.next() | ||||||
| 
 | 
 | ||||||
|         for r in res: |         yield first | ||||||
|             yield r |  | ||||||
| 
 |  | ||||||
|         # the above was the first itersize record. the following are |  | ||||||
|         # in a repeated loop. |  | ||||||
|         while 1: |         while 1: | ||||||
|             res = _cursor.fetchmany(self, self.itersize) |             yield res.next() | ||||||
|             if not res: |  | ||||||
|                 return |  | ||||||
|             for r in res: |  | ||||||
|                 yield r |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class DictConnection(_connection): | class DictConnection(_connection): | ||||||
|  | @ -318,14 +310,17 @@ class NamedTupleCursor(_cursor): | ||||||
|         return [nt(*t) for t in ts] |         return [nt(*t) for t in ts] | ||||||
| 
 | 
 | ||||||
|     def __iter__(self): |     def __iter__(self): | ||||||
|         # Invoking _cursor.__iter__(self) goes to infinite recursion, |         it = _cursor.__iter__(self) | ||||||
|         # so we do pagination by hand |         t = it.next() | ||||||
|  | 
 | ||||||
|  |         nt = self.Record | ||||||
|  |         if nt is None: | ||||||
|  |             nt = self.Record = self._make_nt() | ||||||
|  | 
 | ||||||
|  |         yield nt(*t) | ||||||
|  | 
 | ||||||
|         while 1: |         while 1: | ||||||
|             recs = self.fetchmany(self.itersize) |             yield nt(*it.next()) | ||||||
|             if not recs: |  | ||||||
|                 return |  | ||||||
|             for rec in recs: |  | ||||||
|                 yield rec |  | ||||||
| 
 | 
 | ||||||
|     try: |     try: | ||||||
|         from collections import namedtuple |         from collections import namedtuple | ||||||
|  | @ -445,7 +440,7 @@ class UUID_adapter(object): | ||||||
|     """Adapt Python's uuid.UUID__ type to PostgreSQL's uuid__. |     """Adapt Python's uuid.UUID__ type to PostgreSQL's uuid__. | ||||||
| 
 | 
 | ||||||
|     .. __: http://docs.python.org/library/uuid.html |     .. __: http://docs.python.org/library/uuid.html | ||||||
|     .. __: http://www.postgresql.org/docs/8.4/static/datatype-uuid.html |     .. __: http://www.postgresql.org/docs/current/static/datatype-uuid.html | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, uuid): |     def __init__(self, uuid): | ||||||
|  | @ -460,31 +455,29 @@ class UUID_adapter(object): | ||||||
|     __str__ = getquoted |     __str__ = getquoted | ||||||
| 
 | 
 | ||||||
| def register_uuid(oids=None, conn_or_curs=None): | def register_uuid(oids=None, conn_or_curs=None): | ||||||
|     """Create the UUID type and an uuid.UUID adapter.""" |     """Create the UUID type and an uuid.UUID adapter. | ||||||
|  | 
 | ||||||
|  |     :param oids: oid for the PostgreSQL :sql:`uuid` type, or 2-items sequence | ||||||
|  |         with oids of the type and the array. If not specified, use PostgreSQL | ||||||
|  |         standard oids. | ||||||
|  |     :param conn_or_curs: where to register the typecaster. If not specified, | ||||||
|  |         register it globally. | ||||||
|  |     """ | ||||||
| 
 | 
 | ||||||
|     import uuid |     import uuid | ||||||
| 
 | 
 | ||||||
|     if not oids: |     if not oids: | ||||||
|         oid1 = 2950 |         oid1 = 2950 | ||||||
|         oid2 = 2951 |         oid2 = 2951 | ||||||
|     elif type(oids) == list: |     elif isinstance(oids, (list, tuple)): | ||||||
|         oid1, oid2 = oids |         oid1, oid2 = oids | ||||||
|     else: |     else: | ||||||
|         oid1 = oids |         oid1 = oids | ||||||
|         oid2 = 2951 |         oid2 = 2951 | ||||||
| 
 | 
 | ||||||
|     def parseUUIDARRAY(data, cursor): |  | ||||||
|         if data is None: |  | ||||||
|             return None |  | ||||||
|         elif data == '{}': |  | ||||||
|             return [] |  | ||||||
|         else: |  | ||||||
|             return [((len(x) > 0 and x != 'NULL') and uuid.UUID(x) or None) |  | ||||||
|                     for x in data[1:-1].split(',')] |  | ||||||
| 
 |  | ||||||
|     _ext.UUID = _ext.new_type((oid1, ), "UUID", |     _ext.UUID = _ext.new_type((oid1, ), "UUID", | ||||||
|             lambda data, cursor: data and uuid.UUID(data) or None) |             lambda data, cursor: data and uuid.UUID(data) or None) | ||||||
|     _ext.UUIDARRAY = _ext.new_type((oid2,), "UUID[]", parseUUIDARRAY) |     _ext.UUIDARRAY = _ext.new_array_type((oid2,), "UUID[]", _ext.UUID) | ||||||
| 
 | 
 | ||||||
|     _ext.register_type(_ext.UUID, conn_or_curs) |     _ext.register_type(_ext.UUID, conn_or_curs) | ||||||
|     _ext.register_type(_ext.UUIDARRAY, conn_or_curs) |     _ext.register_type(_ext.UUIDARRAY, conn_or_curs) | ||||||
|  | @ -526,11 +519,30 @@ class Inet(object): | ||||||
|         return str(self.addr) |         return str(self.addr) | ||||||
| 
 | 
 | ||||||
| def register_inet(oid=None, conn_or_curs=None): | def register_inet(oid=None, conn_or_curs=None): | ||||||
|     """Create the INET type and an Inet adapter.""" |     """Create the INET type and an Inet adapter. | ||||||
|     if not oid: oid = 869 | 
 | ||||||
|     _ext.INET = _ext.new_type((oid, ), "INET", |     :param oid: oid for the PostgreSQL :sql:`inet` type, or 2-items sequence | ||||||
|  |         with oids of the type and the array. If not specified, use PostgreSQL | ||||||
|  |         standard oids. | ||||||
|  |     :param conn_or_curs: where to register the typecaster. If not specified, | ||||||
|  |         register it globally. | ||||||
|  |     """ | ||||||
|  |     if not oid: | ||||||
|  |         oid1 = 869 | ||||||
|  |         oid2 = 1041 | ||||||
|  |     elif isinstance(oid, (list, tuple)): | ||||||
|  |         oid1, oid2 = oid | ||||||
|  |     else: | ||||||
|  |         oid1 = oid | ||||||
|  |         oid2 = 1041 | ||||||
|  | 
 | ||||||
|  |     _ext.INET = _ext.new_type((oid1, ), "INET", | ||||||
|             lambda data, cursor: data and Inet(data) or None) |             lambda data, cursor: data and Inet(data) or None) | ||||||
|  |     _ext.INETARRAY = _ext.new_array_type((oid2, ), "INETARRAY", _ext.INET) | ||||||
|  | 
 | ||||||
|     _ext.register_type(_ext.INET, conn_or_curs) |     _ext.register_type(_ext.INET, conn_or_curs) | ||||||
|  |     _ext.register_type(_ext.INETARRAY, conn_or_curs) | ||||||
|  | 
 | ||||||
|     return _ext.INET |     return _ext.INET | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -849,9 +861,9 @@ class CompositeCaster(object): | ||||||
|         return self._ctor(*attrs) |         return self._ctor(*attrs) | ||||||
| 
 | 
 | ||||||
|     _re_tokenize = regex.compile(r""" |     _re_tokenize = regex.compile(r""" | ||||||
|   \(? ([,\)])                       # an empty token, representing NULL |   \(? ([,)])                        # an empty token, representing NULL | ||||||
| | \(? " ((?: [^"] | "")*) " [,)]    # or a quoted string | | \(? " ((?: [^"] | "")*) " [,)]    # or a quoted string | ||||||
| | \(? ([^",\)]+) [,\)]              # or an unquoted string | | \(? ([^",)]+) [,)]                # or an unquoted string | ||||||
|     """, regex.VERBOSE) |     """, regex.VERBOSE) | ||||||
| 
 | 
 | ||||||
|     _re_undouble = regex.compile(r'(["\\])\1') |     _re_undouble = regex.compile(r'(["\\])\1') | ||||||
|  | @ -861,7 +873,7 @@ class CompositeCaster(object): | ||||||
|         rv = [] |         rv = [] | ||||||
|         for m in self._re_tokenize.finditer(s): |         for m in self._re_tokenize.finditer(s): | ||||||
|             if m is None: |             if m is None: | ||||||
|                 raise psycopg2.InterfaceError("can't parse type: %r", s) |                 raise psycopg2.InterfaceError("can't parse type: %r" % s) | ||||||
|             if m.group(1): |             if m.group(1): | ||||||
|                 rv.append(None) |                 rv.append(None) | ||||||
|             elif m.group(2): |             elif m.group(2): | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								lib/tz.py
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								lib/tz.py
									
									
									
									
									
								
							|  | @ -38,20 +38,40 @@ class FixedOffsetTimezone(datetime.tzinfo): | ||||||
|     with a small change to the `!__init__()` method to allow for pickling |     with a small change to the `!__init__()` method to allow for pickling | ||||||
|     and a default name in the form ``sHH:MM`` (``s`` is the sign.). |     and a default name in the form ``sHH:MM`` (``s`` is the sign.). | ||||||
| 
 | 
 | ||||||
|  |     The implementation also caches instances. During creation, if a | ||||||
|  |     FixedOffsetTimezone instance has previously been created with the same | ||||||
|  |     offset and name that instance will be returned. This saves memory and | ||||||
|  |     improves comparability. | ||||||
|  | 
 | ||||||
|     .. __: http://docs.python.org/library/datetime.html#datetime-tzinfo |     .. __: http://docs.python.org/library/datetime.html#datetime-tzinfo | ||||||
|     """ |     """ | ||||||
|     _name = None |     _name = None | ||||||
|     _offset = ZERO |     _offset = ZERO | ||||||
| 
 | 
 | ||||||
|  |     _cache = {} | ||||||
|  | 
 | ||||||
|     def __init__(self, offset=None, name=None): |     def __init__(self, offset=None, name=None): | ||||||
|         if offset is not None: |         if offset is not None: | ||||||
|             self._offset = datetime.timedelta(minutes = offset) |             self._offset = datetime.timedelta(minutes = offset) | ||||||
|         if name is not None: |         if name is not None: | ||||||
|             self._name = name |             self._name = name | ||||||
| 
 | 
 | ||||||
|  |     def __new__(cls, offset=None, name=None): | ||||||
|  |         """Return a suitable instance created earlier if it exists | ||||||
|  |         """ | ||||||
|  |         key = (offset, name) | ||||||
|  |         try: | ||||||
|  |             return cls._cache[key] | ||||||
|  |         except KeyError: | ||||||
|  |             tz = datetime.tzinfo.__new__(cls, offset, name) | ||||||
|  |             tz.__init__(offset, name) | ||||||
|  |             cls._cache[key] = tz | ||||||
|  |             return tz | ||||||
|  | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|  |         offset_mins = self._offset.seconds // 60 + self._offset.days * 24 * 60 | ||||||
|         return "psycopg2.tz.FixedOffsetTimezone(offset=%r, name=%r)" \ |         return "psycopg2.tz.FixedOffsetTimezone(offset=%r, name=%r)" \ | ||||||
|             % (self._offset.seconds // 60, self._name) |             % (offset_mins, self._name) | ||||||
| 
 | 
 | ||||||
|     def utcoffset(self, dt): |     def utcoffset(self, dt): | ||||||
|         return self._offset |         return self._offset | ||||||
|  |  | ||||||
|  | @ -65,6 +65,13 @@ binary_quote(binaryObject *self) | ||||||
|     int got_view = 0; |     int got_view = 0; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  |     /* Allow Binary(None) to work */ | ||||||
|  |     if (self->wrapped == Py_None) { | ||||||
|  |         Py_INCREF(psyco_null); | ||||||
|  |         rv = psyco_null; | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /* if we got a plain string or a buffer we escape it and save the buffer */ |     /* if we got a plain string or a buffer we escape it and save the buffer */ | ||||||
| 
 | 
 | ||||||
| #if HAS_MEMORYVIEW | #if HAS_MEMORYVIEW | ||||||
|  | @ -93,7 +100,7 @@ binary_quote(binaryObject *self) | ||||||
| 
 | 
 | ||||||
|     /* escape and build quoted buffer */ |     /* escape and build quoted buffer */ | ||||||
| 
 | 
 | ||||||
|     to = (char *)binary_escape((unsigned char*)buffer, (size_t) buffer_len, |     to = (char *)binary_escape((unsigned char*)buffer, (size_t)buffer_len, | ||||||
|         &len, self->conn ? ((connectionObject*)self->conn)->pgconn : NULL); |         &len, self->conn ? ((connectionObject*)self->conn)->pgconn : NULL); | ||||||
|     if (to == NULL) { |     if (to == NULL) { | ||||||
|         PyErr_NoMemory(); |         PyErr_NoMemory(); | ||||||
|  | @ -113,12 +120,6 @@ exit: | ||||||
|     if (got_view) { PyBuffer_Release(&view); } |     if (got_view) { PyBuffer_Release(&view); } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     /* Allow Binary(None) to work */ |  | ||||||
|     if (self->wrapped == Py_None) { |  | ||||||
|         Py_INCREF(psyco_null); |  | ||||||
|         rv = psyco_null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* if the wrapped object is not bytes or a buffer, this is an error */ |     /* if the wrapped object is not bytes or a buffer, this is an error */ | ||||||
|     if (!rv && !PyErr_Occurred()) { |     if (!rv && !PyErr_Occurred()) { | ||||||
|         PyErr_Format(PyExc_TypeError, "can't escape %s to binary", |         PyErr_Format(PyExc_TypeError, "can't escape %s to binary", | ||||||
|  | @ -149,16 +150,14 @@ binary_str(binaryObject *self) | ||||||
| static PyObject * | static PyObject * | ||||||
| binary_prepare(binaryObject *self, PyObject *args) | binary_prepare(binaryObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     connectionObject *conn; |     PyObject *conn; | ||||||
| 
 | 
 | ||||||
|     if (!PyArg_ParseTuple(args, "O", &conn)) |     if (!PyArg_ParseTuple(args, "O!", &connectionType, &conn)) | ||||||
|         return NULL; |         return NULL; | ||||||
| 
 | 
 | ||||||
|     Py_XDECREF(self->conn); |     Py_XDECREF(self->conn); | ||||||
|     if (conn) { |     self->conn = conn; | ||||||
|         self->conn = (PyObject*)conn; |  | ||||||
|     Py_INCREF(self->conn); |     Py_INCREF(self->conn); | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     Py_INCREF(Py_None); |     Py_INCREF(Py_None); | ||||||
|     return Py_None; |     return Py_None; | ||||||
|  |  | ||||||
|  | @ -427,6 +427,10 @@ psyco_DateFromTicks(PyObject *self, PyObject *args) | ||||||
|             Py_DECREF(args); |             Py_DECREF(args); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 	else { | ||||||
|  | 		PyErr_SetString(InterfaceError, "failed localtime call"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -451,6 +455,10 @@ psyco_TimeFromTicks(PyObject *self, PyObject *args) | ||||||
|             Py_DECREF(args); |             Py_DECREF(args); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 	else { | ||||||
|  | 		PyErr_SetString(InterfaceError, "failed localtime call"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -473,6 +481,9 @@ psyco_TimestampFromTicks(PyObject *self, PyObject *args) | ||||||
|             tm.tm_hour, tm.tm_min, (double)tm.tm_sec + ticks, |             tm.tm_hour, tm.tm_min, (double)tm.tm_sec + ticks, | ||||||
|             pyPsycopgTzLOCAL); |             pyPsycopgTzLOCAL); | ||||||
|     } |     } | ||||||
|  | 	else { | ||||||
|  | 		PyErr_SetString(InterfaceError, "failed localtime call"); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -98,9 +98,9 @@ list_getquoted(listObject *self, PyObject *args) | ||||||
| static PyObject * | static PyObject * | ||||||
| list_prepare(listObject *self, PyObject *args) | list_prepare(listObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     connectionObject *conn; |     PyObject *conn; | ||||||
| 
 | 
 | ||||||
|     if (!PyArg_ParseTuple(args, "O", &conn)) |     if (!PyArg_ParseTuple(args, "O!", &connectionType, &conn)) | ||||||
|         return NULL; |         return NULL; | ||||||
| 
 | 
 | ||||||
|     /* note that we don't copy the encoding from the connection, but take a
 |     /* note that we don't copy the encoding from the connection, but take a
 | ||||||
|  | @ -109,7 +109,7 @@ list_prepare(listObject *self, PyObject *args) | ||||||
|        work even without a connection to the backend. */ |        work even without a connection to the backend. */ | ||||||
|     Py_CLEAR(self->connection); |     Py_CLEAR(self->connection); | ||||||
|     Py_INCREF(conn); |     Py_INCREF(conn); | ||||||
|     self->connection = (PyObject*)conn; |     self->connection = conn; | ||||||
| 
 | 
 | ||||||
|     Py_INCREF(Py_None); |     Py_INCREF(Py_None); | ||||||
|     return Py_None; |     return Py_None; | ||||||
|  |  | ||||||
|  | @ -35,7 +35,7 @@ | ||||||
| 
 | 
 | ||||||
| /* qstring_quote - do the quote process on plain and unicode strings */ | /* qstring_quote - do the quote process on plain and unicode strings */ | ||||||
| 
 | 
 | ||||||
| static PyObject * | BORROWED static PyObject * | ||||||
| qstring_quote(qstringObject *self) | qstring_quote(qstringObject *self) | ||||||
| { | { | ||||||
|     PyObject *str; |     PyObject *str; | ||||||
|  | @ -124,24 +124,22 @@ qstring_str(qstringObject *self) | ||||||
| static PyObject * | static PyObject * | ||||||
| qstring_prepare(qstringObject *self, PyObject *args) | qstring_prepare(qstringObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     connectionObject *conn; |     PyObject *conn; | ||||||
| 
 | 
 | ||||||
|     if (!PyArg_ParseTuple(args, "O", &conn)) |     if (!PyArg_ParseTuple(args, "O!", &connectionType, &conn)) | ||||||
|         return NULL; |         return NULL; | ||||||
| 
 | 
 | ||||||
|     /* we bother copying the encoding only if the wrapped string is unicode,
 |     /* we bother copying the encoding only if the wrapped string is unicode,
 | ||||||
|        we don't need the encoding if that's not the case */ |        we don't need the encoding if that's not the case */ | ||||||
|     if (PyUnicode_Check(self->wrapped)) { |     if (PyUnicode_Check(self->wrapped)) { | ||||||
|         if (self->encoding) free(self->encoding); |         if (self->encoding) free(self->encoding); | ||||||
|         self->encoding = strdup(conn->codec); |         self->encoding = strdup(((connectionObject *)conn)->codec); | ||||||
|         Dprintf("qstring_prepare: set encoding to %s", conn->codec); |         Dprintf("qstring_prepare: set encoding to %s", self->encoding); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Py_CLEAR(self->conn); |     Py_CLEAR(self->conn); | ||||||
|     if (conn) { |  | ||||||
|     Py_INCREF(conn); |     Py_INCREF(conn); | ||||||
|         self->conn = (PyObject*)conn; |     self->conn = conn; | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     Py_INCREF(Py_None); |     Py_INCREF(Py_None); | ||||||
|     return Py_None; |     return Py_None; | ||||||
|  |  | ||||||
|  | @ -86,7 +86,7 @@ | ||||||
| 
 | 
 | ||||||
| /* Helpers for formatstring */ | /* Helpers for formatstring */ | ||||||
| 
 | 
 | ||||||
| Py_LOCAL_INLINE(PyObject *) | BORROWED Py_LOCAL_INLINE(PyObject *) | ||||||
| getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) | getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) | ||||||
| { | { | ||||||
|     Py_ssize_t argidx = *p_argidx; |     Py_ssize_t argidx = *p_argidx; | ||||||
|  |  | ||||||
|  | @ -160,4 +160,33 @@ static double round(double num) | ||||||
| #define isinf(x) (!finite((x)) && (x)==(x)) | #define isinf(x) (!finite((x)) && (x)==(x)) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | /* decorators for the gcc cpychecker plugin */ | ||||||
|  | #if defined(WITH_CPYCHECKER_RETURNS_BORROWED_REF_ATTRIBUTE) | ||||||
|  | #define BORROWED \ | ||||||
|  |     __attribute__((cpychecker_returns_borrowed_ref)) | ||||||
|  | #else | ||||||
|  | #define BORROWED | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if defined(WITH_CPYCHECKER_STEALS_REFERENCE_TO_ARG_ATTRIBUTE) | ||||||
|  | #define STEALS(n) \ | ||||||
|  |     __attribute__((cpychecker_steals_reference_to_arg(n))) | ||||||
|  | #else | ||||||
|  | #define STEALS(n) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE) | ||||||
|  | #define RAISES_NEG \ | ||||||
|  |     __attribute__((cpychecker_negative_result_sets_exception)) | ||||||
|  | #else | ||||||
|  | #define RAISES_NEG | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if defined(WITH_CPYCHECKER_SETS_EXCEPTION_ATTRIBUTE) | ||||||
|  | #define RAISES \ | ||||||
|  |     __attribute__((cpychecker_sets_exception)) | ||||||
|  | #else | ||||||
|  | #define RAISES | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #endif /* !defined(PSYCOPG_CONFIG_H) */ | #endif /* !defined(PSYCOPG_CONFIG_H) */ | ||||||
|  |  | ||||||
|  | @ -131,27 +131,27 @@ typedef struct { | ||||||
| /* C-callable functions in connection_int.c and connection_ext.c */ | /* C-callable functions in connection_int.c and connection_ext.c */ | ||||||
| HIDDEN PyObject *conn_text_from_chars(connectionObject *pgconn, const char *str); | HIDDEN PyObject *conn_text_from_chars(connectionObject *pgconn, const char *str); | ||||||
| HIDDEN int  conn_get_standard_conforming_strings(PGconn *pgconn); | HIDDEN int  conn_get_standard_conforming_strings(PGconn *pgconn); | ||||||
| HIDDEN int  conn_get_isolation_level(connectionObject *self); | RAISES_NEG HIDDEN int  conn_get_isolation_level(connectionObject *self); | ||||||
| HIDDEN int  conn_get_protocol_version(PGconn *pgconn); | HIDDEN int  conn_get_protocol_version(PGconn *pgconn); | ||||||
| HIDDEN int  conn_get_server_version(PGconn *pgconn); | HIDDEN int  conn_get_server_version(PGconn *pgconn); | ||||||
| HIDDEN PGcancel *conn_get_cancel(PGconn *pgconn); | HIDDEN PGcancel *conn_get_cancel(PGconn *pgconn); | ||||||
| HIDDEN void conn_notice_process(connectionObject *self); | HIDDEN void conn_notice_process(connectionObject *self); | ||||||
| HIDDEN void conn_notice_clean(connectionObject *self); | HIDDEN void conn_notice_clean(connectionObject *self); | ||||||
| HIDDEN void conn_notifies_process(connectionObject *self); | HIDDEN void conn_notifies_process(connectionObject *self); | ||||||
| HIDDEN int  conn_setup(connectionObject *self, PGconn *pgconn); | RAISES_NEG HIDDEN int  conn_setup(connectionObject *self, PGconn *pgconn); | ||||||
| HIDDEN int  conn_connect(connectionObject *self, long int async); | HIDDEN int  conn_connect(connectionObject *self, long int async); | ||||||
| HIDDEN void conn_close(connectionObject *self); | HIDDEN void conn_close(connectionObject *self); | ||||||
| HIDDEN int  conn_commit(connectionObject *self); | RAISES_NEG HIDDEN int  conn_commit(connectionObject *self); | ||||||
| HIDDEN int  conn_rollback(connectionObject *self); | RAISES_NEG HIDDEN int  conn_rollback(connectionObject *self); | ||||||
| HIDDEN int  conn_set_session(connectionObject *self, const char *isolevel, | RAISES_NEG HIDDEN int  conn_set_session(connectionObject *self, const char *isolevel, | ||||||
|                                  const char *readonly, const char *deferrable, |                                  const char *readonly, const char *deferrable, | ||||||
|                                  int autocommit); |                                  int autocommit); | ||||||
| HIDDEN int  conn_set_autocommit(connectionObject *self, int value); | HIDDEN int  conn_set_autocommit(connectionObject *self, int value); | ||||||
| HIDDEN int  conn_switch_isolation_level(connectionObject *self, int level); | RAISES_NEG HIDDEN int  conn_switch_isolation_level(connectionObject *self, int level); | ||||||
| HIDDEN int  conn_set_client_encoding(connectionObject *self, const char *enc); | RAISES_NEG HIDDEN int  conn_set_client_encoding(connectionObject *self, const char *enc); | ||||||
| HIDDEN int  conn_poll(connectionObject *self); | HIDDEN int  conn_poll(connectionObject *self); | ||||||
| HIDDEN int  conn_tpc_begin(connectionObject *self, XidObject *xid); | RAISES_NEG HIDDEN int  conn_tpc_begin(connectionObject *self, XidObject *xid); | ||||||
| HIDDEN int  conn_tpc_command(connectionObject *self, | RAISES_NEG HIDDEN int  conn_tpc_command(connectionObject *self, | ||||||
|                              const char *cmd, XidObject *xid); |                              const char *cmd, XidObject *xid); | ||||||
| HIDDEN PyObject *conn_tpc_recover(connectionObject *self); | HIDDEN PyObject *conn_tpc_recover(connectionObject *self); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -120,8 +120,16 @@ conn_notice_process(connectionObject *self) | ||||||
| 
 | 
 | ||||||
|         /* Respect the order in which notices were produced,
 |         /* Respect the order in which notices were produced,
 | ||||||
|            because in notice_list they are reversed (see ticket #9) */ |            because in notice_list they are reversed (see ticket #9) */ | ||||||
|  |         if (msg) { | ||||||
|             PyList_Insert(self->notice_list, nnotices, msg); |             PyList_Insert(self->notice_list, nnotices, msg); | ||||||
|             Py_DECREF(msg); |             Py_DECREF(msg); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             /* We don't really have a way to report errors, so gulp it.
 | ||||||
|  |              * The function should only fail for out of memory, so we are | ||||||
|  |              * likely going to die anyway. */ | ||||||
|  |             PyErr_Clear(); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         notice = notice->next; |         notice = notice->next; | ||||||
|     } |     } | ||||||
|  | @ -242,19 +250,20 @@ conn_get_standard_conforming_strings(PGconn *pgconn) | ||||||
| 
 | 
 | ||||||
| /* Remove irrelevant chars from encoding name and turn it uppercase.
 | /* Remove irrelevant chars from encoding name and turn it uppercase.
 | ||||||
|  * |  * | ||||||
|  * Return a buffer allocated on Python heap, |  * Return a buffer allocated on Python heap into 'clean' and return 0 on | ||||||
|  * NULL and set an exception on error. |  * success, otherwise return -1 and set an exception. | ||||||
|  */ |  */ | ||||||
| static char * | RAISES_NEG static int | ||||||
| clean_encoding_name(const char *enc) | clear_encoding_name(const char *enc, char **clean) | ||||||
| { | { | ||||||
|     const char *i = enc; |     const char *i = enc; | ||||||
|     char *rv, *j; |     char *j, *buf; | ||||||
|  |     int rv = -1; | ||||||
| 
 | 
 | ||||||
|     /* convert to upper case and remove '-' and '_' from string */ |     /* convert to upper case and remove '-' and '_' from string */ | ||||||
|     if (!(j = rv = PyMem_Malloc(strlen(enc) + 1))) { |     if (!(j = buf = PyMem_Malloc(strlen(enc) + 1))) { | ||||||
|         PyErr_NoMemory(); |         PyErr_NoMemory(); | ||||||
|         return NULL; |         goto exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     while (*i) { |     while (*i) { | ||||||
|  | @ -267,25 +276,28 @@ clean_encoding_name(const char *enc) | ||||||
|     } |     } | ||||||
|     *j = '\0'; |     *j = '\0'; | ||||||
| 
 | 
 | ||||||
|     Dprintf("clean_encoding_name: %s -> %s", enc, rv); |     Dprintf("clear_encoding_name: %s -> %s", enc, buf); | ||||||
|  |     *clean = buf; | ||||||
|  |     rv = 0; | ||||||
| 
 | 
 | ||||||
|  | exit: | ||||||
|     return rv; |     return rv; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Convert a PostgreSQL encoding to a Python codec.
 | /* Convert a PostgreSQL encoding to a Python codec.
 | ||||||
|  * |  * | ||||||
|  * Return a new copy of the codec name allocated on the Python heap, |  * Set 'codec' to a new copy of the codec name allocated on the Python heap. | ||||||
|  * NULL with exception in case of error. |  * Return 0 in case of success, else -1 and set an exception. | ||||||
|  * |  * | ||||||
|  * 'enc' should be already normalized (uppercase, no - or _). |  * 'enc' should be already normalized (uppercase, no - or _). | ||||||
|  */ |  */ | ||||||
| static char * | RAISES_NEG static int | ||||||
| conn_encoding_to_codec(const char *enc) | conn_encoding_to_codec(const char *enc, char **codec) | ||||||
| { | { | ||||||
|     char *tmp; |     char *tmp; | ||||||
|     Py_ssize_t size; |     Py_ssize_t size; | ||||||
|     PyObject *pyenc = NULL; |     PyObject *pyenc = NULL; | ||||||
|     char *rv = NULL; |     int rv = -1; | ||||||
| 
 | 
 | ||||||
|     /* Find the Py codec name from the PG encoding */ |     /* Find the Py codec name from the PG encoding */ | ||||||
|     if (!(pyenc = PyDict_GetItemString(psycoEncodings, enc))) { |     if (!(pyenc = PyDict_GetItemString(psycoEncodings, enc))) { | ||||||
|  | @ -305,7 +317,7 @@ conn_encoding_to_codec(const char *enc) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* have our own copy of the python codec name */ |     /* have our own copy of the python codec name */ | ||||||
|     rv = psycopg_strdup(tmp, size); |     rv = psycopg_strdup(codec, tmp, size); | ||||||
| 
 | 
 | ||||||
| exit: | exit: | ||||||
|     Py_XDECREF(pyenc); |     Py_XDECREF(pyenc); | ||||||
|  | @ -320,7 +332,7 @@ exit: | ||||||
|  * |  * | ||||||
|  * Return 0 on success, else nonzero. |  * Return 0 on success, else nonzero. | ||||||
|  */ |  */ | ||||||
| static int | RAISES_NEG static int | ||||||
| conn_read_encoding(connectionObject *self, PGconn *pgconn) | conn_read_encoding(connectionObject *self, PGconn *pgconn) | ||||||
| { | { | ||||||
|     char *enc = NULL, *codec = NULL; |     char *enc = NULL, *codec = NULL; | ||||||
|  | @ -335,12 +347,12 @@ conn_read_encoding(connectionObject *self, PGconn *pgconn) | ||||||
|         goto exit; |         goto exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!(enc = clean_encoding_name(tmp))) { |     if (0 > clear_encoding_name(tmp, &enc)) { | ||||||
|         goto exit; |         goto exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Look for this encoding in Python codecs. */ |     /* Look for this encoding in Python codecs. */ | ||||||
|     if (!(codec = conn_encoding_to_codec(enc))) { |     if (0 > conn_encoding_to_codec(enc, &codec)) { | ||||||
|         goto exit; |         goto exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -362,7 +374,7 @@ exit: | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| conn_get_isolation_level(connectionObject *self) | conn_get_isolation_level(connectionObject *self) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  | @ -456,7 +468,7 @@ conn_is_datestyle_ok(PGconn *pgconn) | ||||||
| 
 | 
 | ||||||
| /* conn_setup - setup and read basic information about the connection */ | /* conn_setup - setup and read basic information about the connection */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| conn_setup(connectionObject *self, PGconn *pgconn) | conn_setup(connectionObject *self, PGconn *pgconn) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  | @ -470,7 +482,7 @@ conn_setup(connectionObject *self, PGconn *pgconn) | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (conn_read_encoding(self, pgconn)) { |     if (0 > conn_read_encoding(self, pgconn)) { | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -484,7 +496,7 @@ conn_setup(connectionObject *self, PGconn *pgconn) | ||||||
|     pthread_mutex_lock(&self->lock); |     pthread_mutex_lock(&self->lock); | ||||||
|     Py_BLOCK_THREADS; |     Py_BLOCK_THREADS; | ||||||
| 
 | 
 | ||||||
|     if (psyco_green() && (pq_set_non_blocking(self, 1, 1) != 0)) { |     if (psyco_green() && (0 > pq_set_non_blocking(self, 1))) { | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -762,7 +774,7 @@ _conn_poll_setup_async(connectionObject *self) | ||||||
|     switch (self->status) { |     switch (self->status) { | ||||||
|     case CONN_STATUS_CONNECTING: |     case CONN_STATUS_CONNECTING: | ||||||
|         /* Set the connection to nonblocking now. */ |         /* Set the connection to nonblocking now. */ | ||||||
|         if (pq_set_non_blocking(self, 1, 1) != 0) { |         if (pq_set_non_blocking(self, 1) != 0) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -773,7 +785,7 @@ _conn_poll_setup_async(connectionObject *self) | ||||||
|             PyErr_SetString(InterfaceError, "only protocol 3 supported"); |             PyErr_SetString(InterfaceError, "only protocol 3 supported"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if (conn_read_encoding(self, self->pgconn)) { |         if (0 > conn_read_encoding(self, self->pgconn)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         self->cancel = conn_get_cancel(self->pgconn); |         self->cancel = conn_get_cancel(self->pgconn); | ||||||
|  | @ -906,6 +918,10 @@ conn_poll(connectionObject *self) | ||||||
| void | void | ||||||
| conn_close(connectionObject *self) | conn_close(connectionObject *self) | ||||||
| { | { | ||||||
|  |     if (self->closed) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /* sets this connection as closed even for other threads; also note that
 |     /* sets this connection as closed even for other threads; also note that
 | ||||||
|        we need to check the value of pgconn, because we get called even when |        we need to check the value of pgconn, because we get called even when | ||||||
|        the connection fails! */ |        the connection fails! */ | ||||||
|  | @ -922,14 +938,13 @@ conn_close(connectionObject *self) | ||||||
|      * closed only in status CONN_STATUS_READY. |      * closed only in status CONN_STATUS_READY. | ||||||
|      */ |      */ | ||||||
| 
 | 
 | ||||||
|     if (self->closed == 0) |  | ||||||
|     self->closed = 1; |     self->closed = 1; | ||||||
| 
 | 
 | ||||||
|     if (self->pgconn) { |     if (self->pgconn) { | ||||||
|         PQfinish(self->pgconn); |         PQfinish(self->pgconn); | ||||||
|         PQfreeCancel(self->cancel); |  | ||||||
|         Dprintf("conn_close: PQfinish called"); |  | ||||||
|         self->pgconn = NULL; |         self->pgconn = NULL; | ||||||
|  |         Dprintf("conn_close: PQfinish called"); | ||||||
|  |         PQfreeCancel(self->cancel); | ||||||
|         self->cancel = NULL; |         self->cancel = NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -939,7 +954,7 @@ conn_close(connectionObject *self) | ||||||
| 
 | 
 | ||||||
| /* conn_commit - commit on a connection */ | /* conn_commit - commit on a connection */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| conn_commit(connectionObject *self) | conn_commit(connectionObject *self) | ||||||
| { | { | ||||||
|     int res; |     int res; | ||||||
|  | @ -950,7 +965,7 @@ conn_commit(connectionObject *self) | ||||||
| 
 | 
 | ||||||
| /* conn_rollback - rollback a connection */ | /* conn_rollback - rollback a connection */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| conn_rollback(connectionObject *self) | conn_rollback(connectionObject *self) | ||||||
| { | { | ||||||
|     int res; |     int res; | ||||||
|  | @ -959,7 +974,7 @@ conn_rollback(connectionObject *self) | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| conn_set_session(connectionObject *self, | conn_set_session(connectionObject *self, | ||||||
|         const char *isolevel, const char *readonly, const char *deferrable, |         const char *isolevel, const char *readonly, const char *deferrable, | ||||||
|         int autocommit) |         int autocommit) | ||||||
|  | @ -1032,7 +1047,7 @@ conn_set_autocommit(connectionObject *self, int value) | ||||||
| 
 | 
 | ||||||
| /* conn_switch_isolation_level - switch isolation level on the connection */ | /* conn_switch_isolation_level - switch isolation level on the connection */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| conn_switch_isolation_level(connectionObject *self, int level) | conn_switch_isolation_level(connectionObject *self, int level) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  | @ -1114,12 +1129,12 @@ endlock: | ||||||
| 
 | 
 | ||||||
| /* conn_set_client_encoding - switch client encoding on connection */ | /* conn_set_client_encoding - switch client encoding on connection */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| conn_set_client_encoding(connectionObject *self, const char *enc) | conn_set_client_encoding(connectionObject *self, const char *enc) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|     char *error = NULL; |     char *error = NULL; | ||||||
|     int res = 1; |     int res = -1; | ||||||
|     char *codec = NULL; |     char *codec = NULL; | ||||||
|     char *clean_enc = NULL; |     char *clean_enc = NULL; | ||||||
| 
 | 
 | ||||||
|  | @ -1128,8 +1143,8 @@ conn_set_client_encoding(connectionObject *self, const char *enc) | ||||||
|     if (strcmp(self->encoding, enc) == 0) return 0; |     if (strcmp(self->encoding, enc) == 0) return 0; | ||||||
| 
 | 
 | ||||||
|     /* We must know what python codec this encoding is. */ |     /* We must know what python codec this encoding is. */ | ||||||
|     if (!(clean_enc = clean_encoding_name(enc))) { goto exit; } |     if (0 > clear_encoding_name(enc, &clean_enc)) { goto exit; } | ||||||
|     if (!(codec = conn_encoding_to_codec(clean_enc))) { goto exit; } |     if (0 > conn_encoding_to_codec(clean_enc, &codec)) { goto exit; } | ||||||
| 
 | 
 | ||||||
|     Py_BEGIN_ALLOW_THREADS; |     Py_BEGIN_ALLOW_THREADS; | ||||||
|     pthread_mutex_lock(&self->lock); |     pthread_mutex_lock(&self->lock); | ||||||
|  | @ -1187,7 +1202,7 @@ exit: | ||||||
|  * in regular transactions, as PostgreSQL won't even know we are in a TPC |  * in regular transactions, as PostgreSQL won't even know we are in a TPC | ||||||
|  * until PREPARE. */ |  * until PREPARE. */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| conn_tpc_begin(connectionObject *self, XidObject *xid) | conn_tpc_begin(connectionObject *self, XidObject *xid) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  | @ -1221,7 +1236,7 @@ conn_tpc_begin(connectionObject *self, XidObject *xid) | ||||||
|  * The function doesn't change the connection state as it can be used |  * The function doesn't change the connection state as it can be used | ||||||
|  * for many commands and for recovered transactions. */ |  * for many commands and for recovered transactions. */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| conn_tpc_command(connectionObject *self, const char *cmd, XidObject *xid) | conn_tpc_command(connectionObject *self, const char *cmd, XidObject *xid) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  |  | ||||||
|  | @ -122,8 +122,6 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *keywds) | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_conn_close(connectionObject *self, PyObject *args) | psyco_conn_close(connectionObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     EXC_IF_CONN_CLOSED(self); |  | ||||||
| 
 |  | ||||||
|     Dprintf("psyco_conn_close: closing connection at %p", self); |     Dprintf("psyco_conn_close: closing connection at %p", self); | ||||||
|     conn_close(self); |     conn_close(self); | ||||||
|     Dprintf("psyco_conn_close: connection at %p closed", self); |     Dprintf("psyco_conn_close: connection at %p closed", self); | ||||||
|  | @ -528,7 +526,7 @@ psyco_conn_set_session(connectionObject *self, PyObject *args, PyObject *kwargs) | ||||||
|         if (-1 == c_autocommit) { return NULL; } |         if (-1 == c_autocommit) { return NULL; } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (0 != conn_set_session(self, |     if (0 > conn_set_session(self, | ||||||
|             c_isolevel, c_readonly, c_deferrable, c_autocommit)) { |             c_isolevel, c_readonly, c_deferrable, c_autocommit)) { | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|  | @ -550,7 +548,7 @@ psyco_conn_autocommit_get(connectionObject *self) | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | BORROWED static PyObject * | ||||||
| _psyco_conn_autocommit_set_checks(connectionObject *self) | _psyco_conn_autocommit_set_checks(connectionObject *self) | ||||||
| { | { | ||||||
|     /* wrapper to use the EXC_IF macros.
 |     /* wrapper to use the EXC_IF macros.
 | ||||||
|  | @ -637,7 +635,7 @@ psyco_conn_set_client_encoding(connectionObject *self, PyObject *args) | ||||||
| 
 | 
 | ||||||
|     if (!PyArg_ParseTuple(args, "s", &enc)) return NULL; |     if (!PyArg_ParseTuple(args, "s", &enc)) return NULL; | ||||||
| 
 | 
 | ||||||
|     if (conn_set_client_encoding(self, enc) == 0) { |     if (conn_set_client_encoding(self, enc) >= 0) { | ||||||
|         Py_INCREF(Py_None); |         Py_INCREF(Py_None); | ||||||
|         rv = Py_None; |         rv = Py_None; | ||||||
|     } |     } | ||||||
|  | @ -701,8 +699,8 @@ psyco_conn_get_parameter_status(connectionObject *self, PyObject *args) | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds) | psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds) | ||||||
| { | { | ||||||
|     Oid oid=InvalidOid, new_oid=InvalidOid; |     int oid = (int)InvalidOid, new_oid = (int)InvalidOid; | ||||||
|     char *new_file = NULL; |     const char *new_file = NULL; | ||||||
|     const char *smode = ""; |     const char *smode = ""; | ||||||
|     PyObject *factory = (PyObject *)&lobjectType; |     PyObject *factory = (PyObject *)&lobjectType; | ||||||
|     PyObject *obj; |     PyObject *obj; | ||||||
|  | @ -754,7 +752,7 @@ psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds) | ||||||
| "get_backend_pid() -- Get backend process id." | "get_backend_pid() -- Get backend process id." | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_conn_get_backend_pid(connectionObject *self) | psyco_conn_get_backend_pid(connectionObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     EXC_IF_CONN_CLOSED(self); |     EXC_IF_CONN_CLOSED(self); | ||||||
| 
 | 
 | ||||||
|  | @ -767,7 +765,7 @@ psyco_conn_get_backend_pid(connectionObject *self) | ||||||
| "reset() -- Reset current connection to defaults." | "reset() -- Reset current connection to defaults." | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_conn_reset(connectionObject *self) | psyco_conn_reset(connectionObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     int res; |     int res; | ||||||
| 
 | 
 | ||||||
|  | @ -795,7 +793,7 @@ psyco_conn_get_exception(PyObject *self, void *closure) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_conn_poll(connectionObject *self) | psyco_conn_poll(connectionObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     int res; |     int res; | ||||||
| 
 | 
 | ||||||
|  | @ -817,7 +815,7 @@ psyco_conn_poll(connectionObject *self) | ||||||
| "fileno() -> int -- Return file descriptor associated to database connection." | "fileno() -> int -- Return file descriptor associated to database connection." | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_conn_fileno(connectionObject *self) | psyco_conn_fileno(connectionObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     long int socket; |     long int socket; | ||||||
| 
 | 
 | ||||||
|  | @ -836,7 +834,7 @@ psyco_conn_fileno(connectionObject *self) | ||||||
|  "executing an asynchronous operation." |  "executing an asynchronous operation." | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_conn_isexecuting(connectionObject *self) | psyco_conn_isexecuting(connectionObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     /* synchronous connections will always return False */ |     /* synchronous connections will always return False */ | ||||||
|     if (self->async == 0) { |     if (self->async == 0) { | ||||||
|  | @ -868,7 +866,7 @@ psyco_conn_isexecuting(connectionObject *self) | ||||||
| "cancel() -- cancel the current operation" | "cancel() -- cancel the current operation" | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_conn_cancel(connectionObject *self) | psyco_conn_cancel(connectionObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     char errbuf[256]; |     char errbuf[256]; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -85,7 +85,7 @@ struct cursorObject { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* C-callable functions in cursor_int.c and cursor_ext.c */ | /* C-callable functions in cursor_int.c and cursor_ext.c */ | ||||||
| HIDDEN PyObject *curs_get_cast(cursorObject *self, PyObject *oid); | BORROWED HIDDEN PyObject *curs_get_cast(cursorObject *self, PyObject *oid); | ||||||
| HIDDEN void curs_reset(cursorObject *self); | HIDDEN void curs_reset(cursorObject *self); | ||||||
| 
 | 
 | ||||||
| /* exception-raising macros */ | /* exception-raising macros */ | ||||||
|  |  | ||||||
|  | @ -38,7 +38,7 @@ | ||||||
|  * Return a borrowed reference. |  * Return a borrowed reference. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| PyObject * | BORROWED PyObject * | ||||||
| curs_get_cast(cursorObject *self, PyObject *oid) | curs_get_cast(cursorObject *self, PyObject *oid) | ||||||
| { | { | ||||||
|     PyObject *cast; |     PyObject *cast; | ||||||
|  |  | ||||||
|  | @ -52,9 +52,12 @@ extern PyObject *pyPsycopgTzFixedOffsetTimezone; | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_curs_close(cursorObject *self, PyObject *args) | psyco_curs_close(cursorObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     EXC_IF_CURS_CLOSED(self); |  | ||||||
|     EXC_IF_ASYNC_IN_PROGRESS(self, close); |     EXC_IF_ASYNC_IN_PROGRESS(self, close); | ||||||
| 
 | 
 | ||||||
|  |     if (self->closed) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (self->name != NULL) { |     if (self->name != NULL) { | ||||||
|         char buffer[128]; |         char buffer[128]; | ||||||
| 
 | 
 | ||||||
|  | @ -66,6 +69,7 @@ psyco_curs_close(cursorObject *self, PyObject *args) | ||||||
|     self->closed = 1; |     self->closed = 1; | ||||||
|     Dprintf("psyco_curs_close: cursor at %p closed", self); |     Dprintf("psyco_curs_close: cursor at %p closed", self); | ||||||
| 
 | 
 | ||||||
|  | exit: | ||||||
|     Py_INCREF(Py_None); |     Py_INCREF(Py_None); | ||||||
|     return Py_None; |     return Py_None; | ||||||
| } | } | ||||||
|  | @ -75,7 +79,7 @@ psyco_curs_close(cursorObject *self, PyObject *args) | ||||||
| 
 | 
 | ||||||
| /* mogrify a query string and build argument array or dict */ | /* mogrify a query string and build argument array or dict */ | ||||||
| 
 | 
 | ||||||
| static int | RAISES_NEG static int | ||||||
| _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new) | _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new) | ||||||
| { | { | ||||||
|     PyObject *key, *value, *n; |     PyObject *key, *value, *n; | ||||||
|  | @ -217,7 +221,10 @@ _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (n == NULL) { |             if (n == NULL) { | ||||||
|                 n = PyTuple_New(PyObject_Length(var)); |                 if (!(n = PyTuple_New(PyObject_Length(var)))) { | ||||||
|  |                     Py_DECREF(value); | ||||||
|  |                     return -1; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /* let's have d point just after the '%' */ |             /* let's have d point just after the '%' */ | ||||||
|  | @ -356,11 +363,12 @@ _psyco_curs_merge_query_args(cursorObject *self, | ||||||
| #define psyco_curs_execute_doc \ | #define psyco_curs_execute_doc \ | ||||||
| "execute(query, vars=None) -- Execute query with bound vars." | "execute(query, vars=None) -- Execute query with bound vars." | ||||||
| 
 | 
 | ||||||
| static int | RAISES_NEG static int | ||||||
| _psyco_curs_execute(cursorObject *self, | _psyco_curs_execute(cursorObject *self, | ||||||
|                     PyObject *operation, PyObject *vars, long int async) |                     PyObject *operation, PyObject *vars, long int async) | ||||||
| { | { | ||||||
|     int res = 0; |     int res = -1; | ||||||
|  |     int tmp; | ||||||
|     PyObject *fquery, *cvt = NULL; |     PyObject *fquery, *cvt = NULL; | ||||||
| 
 | 
 | ||||||
|     operation = _psyco_curs_validate_sql_basic(self, operation); |     operation = _psyco_curs_validate_sql_basic(self, operation); | ||||||
|  | @ -368,7 +376,7 @@ _psyco_curs_execute(cursorObject *self, | ||||||
|     /* Any failure from here forward should 'goto fail' rather than 'return 0'
 |     /* Any failure from here forward should 'goto fail' rather than 'return 0'
 | ||||||
|        directly. */ |        directly. */ | ||||||
| 
 | 
 | ||||||
|     if (operation == NULL) { goto fail; } |     if (operation == NULL) { goto exit; } | ||||||
| 
 | 
 | ||||||
|     IFCLEARPGRES(self->pgres); |     IFCLEARPGRES(self->pgres); | ||||||
| 
 | 
 | ||||||
|  | @ -385,12 +393,12 @@ _psyco_curs_execute(cursorObject *self, | ||||||
| 
 | 
 | ||||||
|     if (vars && vars != Py_None) |     if (vars && vars != Py_None) | ||||||
|     { |     { | ||||||
|         if(_mogrify(vars, operation, self, &cvt) == -1) { goto fail; } |         if (0 > _mogrify(vars, operation, self, &cvt)) { goto exit; } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (vars && cvt) { |     if (vars && cvt) { | ||||||
|         if (!(fquery = _psyco_curs_merge_query_args(self, operation, cvt))) { |         if (!(fquery = _psyco_curs_merge_query_args(self, operation, cvt))) { | ||||||
|             goto fail; |             goto exit; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (self->name != NULL) { |         if (self->name != NULL) { | ||||||
|  | @ -424,22 +432,17 @@ _psyco_curs_execute(cursorObject *self, | ||||||
| 
 | 
 | ||||||
|     /* At this point, the SQL statement must be str, not unicode */ |     /* At this point, the SQL statement must be str, not unicode */ | ||||||
| 
 | 
 | ||||||
|     res = pq_execute(self, Bytes_AS_STRING(self->query), async); |     tmp = pq_execute(self, Bytes_AS_STRING(self->query), async); | ||||||
|     Dprintf("psyco_curs_execute: res = %d, pgres = %p", res, self->pgres); |     Dprintf("psyco_curs_execute: res = %d, pgres = %p", tmp, self->pgres); | ||||||
|     if (res == -1) { goto fail; } |     if (tmp < 0) { goto exit; } | ||||||
| 
 | 
 | ||||||
|     res = 1; /* Success */ |     res = 0; /* Success */ | ||||||
|     goto cleanup; |  | ||||||
| 
 | 
 | ||||||
|     fail: | exit: | ||||||
|         res = 0; |  | ||||||
|         /* Fall through to cleanup */ |  | ||||||
|     cleanup: |  | ||||||
|     /* Py_XDECREF(operation) is safe because the original reference passed
 |     /* Py_XDECREF(operation) is safe because the original reference passed
 | ||||||
|        by the caller was overwritten with either NULL or a new |        by the caller was overwritten with either NULL or a new | ||||||
|        reference */ |        reference */ | ||||||
|     Py_XDECREF(operation); |     Py_XDECREF(operation); | ||||||
| 
 |  | ||||||
|     Py_XDECREF(cvt); |     Py_XDECREF(cvt); | ||||||
| 
 | 
 | ||||||
|     return res; |     return res; | ||||||
|  | @ -476,13 +479,13 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs) | ||||||
|     EXC_IF_ASYNC_IN_PROGRESS(self, execute); |     EXC_IF_ASYNC_IN_PROGRESS(self, execute); | ||||||
|     EXC_IF_TPC_PREPARED(self->conn, execute); |     EXC_IF_TPC_PREPARED(self->conn, execute); | ||||||
| 
 | 
 | ||||||
|     if (_psyco_curs_execute(self, operation, vars, self->conn->async)) { |     if (0 > _psyco_curs_execute(self, operation, vars, self->conn->async)) { | ||||||
|         Py_INCREF(Py_None); |  | ||||||
|         return Py_None; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /* success */ | ||||||
|  |     Py_INCREF(Py_None); | ||||||
|  |     return Py_None; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #define psyco_curs_executemany_doc \ | #define psyco_curs_executemany_doc \ | ||||||
|  | @ -521,7 +524,7 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     while ((v = PyIter_Next(vars)) != NULL) { |     while ((v = PyIter_Next(vars)) != NULL) { | ||||||
|         if (_psyco_curs_execute(self, operation, v, 0) == 0) { |         if (0 > _psyco_curs_execute(self, operation, v, 0)) { | ||||||
|             Py_DECREF(v); |             Py_DECREF(v); | ||||||
|             Py_XDECREF(iter); |             Py_XDECREF(iter); | ||||||
|             return NULL; |             return NULL; | ||||||
|  | @ -568,7 +571,7 @@ _psyco_curs_mogrify(cursorObject *self, | ||||||
| 
 | 
 | ||||||
|     if (vars && vars != Py_None) |     if (vars && vars != Py_None) | ||||||
|     { |     { | ||||||
|         if (_mogrify(vars, operation, self, &cvt) == -1) { |         if (0 > _mogrify(vars, operation, self, &cvt)) { | ||||||
|             goto cleanup; |             goto cleanup; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -644,7 +647,7 @@ psyco_curs_cast(cursorObject *self, PyObject *args) | ||||||
| "default) or using the sequence factory previously set in the\n" \ | "default) or using the sequence factory previously set in the\n" \ | ||||||
| "`row_factory` attribute. Return `!None` when no more data is available.\n" | "`row_factory` attribute. Return `!None` when no more data is available.\n" | ||||||
| 
 | 
 | ||||||
| static int | RAISES_NEG static int | ||||||
| _psyco_curs_prefetch(cursorObject *self) | _psyco_curs_prefetch(cursorObject *self) | ||||||
| { | { | ||||||
|     int i = 0; |     int i = 0; | ||||||
|  | @ -661,13 +664,14 @@ _psyco_curs_prefetch(cursorObject *self) | ||||||
|     return i; |     return i; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | RAISES_NEG static int | ||||||
| _psyco_curs_buildrow_fill(cursorObject *self, PyObject *res, | _psyco_curs_buildrow_fill(cursorObject *self, PyObject *res, | ||||||
|                           int row, int n, int istuple) |                           int row, int n, int istuple) | ||||||
| { | { | ||||||
|     int i, len, err; |     int i, len, err; | ||||||
|     const char *str; |     const char *str; | ||||||
|     PyObject *val; |     PyObject *val; | ||||||
|  |     int rv = -1; | ||||||
| 
 | 
 | ||||||
|     for (i=0; i < n; i++) { |     for (i=0; i < n; i++) { | ||||||
|         if (PQgetisnull(self->pgres, row, i)) { |         if (PQgetisnull(self->pgres, row, i)) { | ||||||
|  | @ -682,10 +686,11 @@ _psyco_curs_buildrow_fill(cursorObject *self, PyObject *res, | ||||||
|         Dprintf("_psyco_curs_buildrow: row %ld, element %d, len %d", |         Dprintf("_psyco_curs_buildrow: row %ld, element %d, len %d", | ||||||
|                 self->row, i, len); |                 self->row, i, len); | ||||||
| 
 | 
 | ||||||
|         val = typecast_cast(PyTuple_GET_ITEM(self->casts, i), str, len, |         if (!(val = typecast_cast(PyTuple_GET_ITEM(self->casts, i), str, len, | ||||||
|                             (PyObject*)self); |                             (PyObject*)self))) { | ||||||
|  |             goto exit; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         if (val) { |  | ||||||
|         Dprintf("_psyco_curs_buildrow: val->refcnt = " |         Dprintf("_psyco_curs_buildrow: val->refcnt = " | ||||||
|             FORMAT_CODE_PY_SSIZE_T, |             FORMAT_CODE_PY_SSIZE_T, | ||||||
|             Py_REFCNT(val) |             Py_REFCNT(val) | ||||||
|  | @ -696,45 +701,44 @@ _psyco_curs_buildrow_fill(cursorObject *self, PyObject *res, | ||||||
|         else { |         else { | ||||||
|             err = PySequence_SetItem(res, i, val); |             err = PySequence_SetItem(res, i, val); | ||||||
|             Py_DECREF(val); |             Py_DECREF(val); | ||||||
|                 if (err == -1) { |             if (err == -1) { goto exit; } | ||||||
|                     Py_DECREF(res); |  | ||||||
|                     res = NULL; |  | ||||||
|                     break; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|         } | 
 | ||||||
|         else { |     rv = 0; | ||||||
|             /* an error occurred in the type system, we return NULL to raise
 | 
 | ||||||
|                an exception. the typecast code should already have set the | exit: | ||||||
|                exception type and text */ |     return rv; | ||||||
|             Py_DECREF(res); |  | ||||||
|             res = NULL; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return res; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| _psyco_curs_buildrow(cursorObject *self, int row) | _psyco_curs_buildrow(cursorObject *self, int row) | ||||||
| { | { | ||||||
|     int n; |     int n; | ||||||
|  |     int istuple; | ||||||
|  |     PyObject *t = NULL; | ||||||
|  |     PyObject *rv = NULL; | ||||||
| 
 | 
 | ||||||
|     n = PQnfields(self->pgres); |     n = PQnfields(self->pgres); | ||||||
|     return _psyco_curs_buildrow_fill(self, PyTuple_New(n), row, n, 1); |     istuple = (self->tuple_factory == Py_None); | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| static PyObject * |     if (istuple) { | ||||||
| _psyco_curs_buildrow_with_factory(cursorObject *self, int row) |         t = PyTuple_New(n); | ||||||
| { |     } | ||||||
|     int n; |     else { | ||||||
|     PyObject *res; |         t = PyObject_CallFunctionObjArgs(self->tuple_factory, self, NULL); | ||||||
|  |     } | ||||||
|  |     if (!t) { goto exit; } | ||||||
| 
 | 
 | ||||||
|     n = PQnfields(self->pgres); |     if (0 <= _psyco_curs_buildrow_fill(self, t, row, n, istuple)) { | ||||||
|     if (!(res = PyObject_CallFunctionObjArgs(self->tuple_factory, self, NULL))) |         rv = t; | ||||||
|         return NULL; |         t = NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  |     Py_XDECREF(t); | ||||||
|  |     return rv; | ||||||
| 
 | 
 | ||||||
|     return _psyco_curs_buildrow_fill(self, res, row, n, 0); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
|  | @ -766,11 +770,7 @@ psyco_curs_fetchone(cursorObject *self, PyObject *args) | ||||||
|         return Py_None; |         return Py_None; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (self->tuple_factory == Py_None) |  | ||||||
|     res = _psyco_curs_buildrow(self, self->row); |     res = _psyco_curs_buildrow(self, self->row); | ||||||
|     else |  | ||||||
|         res = _psyco_curs_buildrow_with_factory(self, self->row); |  | ||||||
| 
 |  | ||||||
|     self->row++; /* move the counter to next line */ |     self->row++; /* move the counter to next line */ | ||||||
| 
 | 
 | ||||||
|     /* if the query was async aggresively free pgres, to allow
 |     /* if the query was async aggresively free pgres, to allow
 | ||||||
|  | @ -817,11 +817,7 @@ psyco_curs_next_named(cursorObject *self) | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (self->tuple_factory == Py_None) |  | ||||||
|     res = _psyco_curs_buildrow(self, self->row); |     res = _psyco_curs_buildrow(self, self->row); | ||||||
|     else |  | ||||||
|         res = _psyco_curs_buildrow_with_factory(self, self->row); |  | ||||||
| 
 |  | ||||||
|     self->row++; /* move the counter to next line */ |     self->row++; /* move the counter to next line */ | ||||||
| 
 | 
 | ||||||
|     /* if the query was async aggresively free pgres, to allow
 |     /* if the query was async aggresively free pgres, to allow
 | ||||||
|  | @ -848,7 +844,9 @@ static PyObject * | ||||||
| psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords) | psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords) | ||||||
| { | { | ||||||
|     int i; |     int i; | ||||||
|     PyObject *list, *res; |     PyObject *list = NULL; | ||||||
|  |     PyObject *row = NULL; | ||||||
|  |     PyObject *rv = NULL; | ||||||
| 
 | 
 | ||||||
|     PyObject *pysize = NULL; |     PyObject *pysize = NULL; | ||||||
|     long int size = self->arraysize; |     long int size = self->arraysize; | ||||||
|  | @ -879,8 +877,8 @@ psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords) | ||||||
|         EXC_IF_TPC_PREPARED(self->conn, fetchone); |         EXC_IF_TPC_PREPARED(self->conn, fetchone); | ||||||
|         PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM \"%s\"", |         PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM \"%s\"", | ||||||
|             (int)size, self->name); |             (int)size, self->name); | ||||||
|         if (pq_execute(self, buffer, 0) == -1) return NULL; |         if (pq_execute(self, buffer, 0) == -1) { goto exit; } | ||||||
|         if (_psyco_curs_prefetch(self) < 0) return NULL; |         if (_psyco_curs_prefetch(self) < 0) { goto exit; } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* make sure size is not > than the available number of rows */ |     /* make sure size is not > than the available number of rows */ | ||||||
|  | @ -891,26 +889,21 @@ psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords) | ||||||
|     Dprintf("psyco_curs_fetchmany: size = %ld", size); |     Dprintf("psyco_curs_fetchmany: size = %ld", size); | ||||||
| 
 | 
 | ||||||
|     if (size <= 0) { |     if (size <= 0) { | ||||||
|         return PyList_New(0); |         rv = PyList_New(0); | ||||||
|  |         goto exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     list = PyList_New(size); |     if (!(list = PyList_New(size))) { goto exit; } | ||||||
| 
 | 
 | ||||||
|     for (i = 0; i < size; i++) { |     for (i = 0; i < size; i++) { | ||||||
|         if (self->tuple_factory == Py_None) |         row = _psyco_curs_buildrow(self, self->row); | ||||||
|             res = _psyco_curs_buildrow(self, self->row); |  | ||||||
|         else |  | ||||||
|             res = _psyco_curs_buildrow_with_factory(self, self->row); |  | ||||||
| 
 |  | ||||||
|         self->row++; |         self->row++; | ||||||
| 
 | 
 | ||||||
|         if (res == NULL) { |         if (row == NULL) { goto exit; } | ||||||
|             Py_DECREF(list); |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         PyList_SET_ITEM(list, i, res); |         PyList_SET_ITEM(list, i, row); | ||||||
|     } |     } | ||||||
|  |     row = NULL; | ||||||
| 
 | 
 | ||||||
|     /* if the query was async aggresively free pgres, to allow
 |     /* if the query was async aggresively free pgres, to allow
 | ||||||
|        successive requests to reallocate it */ |        successive requests to reallocate it */ | ||||||
|  | @ -919,7 +912,15 @@ psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords) | ||||||
|         && PyWeakref_GetObject(self->conn->async_cursor) == (PyObject*)self) |         && PyWeakref_GetObject(self->conn->async_cursor) == (PyObject*)self) | ||||||
|         IFCLEARPGRES(self->pgres); |         IFCLEARPGRES(self->pgres); | ||||||
| 
 | 
 | ||||||
|     return list; |     /* success */ | ||||||
|  |     rv = list; | ||||||
|  |     list = NULL; | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  |     Py_XDECREF(list); | ||||||
|  |     Py_XDECREF(row); | ||||||
|  | 
 | ||||||
|  |     return rv; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -936,7 +937,9 @@ static PyObject * | ||||||
| psyco_curs_fetchall(cursorObject *self, PyObject *args) | psyco_curs_fetchall(cursorObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     int i, size; |     int i, size; | ||||||
|     PyObject *list, *res; |     PyObject *list = NULL; | ||||||
|  |     PyObject *row = NULL; | ||||||
|  |     PyObject *rv = NULL; | ||||||
| 
 | 
 | ||||||
|     EXC_IF_CURS_CLOSED(self); |     EXC_IF_CURS_CLOSED(self); | ||||||
|     if (_psyco_curs_prefetch(self) < 0) return NULL; |     if (_psyco_curs_prefetch(self) < 0) return NULL; | ||||||
|  | @ -949,33 +952,27 @@ psyco_curs_fetchall(cursorObject *self, PyObject *args) | ||||||
|         EXC_IF_ASYNC_IN_PROGRESS(self, fetchall); |         EXC_IF_ASYNC_IN_PROGRESS(self, fetchall); | ||||||
|         EXC_IF_TPC_PREPARED(self->conn, fetchall); |         EXC_IF_TPC_PREPARED(self->conn, fetchall); | ||||||
|         PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM \"%s\"", self->name); |         PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM \"%s\"", self->name); | ||||||
|         if (pq_execute(self, buffer, 0) == -1) return NULL; |         if (pq_execute(self, buffer, 0) == -1) { goto exit; } | ||||||
|         if (_psyco_curs_prefetch(self) < 0) return NULL; |         if (_psyco_curs_prefetch(self) < 0) { goto exit; } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     size = self->rowcount - self->row; |     size = self->rowcount - self->row; | ||||||
| 
 | 
 | ||||||
|     if (size <= 0) { |     if (size <= 0) { | ||||||
|         return PyList_New(0); |         rv = PyList_New(0); | ||||||
|  |         goto exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     list = PyList_New(size); |     if (!(list = PyList_New(size))) { goto exit; } | ||||||
| 
 | 
 | ||||||
|     for (i = 0; i < size; i++) { |     for (i = 0; i < size; i++) { | ||||||
|         if (self->tuple_factory == Py_None) |         row = _psyco_curs_buildrow(self, self->row); | ||||||
|             res = _psyco_curs_buildrow(self, self->row); |  | ||||||
|         else |  | ||||||
|             res = _psyco_curs_buildrow_with_factory(self, self->row); |  | ||||||
| 
 |  | ||||||
|         self->row++; |         self->row++; | ||||||
|  |         if (row == NULL) { goto exit; } | ||||||
| 
 | 
 | ||||||
|         if (res == NULL) { |         PyList_SET_ITEM(list, i, row); | ||||||
|             Py_DECREF(list); |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         PyList_SET_ITEM(list, i, res); |  | ||||||
|     } |     } | ||||||
|  |     row = NULL; | ||||||
| 
 | 
 | ||||||
|     /* if the query was async aggresively free pgres, to allow
 |     /* if the query was async aggresively free pgres, to allow
 | ||||||
|        successive requests to reallocate it */ |        successive requests to reallocate it */ | ||||||
|  | @ -984,7 +981,15 @@ psyco_curs_fetchall(cursorObject *self, PyObject *args) | ||||||
|         && PyWeakref_GetObject(self->conn->async_cursor) == (PyObject*)self) |         && PyWeakref_GetObject(self->conn->async_cursor) == (PyObject*)self) | ||||||
|         IFCLEARPGRES(self->pgres); |         IFCLEARPGRES(self->pgres); | ||||||
| 
 | 
 | ||||||
|     return list; |     /* success */ | ||||||
|  |     rv = list; | ||||||
|  |     list = NULL; | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  |     Py_XDECREF(list); | ||||||
|  |     Py_XDECREF(row); | ||||||
|  | 
 | ||||||
|  |     return rv; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -994,7 +999,7 @@ psyco_curs_fetchall(cursorObject *self, PyObject *args) | ||||||
| "callproc(procname, parameters=None) -- Execute stored procedure." | "callproc(procname, parameters=None) -- Execute stored procedure." | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs) | psyco_curs_callproc(cursorObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     const char *procname = NULL; |     const char *procname = NULL; | ||||||
|     char *sql = NULL; |     char *sql = NULL; | ||||||
|  | @ -1006,7 +1011,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs) | ||||||
|     if (!PyArg_ParseTuple(args, "s#|O", |     if (!PyArg_ParseTuple(args, "s#|O", | ||||||
|           &procname, &procname_len, ¶meters |           &procname, &procname_len, ¶meters | ||||||
|        )) |        )) | ||||||
|     { return NULL; } |     { goto exit; } | ||||||
| 
 | 
 | ||||||
|     EXC_IF_CURS_CLOSED(self); |     EXC_IF_CURS_CLOSED(self); | ||||||
|     EXC_IF_ASYNC_IN_PROGRESS(self, callproc); |     EXC_IF_ASYNC_IN_PROGRESS(self, callproc); | ||||||
|  | @ -1015,10 +1020,10 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs) | ||||||
|     if (self->name != NULL) { |     if (self->name != NULL) { | ||||||
|         psyco_set_error(ProgrammingError, self, |         psyco_set_error(ProgrammingError, self, | ||||||
|                          "can't call .callproc() on named cursors", NULL, NULL); |                          "can't call .callproc() on named cursors", NULL, NULL); | ||||||
|         return NULL; |         goto exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(parameters != Py_None) { |     if (parameters != Py_None) { | ||||||
|         nparameters = PyObject_Length(parameters); |         nparameters = PyObject_Length(parameters); | ||||||
|         if (nparameters < 0) nparameters = 0; |         if (nparameters < 0) nparameters = 0; | ||||||
|     } |     } | ||||||
|  | @ -1027,7 +1032,8 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs) | ||||||
|     sl = procname_len + 17 + nparameters*3 - (nparameters ? 1 : 0); |     sl = procname_len + 17 + nparameters*3 - (nparameters ? 1 : 0); | ||||||
|     sql = (char*)PyMem_Malloc(sl); |     sql = (char*)PyMem_Malloc(sl); | ||||||
|     if (sql == NULL) { |     if (sql == NULL) { | ||||||
|         return PyErr_NoMemory(); |         PyErr_NoMemory(); | ||||||
|  |         goto exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     sprintf(sql, "SELECT * FROM %s(", procname); |     sprintf(sql, "SELECT * FROM %s(", procname); | ||||||
|  | @ -1037,15 +1043,16 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs) | ||||||
|     sql[sl-2] = ')'; |     sql[sl-2] = ')'; | ||||||
|     sql[sl-1] = '\0'; |     sql[sl-1] = '\0'; | ||||||
| 
 | 
 | ||||||
|     operation = Bytes_FromString(sql); |     if (!(operation = Bytes_FromString(sql))) { goto exit; } | ||||||
|     PyMem_Free((void*)sql); |  | ||||||
| 
 | 
 | ||||||
|     if (_psyco_curs_execute(self, operation, parameters, self->conn->async)) { |     if (0 <= _psyco_curs_execute(self, operation, parameters, self->conn->async)) { | ||||||
|         Py_INCREF(parameters); |         Py_INCREF(parameters); | ||||||
|         res = parameters; |         res = parameters; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Py_DECREF(operation); | exit: | ||||||
|  |     Py_XDECREF(operation); | ||||||
|  |     PyMem_Free((void*)sql); | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1202,6 +1209,7 @@ static char *_psyco_curs_copy_columns(PyObject *columns) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (NULL == (columnlist = PyMem_Malloc(bufsize))) { |     if (NULL == (columnlist = PyMem_Malloc(bufsize))) { | ||||||
|  |         Py_DECREF(coliter); | ||||||
|         PyErr_NoMemory(); |         PyErr_NoMemory(); | ||||||
|         goto error; |         goto error; | ||||||
|     } |     } | ||||||
|  | @ -1258,8 +1266,8 @@ exit: | ||||||
| #define psyco_curs_copy_from_doc \ | #define psyco_curs_copy_from_doc \ | ||||||
| "copy_from(file, table, sep='\\t', null='\\\\N', size=8192, columns=None) -- Copy table from file." | "copy_from(file, table, sep='\\t', null='\\\\N', size=8192, columns=None) -- Copy table from file." | ||||||
| 
 | 
 | ||||||
| static int | STEALS(1) static int | ||||||
| _psyco_curs_has_read_check(PyObject* o, void* var) | _psyco_curs_has_read_check(PyObject *o, PyObject **var) | ||||||
| { | { | ||||||
|     if (PyObject_HasAttrString(o, "readline") |     if (PyObject_HasAttrString(o, "readline") | ||||||
|         && PyObject_HasAttrString(o, "read")) { |         && PyObject_HasAttrString(o, "read")) { | ||||||
|  | @ -1269,7 +1277,7 @@ _psyco_curs_has_read_check(PyObject* o, void* var) | ||||||
|          * which could invoke the garbage collector.  We thus need an |          * which could invoke the garbage collector.  We thus need an | ||||||
|          * INCREF/DECREF pair if we store this pointer in a GC object, such as |          * INCREF/DECREF pair if we store this pointer in a GC object, such as | ||||||
|          * a cursorObject */ |          * a cursorObject */ | ||||||
|         *((PyObject**)var) = o; |         *var = o; | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|  | @ -1344,7 +1352,7 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs) | ||||||
|     Py_INCREF(file); |     Py_INCREF(file); | ||||||
|     self->copyfile = file; |     self->copyfile = file; | ||||||
| 
 | 
 | ||||||
|     if (pq_execute(self, query, 0) == 1) { |     if (pq_execute(self, query, 0) >= 0) { | ||||||
|         res = Py_None; |         res = Py_None; | ||||||
|         Py_INCREF(Py_None); |         Py_INCREF(Py_None); | ||||||
|     } |     } | ||||||
|  | @ -1365,11 +1373,11 @@ exit: | ||||||
| #define psyco_curs_copy_to_doc \ | #define psyco_curs_copy_to_doc \ | ||||||
| "copy_to(file, table, sep='\\t', null='\\\\N', columns=None) -- Copy table to file." | "copy_to(file, table, sep='\\t', null='\\\\N', columns=None) -- Copy table to file." | ||||||
| 
 | 
 | ||||||
| static int | STEALS(1) static int | ||||||
| _psyco_curs_has_write_check(PyObject* o, void* var) | _psyco_curs_has_write_check(PyObject *o, PyObject **var) | ||||||
| { | { | ||||||
|     if (PyObject_HasAttrString(o, "write")) { |     if (PyObject_HasAttrString(o, "write")) { | ||||||
|         *((PyObject**)var) = o; |         *var = o; | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|  | @ -1440,7 +1448,7 @@ psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs) | ||||||
|     Py_INCREF(file); |     Py_INCREF(file); | ||||||
|     self->copyfile = file; |     self->copyfile = file; | ||||||
| 
 | 
 | ||||||
|     if (pq_execute(self, query, 0) == 1) { |     if (pq_execute(self, query, 0) >= 0) { | ||||||
|         res = Py_None; |         res = Py_None; | ||||||
|         Py_INCREF(Py_None); |         Py_INCREF(Py_None); | ||||||
|     } |     } | ||||||
|  | @ -1514,7 +1522,7 @@ psyco_curs_copy_expert(cursorObject *self, PyObject *args, PyObject *kwargs) | ||||||
|     self->copyfile = file; |     self->copyfile = file; | ||||||
| 
 | 
 | ||||||
|     /* At this point, the SQL statement must be str, not unicode */ |     /* At this point, the SQL statement must be str, not unicode */ | ||||||
|     if (pq_execute(self, Bytes_AS_STRING(sql), 0) == 1) { |     if (pq_execute(self, Bytes_AS_STRING(sql), 0) >= 0) { | ||||||
|         res = Py_None; |         res = Py_None; | ||||||
|         Py_INCREF(res); |         Py_INCREF(res); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -51,19 +51,19 @@ typedef struct { | ||||||
| 
 | 
 | ||||||
| /* functions exported from lobject_int.c */ | /* functions exported from lobject_int.c */ | ||||||
| 
 | 
 | ||||||
| HIDDEN int lobject_open(lobjectObject *self, connectionObject *conn, | RAISES_NEG HIDDEN int lobject_open(lobjectObject *self, connectionObject *conn, | ||||||
|                                    Oid oid, const char *smode, Oid new_oid, |                                    Oid oid, const char *smode, Oid new_oid, | ||||||
|                                    const char *new_file); |                                    const char *new_file); | ||||||
| HIDDEN int lobject_unlink(lobjectObject *self); | RAISES_NEG HIDDEN int lobject_unlink(lobjectObject *self); | ||||||
| HIDDEN int lobject_export(lobjectObject *self, const char *filename); | RAISES_NEG HIDDEN int lobject_export(lobjectObject *self, const char *filename); | ||||||
| 
 | 
 | ||||||
| HIDDEN Py_ssize_t lobject_read(lobjectObject *self, char *buf, size_t len); | RAISES_NEG HIDDEN Py_ssize_t lobject_read(lobjectObject *self, char *buf, size_t len); | ||||||
| HIDDEN Py_ssize_t lobject_write(lobjectObject *self, const char *buf, | RAISES_NEG HIDDEN Py_ssize_t lobject_write(lobjectObject *self, const char *buf, | ||||||
|                                 size_t len); |                                 size_t len); | ||||||
| HIDDEN int lobject_seek(lobjectObject *self, int pos, int whence); | RAISES_NEG HIDDEN int lobject_seek(lobjectObject *self, int pos, int whence); | ||||||
| HIDDEN int lobject_tell(lobjectObject *self); | RAISES_NEG HIDDEN int lobject_tell(lobjectObject *self); | ||||||
| HIDDEN int lobject_truncate(lobjectObject *self, size_t len); | RAISES_NEG HIDDEN int lobject_truncate(lobjectObject *self, size_t len); | ||||||
| HIDDEN int lobject_close(lobjectObject *self); | RAISES_NEG HIDDEN int lobject_close(lobjectObject *self); | ||||||
| 
 | 
 | ||||||
| #define lobject_is_closed(self) \ | #define lobject_is_closed(self) \ | ||||||
|     ((self)->fd < 0 || !(self)->conn || (self)->conn->closed) |     ((self)->fd < 0 || !(self)->conn || (self)->conn->closed) | ||||||
|  |  | ||||||
|  | @ -50,7 +50,7 @@ collect_error(connectionObject *conn, char **error) | ||||||
|  * |  * | ||||||
|  * Valid mode are [r|w|rw|n][t|b] |  * Valid mode are [r|w|rw|n][t|b] | ||||||
|  */ |  */ | ||||||
| static int | RAISES_NEG static int | ||||||
| _lobject_parse_mode(const char *mode) | _lobject_parse_mode(const char *mode) | ||||||
| { | { | ||||||
|     int rv = 0; |     int rv = 0; | ||||||
|  | @ -147,7 +147,7 @@ _lobject_unparse_mode(int mode) | ||||||
| 
 | 
 | ||||||
| /* lobject_open - create a new/open an existing lo */ | /* lobject_open - create a new/open an existing lo */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| lobject_open(lobjectObject *self, connectionObject *conn, | lobject_open(lobjectObject *self, connectionObject *conn, | ||||||
|               Oid oid, const char *smode, Oid new_oid, const char *new_file) |               Oid oid, const char *smode, Oid new_oid, const char *new_file) | ||||||
| { | { | ||||||
|  | @ -170,15 +170,18 @@ lobject_open(lobjectObject *self, connectionObject *conn, | ||||||
| 
 | 
 | ||||||
|     /* if the oid is InvalidOid we create a new lob before opening it
 |     /* if the oid is InvalidOid we create a new lob before opening it
 | ||||||
|        or we import a file from the FS, depending on the value of |        or we import a file from the FS, depending on the value of | ||||||
|        new_name */ |        new_file */ | ||||||
|     if (oid == InvalidOid) { |     if (oid == InvalidOid) { | ||||||
|         if (new_file) |         if (new_file) | ||||||
|             self->oid = lo_import(self->conn->pgconn, new_file); |             self->oid = lo_import(self->conn->pgconn, new_file); | ||||||
|         else |         else { | ||||||
|  |             /* Use lo_creat when possible to be more middleware-friendly.
 | ||||||
|  |                See ticket #88. */ | ||||||
|             if (new_oid != InvalidOid) |             if (new_oid != InvalidOid) | ||||||
|                 self->oid = lo_create(self->conn->pgconn, new_oid); |                 self->oid = lo_create(self->conn->pgconn, new_oid); | ||||||
|             else |             else | ||||||
|                 self->oid = lo_creat(self->conn->pgconn, INV_READ | INV_WRITE); |                 self->oid = lo_creat(self->conn->pgconn, INV_READ | INV_WRITE); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         Dprintf("lobject_open: large object created with oid = %d", |         Dprintf("lobject_open: large object created with oid = %d", | ||||||
|                 self->oid); |                 self->oid); | ||||||
|  | @ -235,7 +238,7 @@ lobject_open(lobjectObject *self, connectionObject *conn, | ||||||
| 
 | 
 | ||||||
| /* lobject_close - close an existing lo */ | /* lobject_close - close an existing lo */ | ||||||
| 
 | 
 | ||||||
| static int | RAISES_NEG static int | ||||||
| lobject_close_locked(lobjectObject *self, char **error) | lobject_close_locked(lobjectObject *self, char **error) | ||||||
| { | { | ||||||
|     int retvalue; |     int retvalue; | ||||||
|  | @ -268,7 +271,7 @@ lobject_close_locked(lobjectObject *self, char **error) | ||||||
|     return retvalue; |     return retvalue; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| lobject_close(lobjectObject *self) | lobject_close(lobjectObject *self) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  | @ -290,7 +293,7 @@ lobject_close(lobjectObject *self) | ||||||
| 
 | 
 | ||||||
| /* lobject_unlink - remove an lo from database */ | /* lobject_unlink - remove an lo from database */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| lobject_unlink(lobjectObject *self) | lobject_unlink(lobjectObject *self) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  | @ -324,7 +327,7 @@ lobject_unlink(lobjectObject *self) | ||||||
| 
 | 
 | ||||||
| /* lobject_write - write bytes to a lo */ | /* lobject_write - write bytes to a lo */ | ||||||
| 
 | 
 | ||||||
| Py_ssize_t | RAISES_NEG Py_ssize_t | ||||||
| lobject_write(lobjectObject *self, const char *buf, size_t len) | lobject_write(lobjectObject *self, const char *buf, size_t len) | ||||||
| { | { | ||||||
|     Py_ssize_t written; |     Py_ssize_t written; | ||||||
|  | @ -351,7 +354,7 @@ lobject_write(lobjectObject *self, const char *buf, size_t len) | ||||||
| 
 | 
 | ||||||
| /* lobject_read - read bytes from a lo */ | /* lobject_read - read bytes from a lo */ | ||||||
| 
 | 
 | ||||||
| Py_ssize_t | RAISES_NEG Py_ssize_t | ||||||
| lobject_read(lobjectObject *self, char *buf, size_t len) | lobject_read(lobjectObject *self, char *buf, size_t len) | ||||||
| { | { | ||||||
|     Py_ssize_t n_read; |     Py_ssize_t n_read; | ||||||
|  | @ -375,7 +378,7 @@ lobject_read(lobjectObject *self, char *buf, size_t len) | ||||||
| 
 | 
 | ||||||
| /* lobject_seek - move the current position in the lo */ | /* lobject_seek - move the current position in the lo */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| lobject_seek(lobjectObject *self, int pos, int whence) | lobject_seek(lobjectObject *self, int pos, int whence) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  | @ -403,7 +406,7 @@ lobject_seek(lobjectObject *self, int pos, int whence) | ||||||
| 
 | 
 | ||||||
| /* lobject_tell - tell the current position in the lo */ | /* lobject_tell - tell the current position in the lo */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| lobject_tell(lobjectObject *self) | lobject_tell(lobjectObject *self) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  | @ -430,7 +433,7 @@ lobject_tell(lobjectObject *self) | ||||||
| 
 | 
 | ||||||
| /* lobject_export - export to a local file */ | /* lobject_export - export to a local file */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| lobject_export(lobjectObject *self, const char *filename) | lobject_export(lobjectObject *self, const char *filename) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  | @ -459,7 +462,7 @@ lobject_export(lobjectObject *self, const char *filename) | ||||||
| 
 | 
 | ||||||
| #if PG_VERSION_HEX >= 0x080300 | #if PG_VERSION_HEX >= 0x080300 | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| lobject_truncate(lobjectObject *self, size_t len) | lobject_truncate(lobjectObject *self, size_t len) | ||||||
| { | { | ||||||
|     int retvalue; |     int retvalue; | ||||||
|  |  | ||||||
|  | @ -373,7 +373,7 @@ lobject_dealloc(PyObject* obj) | ||||||
| static int | static int | ||||||
| lobject_init(PyObject *obj, PyObject *args, PyObject *kwds) | lobject_init(PyObject *obj, PyObject *args, PyObject *kwds) | ||||||
| { | { | ||||||
|     Oid oid=InvalidOid, new_oid=InvalidOid; |     int oid = (int)InvalidOid, new_oid = (int)InvalidOid; | ||||||
|     const char *smode = ""; |     const char *smode = ""; | ||||||
|     const char *new_file = NULL; |     const char *new_file = NULL; | ||||||
|     PyObject *conn; |     PyObject *conn; | ||||||
|  | @ -383,7 +383,7 @@ lobject_init(PyObject *obj, PyObject *args, PyObject *kwds) | ||||||
|         return -1; |         return -1; | ||||||
| 
 | 
 | ||||||
|     return lobject_setup((lobjectObject *)obj, |     return lobject_setup((lobjectObject *)obj, | ||||||
|         (connectionObject *)conn, oid, smode, new_oid, new_file); |         (connectionObject *)conn, (Oid)oid, smode, (Oid)new_oid, new_file); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
|  |  | ||||||
|  | @ -52,29 +52,35 @@ microprotocols_init(PyObject *dict) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* microprotocols_add - add a reverse type-caster to the dictionary */ | /* microprotocols_add - add a reverse type-caster to the dictionary
 | ||||||
| 
 |  * | ||||||
|  |  * Return 0 on success, else -1 and set an exception. | ||||||
|  |  */ | ||||||
| int | int | ||||||
| microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast) | microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast) | ||||||
| { | { | ||||||
|     PyObject *key; |     PyObject *key = NULL; | ||||||
|  |     int rv = -1; | ||||||
| 
 | 
 | ||||||
|     if (proto == NULL) proto = (PyObject*)&isqlquoteType; |     if (proto == NULL) proto = (PyObject*)&isqlquoteType; | ||||||
| 
 | 
 | ||||||
|     Dprintf("microprotocols_add: cast %p for (%s, ?)", cast, type->tp_name); |     Dprintf("microprotocols_add: cast %p for (%s, ?)", cast, type->tp_name); | ||||||
| 
 | 
 | ||||||
|     key = PyTuple_Pack(2, (PyObject*)type, proto); |     if (!(key = PyTuple_Pack(2, (PyObject*)type, proto))) { goto exit; } | ||||||
|     PyDict_SetItem(psyco_adapters, key, cast); |     if (0 != PyDict_SetItem(psyco_adapters, key, cast)) { goto exit; } | ||||||
|     Py_DECREF(key); |  | ||||||
| 
 | 
 | ||||||
|     return 0; |     rv = 0; | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  |     Py_XDECREF(key); | ||||||
|  |     return rv; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Check if one of `obj` superclasses has an adapter for `proto`.
 | /* Check if one of `obj` superclasses has an adapter for `proto`.
 | ||||||
|  * |  * | ||||||
|  * If it does, return a *borrowed reference* to the adapter, else NULL. |  * If it does, return a *borrowed reference* to the adapter, else to None. | ||||||
|  */ |  */ | ||||||
| static PyObject * | BORROWED static PyObject * | ||||||
| _get_superclass_adapter(PyObject *obj, PyObject *proto) | _get_superclass_adapter(PyObject *obj, PyObject *proto) | ||||||
| { | { | ||||||
|     PyTypeObject *type; |     PyTypeObject *type; | ||||||
|  | @ -89,14 +95,14 @@ _get_superclass_adapter(PyObject *obj, PyObject *proto) | ||||||
| #endif | #endif | ||||||
|         type->tp_mro)) { |         type->tp_mro)) { | ||||||
|         /* has no mro */ |         /* has no mro */ | ||||||
|         return NULL; |         return Py_None; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Walk the mro from the most specific subclass. */ |     /* Walk the mro from the most specific subclass. */ | ||||||
|     mro = type->tp_mro; |     mro = type->tp_mro; | ||||||
|     for (i = 1, ii = PyTuple_GET_SIZE(mro); i < ii; ++i) { |     for (i = 1, ii = PyTuple_GET_SIZE(mro); i < ii; ++i) { | ||||||
|         st = PyTuple_GET_ITEM(mro, i); |         st = PyTuple_GET_ITEM(mro, i); | ||||||
|         key = PyTuple_Pack(2, st, proto); |         if (!(key = PyTuple_Pack(2, st, proto))) { return NULL; } | ||||||
|         adapter = PyDict_GetItem(psyco_adapters, key); |         adapter = PyDict_GetItem(psyco_adapters, key); | ||||||
|         Py_DECREF(key); |         Py_DECREF(key); | ||||||
| 
 | 
 | ||||||
|  | @ -119,7 +125,7 @@ _get_superclass_adapter(PyObject *obj, PyObject *proto) | ||||||
|             return adapter; |             return adapter; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return NULL; |     return Py_None; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -139,7 +145,7 @@ microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt) | ||||||
|         Py_TYPE(obj)->tp_name); |         Py_TYPE(obj)->tp_name); | ||||||
| 
 | 
 | ||||||
|     /* look for an adapter in the registry */ |     /* look for an adapter in the registry */ | ||||||
|     key = PyTuple_Pack(2, Py_TYPE(obj), proto); |     if (!(key = PyTuple_Pack(2, Py_TYPE(obj), proto))) { return NULL; } | ||||||
|     adapter = PyDict_GetItem(psyco_adapters, key); |     adapter = PyDict_GetItem(psyco_adapters, key); | ||||||
|     Py_DECREF(key); |     Py_DECREF(key); | ||||||
|     if (adapter) { |     if (adapter) { | ||||||
|  | @ -148,7 +154,10 @@ microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Check if a superclass can be adapted and use the same adapter. */ |     /* Check if a superclass can be adapted and use the same adapter. */ | ||||||
|     if (NULL != (adapter = _get_superclass_adapter(obj, proto))) { |     if (!(adapter = _get_superclass_adapter(obj, proto))) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     if (Py_None != adapter) { | ||||||
|         adapted = PyObject_CallFunctionObjArgs(adapter, obj, NULL); |         adapted = PyObject_CallFunctionObjArgs(adapter, obj, NULL); | ||||||
|         return adapted; |         return adapted; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -64,7 +64,7 @@ strip_severity(const char *msg) | ||||||
|    code.  A list of error codes can be found at: |    code.  A list of error codes can be found at: | ||||||
| 
 | 
 | ||||||
|    http://www.postgresql.org/docs/current/static/errcodes-appendix.html */
 |    http://www.postgresql.org/docs/current/static/errcodes-appendix.html */
 | ||||||
| static PyObject * | BORROWED static PyObject * | ||||||
| exception_from_sqlstate(const char *sqlstate) | exception_from_sqlstate(const char *sqlstate) | ||||||
| { | { | ||||||
|     switch (sqlstate[0]) { |     switch (sqlstate[0]) { | ||||||
|  | @ -151,7 +151,7 @@ exception_from_sqlstate(const char *sqlstate) | ||||||
| 
 | 
 | ||||||
|    This function should be called while holding the GIL. */ |    This function should be called while holding the GIL. */ | ||||||
| 
 | 
 | ||||||
| static void | RAISES static void | ||||||
| pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres) | pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres) | ||||||
| { | { | ||||||
|     PyObject *exc = NULL; |     PyObject *exc = NULL; | ||||||
|  | @ -249,7 +249,9 @@ pq_clear_critical(connectionObject *conn) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | /* return -1 if the exception is set (i.e. if conn->critical is set),
 | ||||||
|  |  * else 0 */ | ||||||
|  | RAISES_NEG static int | ||||||
| pq_resolve_critical(connectionObject *conn, int close) | pq_resolve_critical(connectionObject *conn, int close) | ||||||
| { | { | ||||||
|     Dprintf("pq_resolve_critical: resolving %s", conn->critical); |     Dprintf("pq_resolve_critical: resolving %s", conn->critical); | ||||||
|  | @ -267,8 +269,10 @@ pq_resolve_critical(connectionObject *conn, int close) | ||||||
| 
 | 
 | ||||||
|         /* remember to clear the critical! */ |         /* remember to clear the critical! */ | ||||||
|         pq_clear_critical(conn); |         pq_clear_critical(conn); | ||||||
|  | 
 | ||||||
|  |         return -1; | ||||||
|     } |     } | ||||||
|     return NULL; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* pq_clear_async - clear the effects of a previous async query
 | /* pq_clear_async - clear the effects of a previous async query
 | ||||||
|  | @ -300,19 +304,16 @@ pq_clear_async(connectionObject *conn) | ||||||
| 
 | 
 | ||||||
|    Accepted arg values are 1 (nonblocking) and 0 (blocking). |    Accepted arg values are 1 (nonblocking) and 0 (blocking). | ||||||
| 
 | 
 | ||||||
|    Return 0 if everything ok, else nonzero. |    Return 0 if everything ok, else < 0 and set an exception. | ||||||
| 
 |  | ||||||
|    In case of error, if pyerr is nonzero, set a Python exception. |  | ||||||
|  */ |  */ | ||||||
| int | RAISES_NEG int | ||||||
| pq_set_non_blocking(connectionObject *conn, int arg, int pyerr) | pq_set_non_blocking(connectionObject *conn, int arg) | ||||||
| { | { | ||||||
|     int ret = PQsetnonblocking(conn->pgconn, arg); |     int ret = PQsetnonblocking(conn->pgconn, arg); | ||||||
|     if (0 != ret) { |     if (0 != ret) { | ||||||
|         Dprintf("PQsetnonblocking(%d) FAILED", arg); |         Dprintf("PQsetnonblocking(%d) FAILED", arg); | ||||||
|         if (pyerr) { |  | ||||||
|         PyErr_SetString(OperationalError, "PQsetnonblocking() failed"); |         PyErr_SetString(OperationalError, "PQsetnonblocking() failed"); | ||||||
|         } |         ret = -1; | ||||||
|     } |     } | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  | @ -382,7 +383,7 @@ cleanup: | ||||||
|    This function should be called while holding the global interpreter |    This function should be called while holding the global interpreter | ||||||
|    lock. |    lock. | ||||||
|  */ |  */ | ||||||
| void | RAISES void | ||||||
| pq_complete_error(connectionObject *conn, PGresult **pgres, char **error) | pq_complete_error(connectionObject *conn, PGresult **pgres, char **error) | ||||||
| { | { | ||||||
|     Dprintf("pq_complete_error: pgconn = %p, pgres = %p, error = %s", |     Dprintf("pq_complete_error: pgconn = %p, pgres = %p, error = %s", | ||||||
|  | @ -444,38 +445,39 @@ pq_commit(connectionObject *conn) | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|     char *error = NULL; |     char *error = NULL; | ||||||
| 
 | 
 | ||||||
|  |     Py_BEGIN_ALLOW_THREADS; | ||||||
|  |     pthread_mutex_lock(&conn->lock); | ||||||
|  | 
 | ||||||
|     Dprintf("pq_commit: pgconn = %p, autocommit = %d, status = %d", |     Dprintf("pq_commit: pgconn = %p, autocommit = %d, status = %d", | ||||||
|             conn->pgconn, conn->autocommit, conn->status); |             conn->pgconn, conn->autocommit, conn->status); | ||||||
| 
 | 
 | ||||||
|     if (conn->autocommit || conn->status != CONN_STATUS_BEGIN) { |     if (conn->autocommit || conn->status != CONN_STATUS_BEGIN) { | ||||||
|         Dprintf("pq_commit: no transaction to commit"); |         Dprintf("pq_commit: no transaction to commit"); | ||||||
|         return 0; |         retvalue = 0; | ||||||
|     } |     } | ||||||
| 
 |     else { | ||||||
|     Py_BEGIN_ALLOW_THREADS; |  | ||||||
|     pthread_mutex_lock(&conn->lock); |  | ||||||
|         conn->mark += 1; |         conn->mark += 1; | ||||||
| 
 |  | ||||||
|         retvalue = pq_execute_command_locked(conn, "COMMIT", &pgres, &error, &_save); |         retvalue = pq_execute_command_locked(conn, "COMMIT", &pgres, &error, &_save); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     Py_BLOCK_THREADS; |     Py_BLOCK_THREADS; | ||||||
|     conn_notice_process(conn); |     conn_notice_process(conn); | ||||||
|     Py_UNBLOCK_THREADS; |     Py_UNBLOCK_THREADS; | ||||||
| 
 | 
 | ||||||
|  |     /* Even if an error occurred, the connection will be rolled back,
 | ||||||
|  |        so we unconditionally set the connection status here. */ | ||||||
|  |     conn->status = CONN_STATUS_READY; | ||||||
|  | 
 | ||||||
|     pthread_mutex_unlock(&conn->lock); |     pthread_mutex_unlock(&conn->lock); | ||||||
|     Py_END_ALLOW_THREADS; |     Py_END_ALLOW_THREADS; | ||||||
| 
 | 
 | ||||||
|     if (retvalue < 0) |     if (retvalue < 0) | ||||||
|         pq_complete_error(conn, &pgres, &error); |         pq_complete_error(conn, &pgres, &error); | ||||||
| 
 | 
 | ||||||
|     /* Even if an error occurred, the connection will be rolled back,
 |  | ||||||
|        so we unconditionally set the connection status here. */ |  | ||||||
|     conn->status = CONN_STATUS_READY; |  | ||||||
| 
 |  | ||||||
|     return retvalue; |     return retvalue; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| pq_abort_locked(connectionObject *conn, PGresult **pgres, char **error, | pq_abort_locked(connectionObject *conn, PGresult **pgres, char **error, | ||||||
|                 PyThreadState **tstate) |                 PyThreadState **tstate) | ||||||
| { | { | ||||||
|  | @ -502,7 +504,7 @@ pq_abort_locked(connectionObject *conn, PGresult **pgres, char **error, | ||||||
|    This function should be called while holding the global interpreter |    This function should be called while holding the global interpreter | ||||||
|    lock. */ |    lock. */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| pq_abort(connectionObject *conn) | pq_abort(connectionObject *conn) | ||||||
| { | { | ||||||
|     int retvalue = -1; |     int retvalue = -1; | ||||||
|  | @ -512,11 +514,6 @@ pq_abort(connectionObject *conn) | ||||||
|     Dprintf("pq_abort: pgconn = %p, autocommit = %d, status = %d", |     Dprintf("pq_abort: pgconn = %p, autocommit = %d, status = %d", | ||||||
|             conn->pgconn, conn->autocommit, conn->status); |             conn->pgconn, conn->autocommit, conn->status); | ||||||
| 
 | 
 | ||||||
|     if (conn->autocommit || conn->status != CONN_STATUS_BEGIN) { |  | ||||||
|         Dprintf("pq_abort: no transaction to abort"); |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Py_BEGIN_ALLOW_THREADS; |     Py_BEGIN_ALLOW_THREADS; | ||||||
|     pthread_mutex_lock(&conn->lock); |     pthread_mutex_lock(&conn->lock); | ||||||
| 
 | 
 | ||||||
|  | @ -544,7 +541,7 @@ pq_abort(connectionObject *conn) | ||||||
|    connection without holding the global interpreter lock. |    connection without holding the global interpreter lock. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| pq_reset_locked(connectionObject *conn, PGresult **pgres, char **error, | pq_reset_locked(connectionObject *conn, PGresult **pgres, char **error, | ||||||
|                 PyThreadState **tstate) |                 PyThreadState **tstate) | ||||||
| { | { | ||||||
|  | @ -836,7 +833,7 @@ pq_flush(connectionObject *conn) | ||||||
|    this fucntion locks the connection object |    this fucntion locks the connection object | ||||||
|    this function call Py_*_ALLOW_THREADS macros */ |    this function call Py_*_ALLOW_THREADS macros */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| pq_execute(cursorObject *curs, const char *query, int async) | pq_execute(cursorObject *curs, const char *query, int async) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|  | @ -846,8 +843,7 @@ pq_execute(cursorObject *curs, const char *query, int async) | ||||||
|     /* if the status of the connection is critical raise an exception and
 |     /* if the status of the connection is critical raise an exception and
 | ||||||
|        definitely close the connection */ |        definitely close the connection */ | ||||||
|     if (curs->conn->critical) { |     if (curs->conn->critical) { | ||||||
|         pq_resolve_critical(curs->conn, 1); |         return pq_resolve_critical(curs->conn, 1); | ||||||
|         return -1; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* check status of connection, raise error if not OK */ |     /* check status of connection, raise error if not OK */ | ||||||
|  | @ -942,12 +938,13 @@ pq_execute(cursorObject *curs, const char *query, int async) | ||||||
|        to respect the old DBAPI-2.0 compatible behaviour */ |        to respect the old DBAPI-2.0 compatible behaviour */ | ||||||
|     if (async == 0) { |     if (async == 0) { | ||||||
|         Dprintf("pq_execute: entering syncronous DBAPI compatibility mode"); |         Dprintf("pq_execute: entering syncronous DBAPI compatibility mode"); | ||||||
|         if (pq_fetch(curs) == -1) return -1; |         if (pq_fetch(curs) < 0) return -1; | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|  |         PyObject *tmp; | ||||||
|         curs->conn->async_status = async_status; |         curs->conn->async_status = async_status; | ||||||
|         curs->conn->async_cursor = PyWeakref_NewRef((PyObject *)curs, NULL); |         curs->conn->async_cursor = tmp = PyWeakref_NewRef((PyObject *)curs, NULL); | ||||||
|         if (!curs->conn->async_cursor) { |         if (!tmp) { | ||||||
|             /* weakref creation failed */ |             /* weakref creation failed */ | ||||||
|             return -1; |             return -1; | ||||||
|         } |         } | ||||||
|  | @ -1016,7 +1013,7 @@ pq_get_last_result(connectionObject *conn) | ||||||
|       1 - result from backend (possibly data is ready) |       1 - result from backend (possibly data is ready) | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| static int | RAISES_NEG static int | ||||||
| _pq_fetch_tuples(cursorObject *curs) | _pq_fetch_tuples(cursorObject *curs) | ||||||
| { | { | ||||||
|     int i, *dsize = NULL; |     int i, *dsize = NULL; | ||||||
|  | @ -1416,8 +1413,7 @@ pq_fetch(cursorObject *curs) | ||||||
|         Dprintf("pq_fetch: got a NULL pgres, checking for critical"); |         Dprintf("pq_fetch: got a NULL pgres, checking for critical"); | ||||||
|         pq_set_critical(curs->conn); |         pq_set_critical(curs->conn); | ||||||
|         if (curs->conn->critical) { |         if (curs->conn->critical) { | ||||||
|             pq_resolve_critical(curs->conn); |             return pq_resolve_critical(curs->conn); | ||||||
|             return -1; |  | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             return 0; |             return 0; | ||||||
|  | @ -1493,13 +1489,7 @@ pq_fetch(cursorObject *curs) | ||||||
|        raise the exception but we avoid to close the connection) */ |        raise the exception but we avoid to close the connection) */ | ||||||
|     Dprintf("pq_fetch: fetching done; check for critical errors"); |     Dprintf("pq_fetch: fetching done; check for critical errors"); | ||||||
|     if (curs->conn->critical) { |     if (curs->conn->critical) { | ||||||
|         if (ex == -1) { |         return pq_resolve_critical(curs->conn, ex == -1 ? 1 : 0); | ||||||
|             pq_resolve_critical(curs->conn, 1); |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             pq_resolve_critical(curs->conn, 0); |  | ||||||
|         } |  | ||||||
|         return -1; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return ex; |     return ex; | ||||||
|  |  | ||||||
|  | @ -35,18 +35,18 @@ | ||||||
| 
 | 
 | ||||||
| /* exported functions */ | /* exported functions */ | ||||||
| HIDDEN PGresult *pq_get_last_result(connectionObject *conn); | HIDDEN PGresult *pq_get_last_result(connectionObject *conn); | ||||||
| HIDDEN int pq_fetch(cursorObject *curs); | RAISES_NEG HIDDEN int pq_fetch(cursorObject *curs); | ||||||
| HIDDEN int pq_execute(cursorObject *curs, const char *query, int async); | RAISES_NEG HIDDEN int pq_execute(cursorObject *curs, const char *query, int async); | ||||||
| HIDDEN int pq_send_query(connectionObject *conn, const char *query); | HIDDEN int pq_send_query(connectionObject *conn, const char *query); | ||||||
| HIDDEN int pq_begin_locked(connectionObject *conn, PGresult **pgres, | HIDDEN int pq_begin_locked(connectionObject *conn, PGresult **pgres, | ||||||
|                            char **error, PyThreadState **tstate); |                            char **error, PyThreadState **tstate); | ||||||
| HIDDEN int pq_commit(connectionObject *conn); | HIDDEN int pq_commit(connectionObject *conn); | ||||||
| HIDDEN int pq_abort_locked(connectionObject *conn, PGresult **pgres, | RAISES_NEG HIDDEN int pq_abort_locked(connectionObject *conn, PGresult **pgres, | ||||||
|                            char **error, PyThreadState **tstate); |                            char **error, PyThreadState **tstate); | ||||||
| HIDDEN int pq_abort(connectionObject *conn); | RAISES_NEG HIDDEN int pq_abort(connectionObject *conn); | ||||||
| HIDDEN int pq_reset_locked(connectionObject *conn, PGresult **pgres, | HIDDEN int pq_reset_locked(connectionObject *conn, PGresult **pgres, | ||||||
|                             char **error, PyThreadState **tstate); |                             char **error, PyThreadState **tstate); | ||||||
| HIDDEN int pq_reset(connectionObject *conn); | RAISES_NEG HIDDEN int pq_reset(connectionObject *conn); | ||||||
| HIDDEN char *pq_get_guc_locked(connectionObject *conn, const char *param, | HIDDEN char *pq_get_guc_locked(connectionObject *conn, const char *param, | ||||||
|                                PGresult **pgres, |                                PGresult **pgres, | ||||||
|                                char **error, PyThreadState **tstate); |                                char **error, PyThreadState **tstate); | ||||||
|  | @ -61,7 +61,7 @@ HIDDEN int pq_is_busy(connectionObject *conn); | ||||||
| HIDDEN int pq_is_busy_locked(connectionObject *conn); | HIDDEN int pq_is_busy_locked(connectionObject *conn); | ||||||
| HIDDEN int pq_flush(connectionObject *conn); | HIDDEN int pq_flush(connectionObject *conn); | ||||||
| HIDDEN void pq_clear_async(connectionObject *conn); | HIDDEN void pq_clear_async(connectionObject *conn); | ||||||
| HIDDEN int pq_set_non_blocking(connectionObject *conn, int arg, int pyerr); | RAISES_NEG HIDDEN int pq_set_non_blocking(connectionObject *conn, int arg); | ||||||
| 
 | 
 | ||||||
| HIDDEN void pq_set_critical(connectionObject *conn, const char *msg); | HIDDEN void pq_set_critical(connectionObject *conn, const char *msg); | ||||||
| 
 | 
 | ||||||
|  | @ -69,7 +69,7 @@ HIDDEN int pq_execute_command_locked(connectionObject *conn, | ||||||
|                                      const char *query, |                                      const char *query, | ||||||
|                                      PGresult **pgres, char **error, |                                      PGresult **pgres, char **error, | ||||||
|                                      PyThreadState **tstate); |                                      PyThreadState **tstate); | ||||||
| HIDDEN void pq_complete_error(connectionObject *conn, PGresult **pgres, | RAISES HIDDEN void pq_complete_error(connectionObject *conn, PGresult **pgres, | ||||||
|                               char **error); |                               char **error); | ||||||
| 
 | 
 | ||||||
| #endif /* !defined(PSYCOPG_PQPATH_H) */ | #endif /* !defined(PSYCOPG_PQPATH_H) */ | ||||||
|  |  | ||||||
|  | @ -120,17 +120,19 @@ HIDDEN PyObject *psyco_GetDecimalType(void); | ||||||
| typedef struct cursorObject cursorObject; | typedef struct cursorObject cursorObject; | ||||||
| 
 | 
 | ||||||
| /* some utility functions */ | /* some utility functions */ | ||||||
| HIDDEN void psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg, | RAISES HIDDEN void psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg, | ||||||
|                             const char *pgerror, const char *pgcode); |                             const char *pgerror, const char *pgcode); | ||||||
| 
 | 
 | ||||||
| HIDDEN char *psycopg_escape_string(PyObject *conn, | HIDDEN char *psycopg_escape_string(PyObject *conn, | ||||||
|               const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen); |               const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen); | ||||||
| HIDDEN char *psycopg_escape_identifier_easy(const char *from, Py_ssize_t len); | HIDDEN char *psycopg_escape_identifier_easy(const char *from, Py_ssize_t len); | ||||||
| HIDDEN char *psycopg_strdup(const char *from, Py_ssize_t len); | HIDDEN int psycopg_strdup(char **to, const char *from, Py_ssize_t len); | ||||||
| HIDDEN PyObject * psycopg_ensure_bytes(PyObject *obj); |  | ||||||
| HIDDEN PyObject * psycopg_ensure_text(PyObject *obj); |  | ||||||
| HIDDEN int psycopg_is_text_file(PyObject *f); | HIDDEN int psycopg_is_text_file(PyObject *f); | ||||||
| 
 | 
 | ||||||
|  | STEALS(1) HIDDEN PyObject * psycopg_ensure_bytes(PyObject *obj); | ||||||
|  | 
 | ||||||
|  | STEALS(1) HIDDEN PyObject * psycopg_ensure_text(PyObject *obj); | ||||||
|  | 
 | ||||||
| /* Exceptions docstrings */ | /* Exceptions docstrings */ | ||||||
| #define Error_doc \ | #define Error_doc \ | ||||||
| "Base class for error exceptions." | "Base class for error exceptions." | ||||||
|  |  | ||||||
|  | @ -143,14 +143,6 @@ psyco_connect(PyObject *self, PyObject *args, PyObject *keywds) | ||||||
| "  * `name`: Name for the new type\n" \ | "  * `name`: Name for the new type\n" \ | ||||||
| "  * `baseobj`: Adapter to perform type conversion of a single array item." | "  * `baseobj`: Adapter to perform type conversion of a single array item." | ||||||
| 
 | 
 | ||||||
| static void |  | ||||||
| _psyco_register_type_set(PyObject **dict, PyObject *type) |  | ||||||
| { |  | ||||||
|     if (*dict == NULL) |  | ||||||
|         *dict = PyDict_New(); |  | ||||||
|     typecast_add(type, *dict, 0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_register_type(PyObject *self, PyObject *args) | psyco_register_type(PyObject *self, PyObject *args) | ||||||
| { | { | ||||||
|  | @ -162,10 +154,16 @@ psyco_register_type(PyObject *self, PyObject *args) | ||||||
| 
 | 
 | ||||||
|     if (obj != NULL && obj != Py_None) { |     if (obj != NULL && obj != Py_None) { | ||||||
|         if (PyObject_TypeCheck(obj, &cursorType)) { |         if (PyObject_TypeCheck(obj, &cursorType)) { | ||||||
|             _psyco_register_type_set(&(((cursorObject*)obj)->string_types), type); |             PyObject **dict = &(((cursorObject*)obj)->string_types); | ||||||
|  |             if (*dict == NULL) { | ||||||
|  |                 if (!(*dict = PyDict_New())) { return NULL; } | ||||||
|  |             } | ||||||
|  |             if (0 > typecast_add(type, *dict, 0)) { return NULL; } | ||||||
|         } |         } | ||||||
|         else if (PyObject_TypeCheck(obj, &connectionType)) { |         else if (PyObject_TypeCheck(obj, &connectionType)) { | ||||||
|             typecast_add(type, ((connectionObject*)obj)->string_types, 0); |             if (0 > typecast_add(type, ((connectionObject*)obj)->string_types, 0)) { | ||||||
|  |                 return NULL; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             PyErr_SetString(PyExc_TypeError, |             PyErr_SetString(PyExc_TypeError, | ||||||
|  | @ -174,7 +172,7 @@ psyco_register_type(PyObject *self, PyObject *args) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         typecast_add(type, NULL, 0); |         if (0 > typecast_add(type, NULL, 0)) { return NULL; } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Py_INCREF(Py_None); |     Py_INCREF(Py_None); | ||||||
|  | @ -182,66 +180,108 @@ psyco_register_type(PyObject *self, PyObject *args) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* default adapters */ | /* Initialize the default adapters map
 | ||||||
| 
 |  * | ||||||
| static void |  * Return 0 on success, else -1 and set an exception. | ||||||
|  |  */ | ||||||
|  | static int | ||||||
| psyco_adapters_init(PyObject *mod) | psyco_adapters_init(PyObject *mod) | ||||||
| { | { | ||||||
|     PyObject *call; |     PyObject *call = NULL; | ||||||
|  |     int rv = -1; | ||||||
| 
 | 
 | ||||||
|     microprotocols_add(&PyFloat_Type, NULL, (PyObject*)&pfloatType); |     if (0 != microprotocols_add(&PyFloat_Type, NULL, (PyObject*)&pfloatType)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
| #if PY_MAJOR_VERSION < 3 | #if PY_MAJOR_VERSION < 3 | ||||||
|     microprotocols_add(&PyInt_Type, NULL, (PyObject*)&pintType); |     if (0 != microprotocols_add(&PyInt_Type, NULL, (PyObject*)&pintType)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
| #endif | #endif | ||||||
|     microprotocols_add(&PyLong_Type, NULL, (PyObject*)&pintType); |     if (0 != microprotocols_add(&PyLong_Type, NULL, (PyObject*)&pintType)) { | ||||||
|     microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType); |         goto exit; | ||||||
|  |     } | ||||||
|  |     if (0 != microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     /* strings */ |     /* strings */ | ||||||
| #if PY_MAJOR_VERSION < 3 | #if PY_MAJOR_VERSION < 3 | ||||||
|     microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType); |     if (0 != microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
| #endif | #endif | ||||||
|     microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType); |     if (0 != microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     /* binary */ |     /* binary */ | ||||||
| #if PY_MAJOR_VERSION < 3 | #if PY_MAJOR_VERSION < 3 | ||||||
|     microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType); |     if (0 != microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
| #else | #else | ||||||
|     microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType); |     if (0 != microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 6 | #if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 6 | ||||||
|     microprotocols_add(&PyByteArray_Type, NULL, (PyObject*)&binaryType); |     if (0 != microprotocols_add(&PyByteArray_Type, NULL, (PyObject*)&binaryType)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
| #endif | #endif | ||||||
| #if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 7 | #if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 7 | ||||||
|     microprotocols_add(&PyMemoryView_Type, NULL, (PyObject*)&binaryType); |     if (0 != microprotocols_add(&PyMemoryView_Type, NULL, (PyObject*)&binaryType)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType); |     if (0 != microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     /* the module has already been initialized, so we can obtain the callable
 |     /* the module has already been initialized, so we can obtain the callable
 | ||||||
|        objects directly from its dictionary :) */ |        objects directly from its dictionary :) */ | ||||||
|     call = PyMapping_GetItemString(mod, "DateFromPy"); |     if (!(call = PyMapping_GetItemString(mod, "DateFromPy"))) { goto exit; } | ||||||
|     microprotocols_add(PyDateTimeAPI->DateType, NULL, call); |     if (0 != microprotocols_add(PyDateTimeAPI->DateType, NULL, call)) { goto exit; } | ||||||
|     call = PyMapping_GetItemString(mod, "TimeFromPy"); |     Py_CLEAR(call); | ||||||
|     microprotocols_add(PyDateTimeAPI->TimeType, NULL, call); | 
 | ||||||
|     call = PyMapping_GetItemString(mod, "TimestampFromPy"); |     if (!(call = PyMapping_GetItemString(mod, "TimeFromPy"))) { goto exit; } | ||||||
|     microprotocols_add(PyDateTimeAPI->DateTimeType, NULL, call); |     if (0 != microprotocols_add(PyDateTimeAPI->TimeType, NULL, call)) { goto exit; } | ||||||
|     call = PyMapping_GetItemString(mod, "IntervalFromPy"); |     Py_CLEAR(call); | ||||||
|     microprotocols_add(PyDateTimeAPI->DeltaType, NULL, call); | 
 | ||||||
|  |     if (!(call = PyMapping_GetItemString(mod, "TimestampFromPy"))) { goto exit; } | ||||||
|  |     if (0 != microprotocols_add(PyDateTimeAPI->DateTimeType, NULL, call)) { goto exit; } | ||||||
|  |     Py_CLEAR(call); | ||||||
|  | 
 | ||||||
|  |     if (!(call = PyMapping_GetItemString(mod, "IntervalFromPy"))) { goto exit; } | ||||||
|  |     if (0 != microprotocols_add(PyDateTimeAPI->DeltaType, NULL, call)) { goto exit; } | ||||||
|  |     Py_CLEAR(call); | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_MXDATETIME | #ifdef HAVE_MXDATETIME | ||||||
|     /* as above, we use the callable objects from the psycopg module */ |     /* as above, we use the callable objects from the psycopg module */ | ||||||
|     if (NULL != (call = PyMapping_GetItemString(mod, "TimestampFromMx"))) { |     if (NULL != (call = PyMapping_GetItemString(mod, "TimestampFromMx"))) { | ||||||
|         microprotocols_add(mxDateTime.DateTime_Type, NULL, call); |         if (0 != microprotocols_add(mxDateTime.DateTime_Type, NULL, call)) { goto exit; } | ||||||
|  |         Py_CLEAR(call); | ||||||
| 
 | 
 | ||||||
|         /* if we found the above, we have this too. */ |         /* if we found the above, we have this too. */ | ||||||
|         call = PyMapping_GetItemString(mod, "TimeFromMx"); |         if (!(call = PyMapping_GetItemString(mod, "TimeFromMx"))) { goto exit; } | ||||||
|         microprotocols_add(mxDateTime.DateTimeDelta_Type, NULL, call); |         if (0 != microprotocols_add(mxDateTime.DateTimeDelta_Type, NULL, call)) { goto exit; } | ||||||
|  |         Py_CLEAR(call); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         PyErr_Clear(); |         PyErr_Clear(); | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  |     /* Success! */ | ||||||
|  |     rv = 0; | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  |     Py_XDECREF(call); | ||||||
|  | 
 | ||||||
|  |     return rv; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* psyco_encodings_fill
 | /* psyco_encodings_fill
 | ||||||
|  | @ -326,15 +366,27 @@ static encodingPair encodings[] = { | ||||||
|     {NULL, NULL} |     {NULL, NULL} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void psyco_encodings_fill(PyObject *dict) | /* Initialize the encodings table.
 | ||||||
|  |  * | ||||||
|  |  * Return 0 on success, else -1 and set an exception. | ||||||
|  |  */ | ||||||
|  | static int psyco_encodings_fill(PyObject *dict) | ||||||
| { | { | ||||||
|  |     PyObject *value = NULL; | ||||||
|     encodingPair *enc; |     encodingPair *enc; | ||||||
|  |     int rv = -1; | ||||||
| 
 | 
 | ||||||
|     for (enc = encodings; enc->pgenc != NULL; enc++) { |     for (enc = encodings; enc->pgenc != NULL; enc++) { | ||||||
|         PyObject *value = Text_FromUTF8(enc->pyenc); |         if (!(value = Text_FromUTF8(enc->pyenc))) { goto exit; } | ||||||
|         PyDict_SetItemString(dict, enc->pgenc, value); |         if (0 != PyDict_SetItemString(dict, enc->pgenc, value)) { goto exit; } | ||||||
|         Py_DECREF(value); |         Py_CLEAR(value); | ||||||
|     } |     } | ||||||
|  |     rv = 0; | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  |     Py_XDECREF(value); | ||||||
|  | 
 | ||||||
|  |     return rv; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* psyco_errors_init, psyco_errors_fill (callable from C)
 | /* psyco_errors_init, psyco_errors_fill (callable from C)
 | ||||||
|  | @ -380,7 +432,59 @@ static struct { | ||||||
|     {NULL}  /* Sentinel */ |     {NULL}  /* Sentinel */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void | 
 | ||||||
|  | /* Error.__reduce_ex__
 | ||||||
|  |  * | ||||||
|  |  * The method is required to make exceptions picklable: set the cursor | ||||||
|  |  * attribute to None. Only working from Py 2.5: previous versions | ||||||
|  |  * would require implementing __getstate__, and as of 2012 it's a little | ||||||
|  |  * bit too late to care. */ | ||||||
|  | static PyObject * | ||||||
|  | psyco_error_reduce_ex(PyObject *self, PyObject *args) | ||||||
|  | { | ||||||
|  |     PyObject *proto = NULL; | ||||||
|  |     PyObject *super = NULL; | ||||||
|  |     PyObject *tuple = NULL; | ||||||
|  |     PyObject *dict = NULL; | ||||||
|  |     PyObject *rv = NULL; | ||||||
|  | 
 | ||||||
|  |     /* tuple = Exception.__reduce_ex__(self, proto) */ | ||||||
|  |     if (!PyArg_ParseTuple(args, "O", &proto)) { | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  |     if (!(super = PyObject_GetAttrString(PyExc_Exception, "__reduce_ex__"))) { | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  |     if (!(tuple = PyObject_CallFunctionObjArgs(super, self, proto, NULL))) { | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* tuple[2]['cursor'] = None
 | ||||||
|  |      * | ||||||
|  |      * If these checks fail, we can still return a valid object. Pickle | ||||||
|  |      * will likely fail downstream, but there's nothing else we can do here */ | ||||||
|  |     if (!PyTuple_Check(tuple)) { goto exit; } | ||||||
|  |     if (3 > PyTuple_GET_SIZE(tuple)) { goto exit; } | ||||||
|  |     dict = PyTuple_GET_ITEM(tuple, 2);      /* borrowed */ | ||||||
|  |     if (!PyDict_Check(dict)) { goto exit; } | ||||||
|  | 
 | ||||||
|  |     /* Modify the tuple inplace and return it */ | ||||||
|  |     if (0 != PyDict_SetItemString(dict, "cursor", Py_None)) { | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  |     rv = tuple; | ||||||
|  |     tuple = NULL; | ||||||
|  | 
 | ||||||
|  | error: | ||||||
|  |     Py_XDECREF(tuple); | ||||||
|  |     Py_XDECREF(super); | ||||||
|  | 
 | ||||||
|  |     return rv; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int | ||||||
| psyco_errors_init(void) | psyco_errors_init(void) | ||||||
| { | { | ||||||
|     /* the names of the exceptions here reflect the oranization of the
 |     /* the names of the exceptions here reflect the oranization of the
 | ||||||
|  | @ -388,16 +492,22 @@ psyco_errors_init(void) | ||||||
|        live in _psycopg */ |        live in _psycopg */ | ||||||
| 
 | 
 | ||||||
|     int i; |     int i; | ||||||
|     PyObject *dict; |     PyObject *dict = NULL; | ||||||
|     PyObject *base; |     PyObject *base; | ||||||
|     PyObject *str; |     PyObject *str = NULL; | ||||||
|  |     PyObject *descr = NULL; | ||||||
|  |     int rv = -1; | ||||||
|  | 
 | ||||||
|  |     static PyMethodDef psyco_error_reduce_ex_def = | ||||||
|  |         {"__reduce_ex__", psyco_error_reduce_ex, METH_VARARGS, "pickle helper"}; | ||||||
| 
 | 
 | ||||||
|     for (i=0; exctable[i].name; i++) { |     for (i=0; exctable[i].name; i++) { | ||||||
|         dict = PyDict_New(); |         if (!(dict = PyDict_New())) { goto exit; } | ||||||
| 
 | 
 | ||||||
|         if (exctable[i].docstr) { |         if (exctable[i].docstr) { | ||||||
|             str = Text_FromUTF8(exctable[i].docstr); |             if (!(str = Text_FromUTF8(exctable[i].docstr))) { goto exit; } | ||||||
|             PyDict_SetItemString(dict, "__doc__", str); |             if (0 != PyDict_SetItemString(dict, "__doc__", str)) { goto exit; } | ||||||
|  |             Py_CLEAR(str); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (exctable[i].base == 0) { |         if (exctable[i].base == 0) { | ||||||
|  | @ -411,7 +521,11 @@ psyco_errors_init(void) | ||||||
|         else |         else | ||||||
|             base = *exctable[i].base; |             base = *exctable[i].base; | ||||||
| 
 | 
 | ||||||
|         *exctable[i].exc = PyErr_NewException(exctable[i].name, base, dict); |         if (!(*exctable[i].exc = PyErr_NewException( | ||||||
|  |                 exctable[i].name, base, dict))) { | ||||||
|  |             goto exit; | ||||||
|  |         } | ||||||
|  |         Py_CLEAR(dict); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Make pgerror, pgcode and cursor default to None on psycopg
 |     /* Make pgerror, pgcode and cursor default to None on psycopg
 | ||||||
|  | @ -420,53 +534,71 @@ psyco_errors_init(void) | ||||||
|     PyObject_SetAttrString(Error, "pgerror", Py_None); |     PyObject_SetAttrString(Error, "pgerror", Py_None); | ||||||
|     PyObject_SetAttrString(Error, "pgcode", Py_None); |     PyObject_SetAttrString(Error, "pgcode", Py_None); | ||||||
|     PyObject_SetAttrString(Error, "cursor", Py_None); |     PyObject_SetAttrString(Error, "cursor", Py_None); | ||||||
|  | 
 | ||||||
|  |     /* install __reduce_ex__ on Error to make all the subclasses picklable.
 | ||||||
|  |      * | ||||||
|  |      * Don't install it on Py 2.4: it is not used by the pickle | ||||||
|  |      * protocol, and if called manually fails in an unsettling way, | ||||||
|  |      * probably because the exceptions were old-style classes. */ | ||||||
|  | #if PY_VERSION_HEX >= 0x02050000 | ||||||
|  |     if (!(descr = PyDescr_NewMethod((PyTypeObject *)Error, | ||||||
|  |             &psyco_error_reduce_ex_def))) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
|  |     if (0 != PyObject_SetAttrString(Error, | ||||||
|  |             psyco_error_reduce_ex_def.ml_name, descr)) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     rv = 0; | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  |     Py_XDECREF(descr); | ||||||
|  |     Py_XDECREF(str); | ||||||
|  |     Py_XDECREF(dict); | ||||||
|  |     return rv; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| psyco_errors_fill(PyObject *dict) | psyco_errors_fill(PyObject *dict) | ||||||
| { | { | ||||||
|     PyDict_SetItemString(dict, "Error", Error); |     int i; | ||||||
|     PyDict_SetItemString(dict, "Warning", Warning); |     char *name; | ||||||
|     PyDict_SetItemString(dict, "InterfaceError", InterfaceError); | 
 | ||||||
|     PyDict_SetItemString(dict, "DatabaseError", DatabaseError); |     for (i = 0; exctable[i].name; i++) { | ||||||
|     PyDict_SetItemString(dict, "InternalError", InternalError); |         if (NULL == exctable[i].exc) { continue; } | ||||||
|     PyDict_SetItemString(dict, "OperationalError", OperationalError); | 
 | ||||||
|     PyDict_SetItemString(dict, "ProgrammingError", ProgrammingError); |         /* the name is the part after the last dot */ | ||||||
|     PyDict_SetItemString(dict, "IntegrityError", IntegrityError); |         name = strrchr(exctable[i].name, '.'); | ||||||
|     PyDict_SetItemString(dict, "DataError", DataError); |         name = name ? name + 1 : exctable[i].name; | ||||||
|     PyDict_SetItemString(dict, "NotSupportedError", NotSupportedError); | 
 | ||||||
| #ifdef PSYCOPG_EXTENSIONS |         PyDict_SetItemString(dict, name, *exctable[i].exc); | ||||||
|     PyDict_SetItemString(dict, "QueryCanceledError", QueryCanceledError); |     } | ||||||
|     PyDict_SetItemString(dict, "TransactionRollbackError", |  | ||||||
|                          TransactionRollbackError); |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| psyco_errors_set(PyObject *type) | psyco_errors_set(PyObject *type) | ||||||
| { | { | ||||||
|     PyObject_SetAttrString(type, "Error", Error); |     int i; | ||||||
|     PyObject_SetAttrString(type, "Warning", Warning); |     char *name; | ||||||
|     PyObject_SetAttrString(type, "InterfaceError", InterfaceError); | 
 | ||||||
|     PyObject_SetAttrString(type, "DatabaseError", DatabaseError); |     for (i = 0; exctable[i].name; i++) { | ||||||
|     PyObject_SetAttrString(type, "InternalError", InternalError); |         if (NULL == exctable[i].exc) { continue; } | ||||||
|     PyObject_SetAttrString(type, "OperationalError", OperationalError); | 
 | ||||||
|     PyObject_SetAttrString(type, "ProgrammingError", ProgrammingError); |         /* the name is the part after the last dot */ | ||||||
|     PyObject_SetAttrString(type, "IntegrityError", IntegrityError); |         name = strrchr(exctable[i].name, '.'); | ||||||
|     PyObject_SetAttrString(type, "DataError", DataError); |         name = name ? name + 1 : exctable[i].name; | ||||||
|     PyObject_SetAttrString(type, "NotSupportedError", NotSupportedError); | 
 | ||||||
| #ifdef PSYCOPG_EXTENSIONS |         PyObject_SetAttrString(type, name, *exctable[i].exc); | ||||||
|     PyObject_SetAttrString(type, "QueryCanceledError", QueryCanceledError); |     } | ||||||
|     PyObject_SetAttrString(type, "TransactionRollbackError", |  | ||||||
|                            TransactionRollbackError); |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* psyco_error_new
 | /* psyco_set_error
 | ||||||
| 
 | 
 | ||||||
|    Create a new error of the given type with extra attributes. */ |    Create a new error of the given type with extra attributes. */ | ||||||
| 
 | 
 | ||||||
| void | RAISES void | ||||||
| psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg, | psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg, | ||||||
|                 const char *pgerror, const char *pgcode) |                 const char *pgerror, const char *pgcode) | ||||||
| { | { | ||||||
|  | @ -495,16 +627,18 @@ psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg, | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (pgerror) { |         if (pgerror) { | ||||||
|             t = conn_text_from_chars(conn, pgerror); |             if ((t = conn_text_from_chars(conn, pgerror))) { | ||||||
|                 PyObject_SetAttrString(err, "pgerror", t); |                 PyObject_SetAttrString(err, "pgerror", t); | ||||||
|                 Py_DECREF(t); |                 Py_DECREF(t); | ||||||
|             } |             } | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         if (pgcode) { |         if (pgcode) { | ||||||
|             t = conn_text_from_chars(conn, pgcode); |             if ((t = conn_text_from_chars(conn, pgcode))) { | ||||||
|                 PyObject_SetAttrString(err, "pgcode", t); |                 PyObject_SetAttrString(err, "pgcode", t); | ||||||
|                 Py_DECREF(t); |                 Py_DECREF(t); | ||||||
|             } |             } | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         PyErr_SetObject(exc, err); |         PyErr_SetObject(exc, err); | ||||||
|         Py_DECREF(err); |         Py_DECREF(err); | ||||||
|  | @ -570,7 +704,7 @@ psyco_GetDecimalType(void) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Store the object from future uses. */ |     /* Store the object from future uses. */ | ||||||
|     if (can_cache && !cachedType) { |     if (can_cache && !cachedType && decimalType) { | ||||||
|         Py_INCREF(decimalType); |         Py_INCREF(decimalType); | ||||||
|         cachedType = decimalType; |         cachedType = decimalType; | ||||||
|     } |     } | ||||||
|  | @ -594,15 +728,11 @@ psyco_make_description_type(void) | ||||||
|     /* Try to import collections.namedtuple */ |     /* Try to import collections.namedtuple */ | ||||||
|     if (!(coll = PyImport_ImportModule("collections"))) { |     if (!(coll = PyImport_ImportModule("collections"))) { | ||||||
|         Dprintf("psyco_make_description_type: collections import failed"); |         Dprintf("psyco_make_description_type: collections import failed"); | ||||||
|         PyErr_Clear(); |         goto error; | ||||||
|         rv = Py_None; |  | ||||||
|         goto exit; |  | ||||||
|     } |     } | ||||||
|     if (!(nt = PyObject_GetAttrString(coll, "namedtuple"))) { |     if (!(nt = PyObject_GetAttrString(coll, "namedtuple"))) { | ||||||
|         Dprintf("psyco_make_description_type: no collections.namedtuple"); |         Dprintf("psyco_make_description_type: no collections.namedtuple"); | ||||||
|         PyErr_Clear(); |         goto error; | ||||||
|         rv = Py_None; |  | ||||||
|         goto exit; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Build the namedtuple */ |     /* Build the namedtuple */ | ||||||
|  | @ -614,6 +744,13 @@ exit: | ||||||
|     Py_XDECREF(nt); |     Py_XDECREF(nt); | ||||||
| 
 | 
 | ||||||
|     return rv; |     return rv; | ||||||
|  | 
 | ||||||
|  | error: | ||||||
|  |     /* controlled error: we will fall back to regular tuples. Return None. */ | ||||||
|  |     PyErr_Clear(); | ||||||
|  |     rv = Py_None; | ||||||
|  |     Py_INCREF(rv); | ||||||
|  |     goto exit; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -826,10 +963,10 @@ INIT_MODULE(_psycopg)(void) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     /* other mixed initializations of module-level variables */ |     /* other mixed initializations of module-level variables */ | ||||||
|     psycoEncodings = PyDict_New(); |     if (!(psycoEncodings = PyDict_New())) { goto exit; } | ||||||
|     psyco_encodings_fill(psycoEncodings); |     if (0 != psyco_encodings_fill(psycoEncodings)) { goto exit; } | ||||||
|     psyco_null = Bytes_FromString("NULL"); |     psyco_null = Bytes_FromString("NULL"); | ||||||
|     psyco_DescriptionType = psyco_make_description_type(); |     if (!(psyco_DescriptionType = psyco_make_description_type())) { goto exit; } | ||||||
| 
 | 
 | ||||||
|     /* set some module's parameters */ |     /* set some module's parameters */ | ||||||
|     PyModule_AddStringConstant(module, "__version__", PSYCOPG_VERSION); |     PyModule_AddStringConstant(module, "__version__", PSYCOPG_VERSION); | ||||||
|  | @ -862,14 +999,14 @@ INIT_MODULE(_psycopg)(void) | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
|     /* initialize default set of typecasters */ |     /* initialize default set of typecasters */ | ||||||
|     typecast_init(dict); |     if (0 != typecast_init(dict)) { goto exit; } | ||||||
| 
 | 
 | ||||||
|     /* initialize microprotocols layer */ |     /* initialize microprotocols layer */ | ||||||
|     microprotocols_init(dict); |     microprotocols_init(dict); | ||||||
|     psyco_adapters_init(dict); |     if (0 != psyco_adapters_init(dict)) { goto exit; } | ||||||
| 
 | 
 | ||||||
|     /* create a standard set of exceptions and add them to the module's dict */ |     /* create a standard set of exceptions and add them to the module's dict */ | ||||||
|     psyco_errors_init(); |     if (0 != psyco_errors_init()) { goto exit; } | ||||||
|     psyco_errors_fill(dict); |     psyco_errors_fill(dict); | ||||||
| 
 | 
 | ||||||
|     /* Solve win32 build issue about non-constant initializer element */ |     /* Solve win32 build issue about non-constant initializer element */ | ||||||
|  |  | ||||||
|  | @ -250,34 +250,28 @@ PyObject *psyco_default_binary_cast; | ||||||
| 
 | 
 | ||||||
| /* typecast_init - initialize the dictionary and create default types */ | /* typecast_init - initialize the dictionary and create default types */ | ||||||
| 
 | 
 | ||||||
| int | RAISES_NEG int | ||||||
| typecast_init(PyObject *dict) | typecast_init(PyObject *dict) | ||||||
| { | { | ||||||
|     int i; |     int i; | ||||||
|  |     int rv = -1; | ||||||
|  |     typecastObject *t = NULL; | ||||||
| 
 | 
 | ||||||
|     /* create type dictionary and put it in module namespace */ |     /* create type dictionary and put it in module namespace */ | ||||||
|     psyco_types = PyDict_New(); |     if (!(psyco_types = PyDict_New())) { goto exit; } | ||||||
|     psyco_binary_types = PyDict_New(); |  | ||||||
| 
 |  | ||||||
|     if (!psyco_types || !psyco_binary_types) { |  | ||||||
|         Py_XDECREF(psyco_types); |  | ||||||
|         Py_XDECREF(psyco_binary_types); |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     PyDict_SetItemString(dict, "string_types", psyco_types); |     PyDict_SetItemString(dict, "string_types", psyco_types); | ||||||
|  | 
 | ||||||
|  |     if (!(psyco_binary_types = PyDict_New())) { goto exit; } | ||||||
|     PyDict_SetItemString(dict, "binary_types", psyco_binary_types); |     PyDict_SetItemString(dict, "binary_types", psyco_binary_types); | ||||||
| 
 | 
 | ||||||
|     /* insert the cast types into the 'types' dictionary and register them in
 |     /* insert the cast types into the 'types' dictionary and register them in
 | ||||||
|        the module dictionary */ |        the module dictionary */ | ||||||
|     for (i = 0; typecast_builtins[i].name != NULL; i++) { |     for (i = 0; typecast_builtins[i].name != NULL; i++) { | ||||||
|         typecastObject *t; |  | ||||||
| 
 |  | ||||||
|         Dprintf("typecast_init: initializing %s", typecast_builtins[i].name); |         Dprintf("typecast_init: initializing %s", typecast_builtins[i].name); | ||||||
| 
 | 
 | ||||||
|         t = (typecastObject *)typecast_from_c(&(typecast_builtins[i]), dict); |         t = (typecastObject *)typecast_from_c(&(typecast_builtins[i]), dict); | ||||||
|         if (t == NULL) return -1; |         if (t == NULL) { goto exit; } | ||||||
|         if (typecast_add((PyObject *)t, NULL, 0) != 0) return -1; |         if (typecast_add((PyObject *)t, NULL, 0) < 0) { goto exit; } | ||||||
| 
 | 
 | ||||||
|         PyDict_SetItem(dict, t->name, (PyObject *)t); |         PyDict_SetItem(dict, t->name, (PyObject *)t); | ||||||
| 
 | 
 | ||||||
|  | @ -285,6 +279,8 @@ typecast_init(PyObject *dict) | ||||||
|         if (typecast_builtins[i].values == typecast_BINARY_types) { |         if (typecast_builtins[i].values == typecast_BINARY_types) { | ||||||
|             psyco_default_binary_cast = (PyObject *)t; |             psyco_default_binary_cast = (PyObject *)t; | ||||||
|         } |         } | ||||||
|  |         Py_DECREF((PyObject *)t); | ||||||
|  |         t = NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* create and save a default cast object (but does not register it) */ |     /* create and save a default cast object (but does not register it) */ | ||||||
|  | @ -294,29 +290,35 @@ typecast_init(PyObject *dict) | ||||||
| #ifdef HAVE_MXDATETIME | #ifdef HAVE_MXDATETIME | ||||||
|     if (0 == psyco_typecast_mxdatetime_init()) { |     if (0 == psyco_typecast_mxdatetime_init()) { | ||||||
|         for (i = 0; typecast_mxdatetime[i].name != NULL; i++) { |         for (i = 0; typecast_mxdatetime[i].name != NULL; i++) { | ||||||
|             typecastObject *t; |  | ||||||
|             Dprintf("typecast_init: initializing %s", typecast_mxdatetime[i].name); |             Dprintf("typecast_init: initializing %s", typecast_mxdatetime[i].name); | ||||||
|             t = (typecastObject *)typecast_from_c(&(typecast_mxdatetime[i]), dict); |             t = (typecastObject *)typecast_from_c(&(typecast_mxdatetime[i]), dict); | ||||||
|             if (t == NULL) return -1; |             if (t == NULL) { goto exit; } | ||||||
|             PyDict_SetItem(dict, t->name, (PyObject *)t); |             PyDict_SetItem(dict, t->name, (PyObject *)t); | ||||||
|  |             Py_DECREF((PyObject *)t); | ||||||
|  |             t = NULL; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     if (psyco_typecast_datetime_init()) { return -1; } |     if (0 > psyco_typecast_datetime_init()) { goto exit; } | ||||||
|     for (i = 0; typecast_pydatetime[i].name != NULL; i++) { |     for (i = 0; typecast_pydatetime[i].name != NULL; i++) { | ||||||
|         typecastObject *t; |  | ||||||
|         Dprintf("typecast_init: initializing %s", typecast_pydatetime[i].name); |         Dprintf("typecast_init: initializing %s", typecast_pydatetime[i].name); | ||||||
|         t = (typecastObject *)typecast_from_c(&(typecast_pydatetime[i]), dict); |         t = (typecastObject *)typecast_from_c(&(typecast_pydatetime[i]), dict); | ||||||
|         if (t == NULL) return -1; |         if (t == NULL) { goto exit; } | ||||||
|         PyDict_SetItem(dict, t->name, (PyObject *)t); |         PyDict_SetItem(dict, t->name, (PyObject *)t); | ||||||
|  |         Py_DECREF((PyObject *)t); | ||||||
|  |         t = NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return 0; |     rv = 0; | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  |     Py_XDECREF((PyObject *)t); | ||||||
|  |     return rv; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* typecast_add - add a type object to the dictionary */ | /* typecast_add - add a type object to the dictionary */ | ||||||
| int | RAISES_NEG int | ||||||
| typecast_add(PyObject *obj, PyObject *dict, int binary) | typecast_add(PyObject *obj, PyObject *dict, int binary) | ||||||
| { | { | ||||||
|     PyObject *val; |     PyObject *val; | ||||||
|  | @ -466,7 +468,7 @@ typecast_repr(PyObject *self) | ||||||
| static PyObject * | static PyObject * | ||||||
| typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs) | typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs) | ||||||
| { | { | ||||||
|     char *string; |     const char *string; | ||||||
|     Py_ssize_t length; |     Py_ssize_t length; | ||||||
|     PyObject *cursor; |     PyObject *cursor; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -71,8 +71,8 @@ extern HIDDEN PyObject *psyco_default_binary_cast; | ||||||
| /** exported functions **/ | /** exported functions **/ | ||||||
| 
 | 
 | ||||||
| /* used by module.c to init the type system and register types */ | /* used by module.c to init the type system and register types */ | ||||||
| HIDDEN int typecast_init(PyObject *dict); | RAISES_NEG HIDDEN int typecast_init(PyObject *dict); | ||||||
| HIDDEN int typecast_add(PyObject *obj, PyObject *dict, int binary); | RAISES_NEG HIDDEN int typecast_add(PyObject *obj, PyObject *dict, int binary); | ||||||
| 
 | 
 | ||||||
| /* the C callable typecastObject creator function */ | /* the C callable typecastObject creator function */ | ||||||
| HIDDEN PyObject *typecast_from_c(typecastObject_initlist *type, PyObject *d); | HIDDEN PyObject *typecast_from_c(typecastObject_initlist *type, PyObject *d); | ||||||
|  |  | ||||||
|  | @ -166,7 +166,7 @@ typecast_array_tokenize(const char *str, Py_ssize_t strlength, | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | RAISES_NEG static int | ||||||
| typecast_array_scan(const char *str, Py_ssize_t strlength, | typecast_array_scan(const char *str, Py_ssize_t strlength, | ||||||
|                     PyObject *curs, PyObject *base, PyObject *array) |                     PyObject *curs, PyObject *base, PyObject *array) | ||||||
| { | { | ||||||
|  | @ -199,7 +199,7 @@ typecast_array_scan(const char *str, Py_ssize_t strlength, | ||||||
| 
 | 
 | ||||||
|             /* before anything else we free the memory */ |             /* before anything else we free the memory */ | ||||||
|             if (state == ASCAN_QUOTED) PyMem_Free(token); |             if (state == ASCAN_QUOTED) PyMem_Free(token); | ||||||
|             if (obj == NULL) return 0; |             if (obj == NULL) return -1; | ||||||
| 
 | 
 | ||||||
|             PyList_Append(array, obj); |             PyList_Append(array, obj); | ||||||
|             Py_DECREF(obj); |             Py_DECREF(obj); | ||||||
|  | @ -207,25 +207,25 @@ typecast_array_scan(const char *str, Py_ssize_t strlength, | ||||||
| 
 | 
 | ||||||
|         else if (state == ASCAN_BEGIN) { |         else if (state == ASCAN_BEGIN) { | ||||||
|             PyObject *sub = PyList_New(0); |             PyObject *sub = PyList_New(0); | ||||||
|             if (sub == NULL) return 0; |             if (sub == NULL) return -1; | ||||||
| 
 | 
 | ||||||
|             PyList_Append(array, sub); |             PyList_Append(array, sub); | ||||||
|             Py_DECREF(sub); |             Py_DECREF(sub); | ||||||
| 
 | 
 | ||||||
|             if (stack_index == MAX_DIMENSIONS) |             if (stack_index == MAX_DIMENSIONS) | ||||||
|                 return 0; |                 return -1; | ||||||
| 
 | 
 | ||||||
|             stack[stack_index++] = array; |             stack[stack_index++] = array; | ||||||
|             array = sub; |             array = sub; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         else if (state == ASCAN_ERROR) { |         else if (state == ASCAN_ERROR) { | ||||||
|             return 0; |             return -1; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         else if (state == ASCAN_END) { |         else if (state == ASCAN_END) { | ||||||
|             if (--stack_index < 0) |             if (--stack_index < 0) | ||||||
|                 return 0; |                 return -1; | ||||||
|             array = stack[stack_index]; |             array = stack[stack_index]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -233,7 +233,7 @@ typecast_array_scan(const char *str, Py_ssize_t strlength, | ||||||
|             break; |             break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return 1; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -260,12 +260,11 @@ typecast_GENERIC_ARRAY_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
|     Dprintf("typecast_GENERIC_ARRAY_cast: str = '%s'," |     Dprintf("typecast_GENERIC_ARRAY_cast: str = '%s'," | ||||||
|             " len = " FORMAT_CODE_PY_SSIZE_T, str, len); |             " len = " FORMAT_CODE_PY_SSIZE_T, str, len); | ||||||
| 
 | 
 | ||||||
|     obj = PyList_New(0); |     if (!(obj = PyList_New(0))) { return NULL; } | ||||||
| 
 | 
 | ||||||
|     /* scan the array skipping the first level of {} */ |     /* scan the array skipping the first level of {} */ | ||||||
|     if (typecast_array_scan(&str[1], len-2, curs, base, obj) == 0) { |     if (typecast_array_scan(&str[1], len-2, curs, base, obj) < 0) { | ||||||
|         Py_DECREF(obj); |         Py_CLEAR(obj); | ||||||
|         obj = NULL; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return obj; |     return obj; | ||||||
|  |  | ||||||
|  | @ -65,7 +65,7 @@ typecast_FLOAT_cast(const char *s, Py_ssize_t len, PyObject *curs) | ||||||
|     PyObject *str = NULL, *flo = NULL; |     PyObject *str = NULL, *flo = NULL; | ||||||
| 
 | 
 | ||||||
|     if (s == NULL) {Py_INCREF(Py_None); return Py_None;} |     if (s == NULL) {Py_INCREF(Py_None); return Py_None;} | ||||||
|     str = Text_FromUTF8AndSize(s, len); |     if (!(str = Text_FromUTF8AndSize(s, len))) { return NULL; } | ||||||
| #if PY_MAJOR_VERSION < 3 | #if PY_MAJOR_VERSION < 3 | ||||||
|     flo = PyFloat_FromString(str, NULL); |     flo = PyFloat_FromString(str, NULL); | ||||||
| #else | #else | ||||||
|  |  | ||||||
|  | @ -208,7 +208,7 @@ static const char hex_lut[128] = { | ||||||
| /* Parse a bytea output buffer encoded in 'hex' format.
 | /* Parse a bytea output buffer encoded in 'hex' format.
 | ||||||
|  * |  * | ||||||
|  * the format is described in |  * the format is described in | ||||||
|  * http://www.postgresql.org/docs/9.0/static/datatype-binary.html
 |  * http://www.postgresql.org/docs/current/static/datatype-binary.html
 | ||||||
|  * |  * | ||||||
|  * Parse the buffer in 'bufin', whose length is 'sizein'. |  * Parse the buffer in 'bufin', whose length is 'sizein'. | ||||||
|  * Return a new buffer allocated by PyMem_Malloc and set 'sizeout' to its size. |  * Return a new buffer allocated by PyMem_Malloc and set 'sizeout' to its size. | ||||||
|  | @ -258,7 +258,7 @@ exit: | ||||||
| /* Parse a bytea output buffer encoded in 'escape' format.
 | /* Parse a bytea output buffer encoded in 'escape' format.
 | ||||||
|  * |  * | ||||||
|  * the format is described in |  * the format is described in | ||||||
|  * http://www.postgresql.org/docs/9.0/static/datatype-binary.html
 |  * http://www.postgresql.org/docs/current/static/datatype-binary.html
 | ||||||
|  * |  * | ||||||
|  * Parse the buffer in 'bufin', whose length is 'sizein'. |  * Parse the buffer in 'bufin', whose length is 'sizein'. | ||||||
|  * Return a new buffer allocated by PyMem_Malloc and set 'sizeout' to its size. |  * Return a new buffer allocated by PyMem_Malloc and set 'sizeout' to its size. | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ | ||||||
| #include <math.h> | #include <math.h> | ||||||
| #include "datetime.h" | #include "datetime.h" | ||||||
| 
 | 
 | ||||||
| static int | RAISES_NEG static int | ||||||
| psyco_typecast_datetime_init(void) | psyco_typecast_datetime_init(void) | ||||||
| { | { | ||||||
|     Dprintf("psyco_typecast_datetime_init: datetime init"); |     Dprintf("psyco_typecast_datetime_init: datetime init"); | ||||||
|  | @ -239,7 +239,7 @@ typecast_PYINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
| 
 | 
 | ||||||
|         case '0': case '1': case '2': case '3': case '4': |         case '0': case '1': case '2': case '3': case '4': | ||||||
|         case '5': case '6': case '7': case '8': case '9': |         case '5': case '6': case '7': case '8': case '9': | ||||||
|             v = v*10 + (double)*str - (double)'0'; |             v = v * 10.0 + (double)(*str - '0'); | ||||||
|             if (part == 6){ |             if (part == 6){ | ||||||
|                 denominator *= 10; |                 denominator *= 10; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -142,7 +142,7 @@ typecast_MXINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
| 
 | 
 | ||||||
|         case '0': case '1': case '2': case '3': case '4': |         case '0': case '1': case '2': case '3': case '4': | ||||||
|         case '5': case '6': case '7': case '8': case '9': |         case '5': case '6': case '7': case '8': case '9': | ||||||
|             v = v*10 + (double)*str - (double)'0'; |             v = v * 10.0 + (double)(*str - '0'); | ||||||
|             Dprintf("typecast_MXINTERVAL_cast: v = %f", v); |             Dprintf("typecast_MXINTERVAL_cast: v = %f", v); | ||||||
|             if (part == 6){ |             if (part == 6){ | ||||||
|                 denominator *= 10; |                 denominator *= 10; | ||||||
|  |  | ||||||
|  | @ -113,20 +113,19 @@ psycopg_escape_identifier_easy(const char *from, Py_ssize_t len) | ||||||
|  * Allocate a new buffer on the Python heap containing the new string. |  * Allocate a new buffer on the Python heap containing the new string. | ||||||
|  * 'len' is optional: if 0 the length is calculated. |  * 'len' is optional: if 0 the length is calculated. | ||||||
|  * |  * | ||||||
|  * Return NULL and set an exception in case of error. |  * Store the return in 'to' and return 0 in case of success, else return -1 | ||||||
|  |  * and raise an exception. | ||||||
|  */ |  */ | ||||||
| char * | RAISES_NEG int | ||||||
| psycopg_strdup(const char *from, Py_ssize_t len) | psycopg_strdup(char **to, const char *from, Py_ssize_t len) | ||||||
| { | { | ||||||
|     char *rv; |  | ||||||
| 
 |  | ||||||
|     if (!len) { len = strlen(from); } |     if (!len) { len = strlen(from); } | ||||||
|     if (!(rv = PyMem_Malloc(len + 1))) { |     if (!(*to = PyMem_Malloc(len + 1))) { | ||||||
|         PyErr_NoMemory(); |         PyErr_NoMemory(); | ||||||
|         return NULL; |         return -1; | ||||||
|     } |     } | ||||||
|     strcpy(rv, from); |     strcpy(*to, from); | ||||||
|     return rv; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Ensure a Python object is a bytes string.
 | /* Ensure a Python object is a bytes string.
 | ||||||
|  | @ -139,7 +138,7 @@ psycopg_strdup(const char *from, Py_ssize_t len) | ||||||
|  * |  * | ||||||
|  * It is safe to call the function on NULL. |  * It is safe to call the function on NULL. | ||||||
|  */ |  */ | ||||||
| PyObject * | STEALS(1) PyObject * | ||||||
| psycopg_ensure_bytes(PyObject *obj) | psycopg_ensure_bytes(PyObject *obj) | ||||||
| { | { | ||||||
|     PyObject *rv = NULL; |     PyObject *rv = NULL; | ||||||
|  | @ -169,7 +168,7 @@ psycopg_ensure_bytes(PyObject *obj) | ||||||
|  * The function is ref neutral: steals a ref from obj and adds one to the |  * The function is ref neutral: steals a ref from obj and adds one to the | ||||||
|  * return value.  It is safe to call it on NULL. |  * return value.  It is safe to call it on NULL. | ||||||
|  */ |  */ | ||||||
| PyObject * | STEALS(1) PyObject * | ||||||
| psycopg_ensure_text(PyObject *obj) | psycopg_ensure_text(PyObject *obj) | ||||||
| { | { | ||||||
| #if PY_MAJOR_VERSION < 3 | #if PY_MAJOR_VERSION < 3 | ||||||
|  |  | ||||||
|  | @ -78,7 +78,9 @@ static PyMemberDef xid_members[] = { | ||||||
| static PyObject * | static PyObject * | ||||||
| xid_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) | xid_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) | ||||||
| { | { | ||||||
|     XidObject *self = (XidObject *)type->tp_alloc(type, 0); |     XidObject *self; | ||||||
|  | 
 | ||||||
|  |     if (!(self = (XidObject *)type->tp_alloc(type, 0))) { return NULL; } | ||||||
| 
 | 
 | ||||||
|     Py_INCREF(Py_None); |     Py_INCREF(Py_None); | ||||||
|     self->format_id = Py_None; |     self->format_id = Py_None; | ||||||
|  | @ -486,7 +488,7 @@ exit: | ||||||
|  * |  * | ||||||
|  * Return a borrowed reference. */ |  * Return a borrowed reference. */ | ||||||
| 
 | 
 | ||||||
| static PyObject * | BORROWED static PyObject * | ||||||
| _xid_get_parse_regex(void) { | _xid_get_parse_regex(void) { | ||||||
|     static PyObject *rv; |     static PyObject *rv; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ define=PSYCOPG_EXTENSIONS,PSYCOPG_NEW_BOOLEAN,HAVE_PQFREEMEM | ||||||
| # PSYCOPG_DEBUG can be added to enable verbose debug information | # PSYCOPG_DEBUG can be added to enable verbose debug information | ||||||
| # PSYCOPG_NEW_BOOLEAN to format booleans as true/false vs 't'/'f' | # PSYCOPG_NEW_BOOLEAN to format booleans as true/false vs 't'/'f' | ||||||
| 
 | 
 | ||||||
| # Set to 1 to use Python datatime objects for default date/time representation. | # Set to 1 to use Python datetime objects for default date/time representation. | ||||||
| use_pydatetime=1 | use_pydatetime=1 | ||||||
| 
 | 
 | ||||||
| # If the build system does not find the mx.DateTime headers, try | # If the build system does not find the mx.DateTime headers, try | ||||||
|  |  | ||||||
|  | @ -380,7 +380,9 @@ class DatabaseAPI20Test(unittest.TestCase): | ||||||
|         self.assertRaises(self.driver.Error,con.commit) |         self.assertRaises(self.driver.Error,con.commit) | ||||||
| 
 | 
 | ||||||
|         # connection.close should raise an Error if called more than once |         # connection.close should raise an Error if called more than once | ||||||
|         self.assertRaises(self.driver.Error,con.close) |         # Issue discussed on DB-SIG: consensus seem that close() should not | ||||||
|  |         # raised if called on closed objects. Issue reported back to Stuart. | ||||||
|  |         # self.assertRaises(self.driver.Error,con.close) | ||||||
| 
 | 
 | ||||||
|     def test_execute(self): |     def test_execute(self): | ||||||
|         con = self._connect() |         con = self._connect() | ||||||
|  |  | ||||||
|  | @ -48,6 +48,12 @@ class ConnectionTests(unittest.TestCase): | ||||||
|         conn.close() |         conn.close() | ||||||
|         self.assertEqual(conn.closed, True) |         self.assertEqual(conn.closed, True) | ||||||
| 
 | 
 | ||||||
|  |     def test_close_idempotent(self): | ||||||
|  |         conn = self.conn | ||||||
|  |         conn.close() | ||||||
|  |         conn.close() | ||||||
|  |         self.assert_(conn.closed) | ||||||
|  | 
 | ||||||
|     def test_cursor_closed_attribute(self): |     def test_cursor_closed_attribute(self): | ||||||
|         conn = self.conn |         conn = self.conn | ||||||
|         curs = conn.cursor() |         curs = conn.cursor() | ||||||
|  | @ -166,6 +172,35 @@ class ConnectionTests(unittest.TestCase): | ||||||
|         gc.collect() |         gc.collect() | ||||||
|         self.assert_(w() is None) |         self.assert_(w() is None) | ||||||
| 
 | 
 | ||||||
|  |     def test_commit_concurrency(self): | ||||||
|  |         # The problem is the one reported in ticket #103. Because of bad | ||||||
|  |         # status check, we commit even when a commit is already on its way. | ||||||
|  |         # We can detect this condition by the warnings. | ||||||
|  |         conn = self.conn | ||||||
|  |         notices = [] | ||||||
|  |         stop = [] | ||||||
|  | 
 | ||||||
|  |         def committer(): | ||||||
|  |             while not stop: | ||||||
|  |                 conn.commit() | ||||||
|  |                 while conn.notices: | ||||||
|  |                     notices.append((2, conn.notices.pop())) | ||||||
|  | 
 | ||||||
|  |         cur = conn.cursor() | ||||||
|  |         t1 = threading.Thread(target=committer) | ||||||
|  |         t1.start() | ||||||
|  |         i = 1 | ||||||
|  |         for i in range(1000): | ||||||
|  |             cur.execute("select %s;",(i,)) | ||||||
|  |             conn.commit() | ||||||
|  |             while conn.notices: | ||||||
|  |                 notices.append((1, conn.notices.pop())) | ||||||
|  | 
 | ||||||
|  |         # Stop the committer thread | ||||||
|  |         stop.append(True) | ||||||
|  | 
 | ||||||
|  |         self.assert_(not notices, "%d notices raised" % len(notices)) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class IsolationLevelsTestCase(unittest.TestCase): | class IsolationLevelsTestCase(unittest.TestCase): | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -37,6 +37,12 @@ class CursorTests(unittest.TestCase): | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
|         self.conn.close() |         self.conn.close() | ||||||
| 
 | 
 | ||||||
|  |     def test_close_idempotent(self): | ||||||
|  |         cur = self.conn.cursor() | ||||||
|  |         cur.close() | ||||||
|  |         cur.close() | ||||||
|  |         self.assert_(cur.closed) | ||||||
|  | 
 | ||||||
|     def test_empty_query(self): |     def test_empty_query(self): | ||||||
|         cur = self.conn.cursor() |         cur = self.conn.cursor() | ||||||
|         self.assertRaises(psycopg2.ProgrammingError, cur.execute, "") |         self.assertRaises(psycopg2.ProgrammingError, cur.execute, "") | ||||||
|  | @ -234,6 +240,17 @@ class CursorTests(unittest.TestCase): | ||||||
|         # everything swallowed in two gulps |         # everything swallowed in two gulps | ||||||
|         self.assertEqual(rv, [(i,((i - 1) % 30) + 1) for i in range(1,51)]) |         self.assertEqual(rv, [(i,((i - 1) % 30) + 1) for i in range(1,51)]) | ||||||
| 
 | 
 | ||||||
|  |     @skip_before_postgres(8, 0) | ||||||
|  |     def test_iter_named_cursor_rownumber(self): | ||||||
|  |         curs = self.conn.cursor('tmp') | ||||||
|  |         # note: this fails if itersize < dataset: internally we check | ||||||
|  |         # rownumber == rowcount to detect when to read anoter page, so we | ||||||
|  |         # would need an extra attribute to have a monotonic rownumber. | ||||||
|  |         curs.itersize = 20 | ||||||
|  |         curs.execute('select generate_series(1,10)') | ||||||
|  |         for i, rec in enumerate(curs): | ||||||
|  |             self.assertEqual(i + 1, curs.rownumber) | ||||||
|  | 
 | ||||||
|     @skip_if_no_namedtuple |     @skip_if_no_namedtuple | ||||||
|     def test_namedtuple_description(self): |     def test_namedtuple_description(self): | ||||||
|         curs = self.conn.cursor() |         curs = self.conn.cursor() | ||||||
|  |  | ||||||
|  | @ -25,7 +25,7 @@ | ||||||
| import math | import math | ||||||
| import unittest | import unittest | ||||||
| import psycopg2 | import psycopg2 | ||||||
| from psycopg2.tz import FixedOffsetTimezone | from psycopg2.tz import FixedOffsetTimezone, ZERO | ||||||
| from testconfig import dsn | from testconfig import dsn | ||||||
| 
 | 
 | ||||||
| class CommonDatetimeTestsMixin: | class CommonDatetimeTestsMixin: | ||||||
|  | @ -78,7 +78,7 @@ class CommonDatetimeTestsMixin: | ||||||
|         value = self.DATETIME(None, self.curs) |         value = self.DATETIME(None, self.curs) | ||||||
|         self.assertEqual(value, None) |         self.assertEqual(value, None) | ||||||
| 
 | 
 | ||||||
|     def test_parse_incomplete_time(self): |     def test_parse_incomplete_datetime(self): | ||||||
|         self.assertRaises(psycopg2.DataError, |         self.assertRaises(psycopg2.DataError, | ||||||
|                           self.DATETIME, '2007', self.curs) |                           self.DATETIME, '2007', self.curs) | ||||||
|         self.assertRaises(psycopg2.DataError, |         self.assertRaises(psycopg2.DataError, | ||||||
|  | @ -513,6 +513,32 @@ class FromTicksTestCase(unittest.TestCase): | ||||||
|             time(0, 11, 59, 999920)) |             time(0, 11, 59, 999920)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class FixedOffsetTimezoneTests(unittest.TestCase): | ||||||
|  | 
 | ||||||
|  |     def test_init_with_no_args(self): | ||||||
|  |         tzinfo = FixedOffsetTimezone() | ||||||
|  |         self.assert_(tzinfo._offset is ZERO) | ||||||
|  |         self.assert_(tzinfo._name is None) | ||||||
|  | 
 | ||||||
|  |     def test_repr_with_positive_offset(self): | ||||||
|  |         tzinfo = FixedOffsetTimezone(5 * 60) | ||||||
|  |         self.assertEqual(repr(tzinfo), "psycopg2.tz.FixedOffsetTimezone(offset=300, name=None)") | ||||||
|  | 
 | ||||||
|  |     def test_repr_with_negative_offset(self): | ||||||
|  |         tzinfo = FixedOffsetTimezone(-5 * 60) | ||||||
|  |         self.assertEqual(repr(tzinfo), "psycopg2.tz.FixedOffsetTimezone(offset=-300, name=None)") | ||||||
|  | 
 | ||||||
|  |     def test_repr_with_name(self): | ||||||
|  |         tzinfo = FixedOffsetTimezone(name="FOO") | ||||||
|  |         self.assertEqual(repr(tzinfo), "psycopg2.tz.FixedOffsetTimezone(offset=0, name='FOO')") | ||||||
|  | 
 | ||||||
|  |     def test_instance_caching(self): | ||||||
|  |         self.assert_(FixedOffsetTimezone(name="FOO") is FixedOffsetTimezone(name="FOO")) | ||||||
|  |         self.assert_(FixedOffsetTimezone(7 * 60) is FixedOffsetTimezone(7 * 60)) | ||||||
|  |         self.assert_(FixedOffsetTimezone(-9 * 60, 'FOO') is FixedOffsetTimezone(-9 * 60, 'FOO')) | ||||||
|  |         self.assert_(FixedOffsetTimezone(9 * 60) is not FixedOffsetTimezone(9 * 60, 'FOO')) | ||||||
|  |         self.assert_(FixedOffsetTimezone(name='FOO') is not FixedOffsetTimezone(9 * 60, 'FOO')) | ||||||
|  | 
 | ||||||
| def test_suite(): | def test_suite(): | ||||||
|     return unittest.TestLoader().loadTestsFromName(__name__) |     return unittest.TestLoader().loadTestsFromName(__name__) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -35,6 +35,7 @@ class ExtrasDictCursorTests(unittest.TestCase): | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
|         self.conn.close() |         self.conn.close() | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     def testDictCursorWithPlainCursorFetchOne(self): |     def testDictCursorWithPlainCursorFetchOne(self): | ||||||
|         self._testWithPlainCursor(lambda curs: curs.fetchone()) |         self._testWithPlainCursor(lambda curs: curs.fetchone()) | ||||||
| 
 | 
 | ||||||
|  | @ -53,6 +54,26 @@ class ExtrasDictCursorTests(unittest.TestCase): | ||||||
|                 return row |                 return row | ||||||
|         self._testWithPlainCursor(getter) |         self._testWithPlainCursor(getter) | ||||||
| 
 | 
 | ||||||
|  |     def testUpdateRow(self): | ||||||
|  |         row = self._testWithPlainCursor(lambda curs: curs.fetchone()) | ||||||
|  |         row['foo'] = 'qux' | ||||||
|  |         self.failUnless(row['foo'] == 'qux') | ||||||
|  |         self.failUnless(row[0] == 'qux') | ||||||
|  | 
 | ||||||
|  |     @skip_before_postgres(8, 0) | ||||||
|  |     def testDictCursorWithPlainCursorIterRowNumber(self): | ||||||
|  |         curs = self.conn.cursor(cursor_factory=psycopg2.extras.DictCursor) | ||||||
|  |         self._testIterRowNumber(curs) | ||||||
|  | 
 | ||||||
|  |     def _testWithPlainCursor(self, getter): | ||||||
|  |         curs = self.conn.cursor(cursor_factory=psycopg2.extras.DictCursor) | ||||||
|  |         curs.execute("SELECT * FROM ExtrasDictCursorTests") | ||||||
|  |         row = getter(curs) | ||||||
|  |         self.failUnless(row['foo'] == 'bar') | ||||||
|  |         self.failUnless(row[0] == 'bar') | ||||||
|  |         return row | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     def testDictCursorWithPlainCursorRealFetchOne(self): |     def testDictCursorWithPlainCursorRealFetchOne(self): | ||||||
|         self._testWithPlainCursorReal(lambda curs: curs.fetchone()) |         self._testWithPlainCursorReal(lambda curs: curs.fetchone()) | ||||||
| 
 | 
 | ||||||
|  | @ -71,6 +92,17 @@ class ExtrasDictCursorTests(unittest.TestCase): | ||||||
|                 return row |                 return row | ||||||
|         self._testWithPlainCursorReal(getter) |         self._testWithPlainCursorReal(getter) | ||||||
| 
 | 
 | ||||||
|  |     @skip_before_postgres(8, 0) | ||||||
|  |     def testDictCursorWithPlainCursorRealIterRowNumber(self): | ||||||
|  |         curs = self.conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) | ||||||
|  |         self._testIterRowNumber(curs) | ||||||
|  | 
 | ||||||
|  |     def _testWithPlainCursorReal(self, getter): | ||||||
|  |         curs = self.conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) | ||||||
|  |         curs.execute("SELECT * FROM ExtrasDictCursorTests") | ||||||
|  |         row = getter(curs) | ||||||
|  |         self.failUnless(row['foo'] == 'bar') | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     def testDictCursorWithNamedCursorFetchOne(self): |     def testDictCursorWithNamedCursorFetchOne(self): | ||||||
|         self._testWithNamedCursor(lambda curs: curs.fetchone()) |         self._testWithNamedCursor(lambda curs: curs.fetchone()) | ||||||
|  | @ -95,6 +127,18 @@ class ExtrasDictCursorTests(unittest.TestCase): | ||||||
|         curs = self.conn.cursor('tmp', cursor_factory=psycopg2.extras.DictCursor) |         curs = self.conn.cursor('tmp', cursor_factory=psycopg2.extras.DictCursor) | ||||||
|         self._testNamedCursorNotGreedy(curs) |         self._testNamedCursorNotGreedy(curs) | ||||||
| 
 | 
 | ||||||
|  |     @skip_before_postgres(8, 0) | ||||||
|  |     def testDictCursorWithNamedCursorIterRowNumber(self): | ||||||
|  |         curs = self.conn.cursor('tmp', cursor_factory=psycopg2.extras.DictCursor) | ||||||
|  |         self._testIterRowNumber(curs) | ||||||
|  | 
 | ||||||
|  |     def _testWithNamedCursor(self, getter): | ||||||
|  |         curs = self.conn.cursor('aname', cursor_factory=psycopg2.extras.DictCursor) | ||||||
|  |         curs.execute("SELECT * FROM ExtrasDictCursorTests") | ||||||
|  |         row = getter(curs) | ||||||
|  |         self.failUnless(row['foo'] == 'bar') | ||||||
|  |         self.failUnless(row[0] == 'bar') | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     def testDictCursorRealWithNamedCursorFetchOne(self): |     def testDictCursorRealWithNamedCursorFetchOne(self): | ||||||
|         self._testWithNamedCursorReal(lambda curs: curs.fetchone()) |         self._testWithNamedCursorReal(lambda curs: curs.fetchone()) | ||||||
|  | @ -119,27 +163,10 @@ class ExtrasDictCursorTests(unittest.TestCase): | ||||||
|         curs = self.conn.cursor('tmp', cursor_factory=psycopg2.extras.RealDictCursor) |         curs = self.conn.cursor('tmp', cursor_factory=psycopg2.extras.RealDictCursor) | ||||||
|         self._testNamedCursorNotGreedy(curs) |         self._testNamedCursorNotGreedy(curs) | ||||||
| 
 | 
 | ||||||
| 
 |     @skip_before_postgres(8, 0) | ||||||
|     def _testWithPlainCursor(self, getter): |     def testDictCursorRealWithNamedCursorIterRowNumber(self): | ||||||
|         curs = self.conn.cursor(cursor_factory=psycopg2.extras.DictCursor) |         curs = self.conn.cursor('tmp', cursor_factory=psycopg2.extras.RealDictCursor) | ||||||
|         curs.execute("SELECT * FROM ExtrasDictCursorTests") |         self._testIterRowNumber(curs) | ||||||
|         row = getter(curs) |  | ||||||
|         self.failUnless(row['foo'] == 'bar') |  | ||||||
|         self.failUnless(row[0] == 'bar') |  | ||||||
|         return row |  | ||||||
| 
 |  | ||||||
|     def _testWithNamedCursor(self, getter): |  | ||||||
|         curs = self.conn.cursor('aname', cursor_factory=psycopg2.extras.DictCursor) |  | ||||||
|         curs.execute("SELECT * FROM ExtrasDictCursorTests") |  | ||||||
|         row = getter(curs) |  | ||||||
|         self.failUnless(row['foo'] == 'bar') |  | ||||||
|         self.failUnless(row[0] == 'bar') |  | ||||||
| 
 |  | ||||||
|     def _testWithPlainCursorReal(self, getter): |  | ||||||
|         curs = self.conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) |  | ||||||
|         curs.execute("SELECT * FROM ExtrasDictCursorTests") |  | ||||||
|         row = getter(curs) |  | ||||||
|         self.failUnless(row['foo'] == 'bar') |  | ||||||
| 
 | 
 | ||||||
|     def _testWithNamedCursorReal(self, getter): |     def _testWithNamedCursorReal(self, getter): | ||||||
|         curs = self.conn.cursor('aname', cursor_factory=psycopg2.extras.RealDictCursor) |         curs = self.conn.cursor('aname', cursor_factory=psycopg2.extras.RealDictCursor) | ||||||
|  | @ -147,11 +174,6 @@ class ExtrasDictCursorTests(unittest.TestCase): | ||||||
|         row = getter(curs) |         row = getter(curs) | ||||||
|         self.failUnless(row['foo'] == 'bar') |         self.failUnless(row['foo'] == 'bar') | ||||||
| 
 | 
 | ||||||
|     def testUpdateRow(self): |  | ||||||
|         row = self._testWithPlainCursor(lambda curs: curs.fetchone()) |  | ||||||
|         row['foo'] = 'qux' |  | ||||||
|         self.failUnless(row['foo'] == 'qux') |  | ||||||
|         self.failUnless(row[0] == 'qux') |  | ||||||
| 
 | 
 | ||||||
|     def _testNamedCursorNotGreedy(self, curs): |     def _testNamedCursorNotGreedy(self, curs): | ||||||
|         curs.itersize = 2 |         curs.itersize = 2 | ||||||
|  | @ -165,6 +187,14 @@ class ExtrasDictCursorTests(unittest.TestCase): | ||||||
|         self.assert_(recs[1]['ts'] - recs[0]['ts'] < timedelta(seconds=0.005)) |         self.assert_(recs[1]['ts'] - recs[0]['ts'] < timedelta(seconds=0.005)) | ||||||
|         self.assert_(recs[2]['ts'] - recs[1]['ts'] > timedelta(seconds=0.0099)) |         self.assert_(recs[2]['ts'] - recs[1]['ts'] > timedelta(seconds=0.0099)) | ||||||
| 
 | 
 | ||||||
|  |     def _testIterRowNumber(self, curs): | ||||||
|  |         # Only checking for dataset < itersize: | ||||||
|  |         # see CursorTests.test_iter_named_cursor_rownumber | ||||||
|  |         curs.itersize = 20 | ||||||
|  |         curs.execute("""select * from generate_series(1,10)""") | ||||||
|  |         for i, r in enumerate(curs): | ||||||
|  |             self.assertEqual(i + 1, curs.rownumber) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class NamedTupleCursorTest(unittest.TestCase): | class NamedTupleCursorTest(unittest.TestCase): | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|  | @ -192,12 +222,14 @@ class NamedTupleCursorTest(unittest.TestCase): | ||||||
|     @skip_if_no_namedtuple |     @skip_if_no_namedtuple | ||||||
|     def test_fetchone(self): |     def test_fetchone(self): | ||||||
|         curs = self.conn.cursor() |         curs = self.conn.cursor() | ||||||
|         curs.execute("select * from nttest where i = 1") |         curs.execute("select * from nttest order by 1") | ||||||
|         t = curs.fetchone() |         t = curs.fetchone() | ||||||
|         self.assertEqual(t[0], 1) |         self.assertEqual(t[0], 1) | ||||||
|         self.assertEqual(t.i, 1) |         self.assertEqual(t.i, 1) | ||||||
|         self.assertEqual(t[1], 'foo') |         self.assertEqual(t[1], 'foo') | ||||||
|         self.assertEqual(t.s, 'foo') |         self.assertEqual(t.s, 'foo') | ||||||
|  |         self.assertEqual(curs.rownumber, 1) | ||||||
|  |         self.assertEqual(curs.rowcount, 3) | ||||||
| 
 | 
 | ||||||
|     @skip_if_no_namedtuple |     @skip_if_no_namedtuple | ||||||
|     def test_fetchmany_noarg(self): |     def test_fetchmany_noarg(self): | ||||||
|  | @ -210,6 +242,8 @@ class NamedTupleCursorTest(unittest.TestCase): | ||||||
|         self.assertEqual(res[0].s, 'foo') |         self.assertEqual(res[0].s, 'foo') | ||||||
|         self.assertEqual(res[1].i, 2) |         self.assertEqual(res[1].i, 2) | ||||||
|         self.assertEqual(res[1].s, 'bar') |         self.assertEqual(res[1].s, 'bar') | ||||||
|  |         self.assertEqual(curs.rownumber, 2) | ||||||
|  |         self.assertEqual(curs.rowcount, 3) | ||||||
| 
 | 
 | ||||||
|     @skip_if_no_namedtuple |     @skip_if_no_namedtuple | ||||||
|     def test_fetchmany(self): |     def test_fetchmany(self): | ||||||
|  | @ -221,6 +255,8 @@ class NamedTupleCursorTest(unittest.TestCase): | ||||||
|         self.assertEqual(res[0].s, 'foo') |         self.assertEqual(res[0].s, 'foo') | ||||||
|         self.assertEqual(res[1].i, 2) |         self.assertEqual(res[1].i, 2) | ||||||
|         self.assertEqual(res[1].s, 'bar') |         self.assertEqual(res[1].s, 'bar') | ||||||
|  |         self.assertEqual(curs.rownumber, 2) | ||||||
|  |         self.assertEqual(curs.rowcount, 3) | ||||||
| 
 | 
 | ||||||
|     @skip_if_no_namedtuple |     @skip_if_no_namedtuple | ||||||
|     def test_fetchall(self): |     def test_fetchall(self): | ||||||
|  | @ -234,6 +270,8 @@ class NamedTupleCursorTest(unittest.TestCase): | ||||||
|         self.assertEqual(res[1].s, 'bar') |         self.assertEqual(res[1].s, 'bar') | ||||||
|         self.assertEqual(res[2].i, 3) |         self.assertEqual(res[2].i, 3) | ||||||
|         self.assertEqual(res[2].s, 'baz') |         self.assertEqual(res[2].s, 'baz') | ||||||
|  |         self.assertEqual(curs.rownumber, 3) | ||||||
|  |         self.assertEqual(curs.rowcount, 3) | ||||||
| 
 | 
 | ||||||
|     @skip_if_no_namedtuple |     @skip_if_no_namedtuple | ||||||
|     def test_executemany(self): |     def test_executemany(self): | ||||||
|  | @ -251,16 +289,26 @@ class NamedTupleCursorTest(unittest.TestCase): | ||||||
|         curs = self.conn.cursor() |         curs = self.conn.cursor() | ||||||
|         curs.execute("select * from nttest order by 1") |         curs.execute("select * from nttest order by 1") | ||||||
|         i = iter(curs) |         i = iter(curs) | ||||||
|  |         self.assertEqual(curs.rownumber, 0) | ||||||
|  | 
 | ||||||
|         t = i.next() |         t = i.next() | ||||||
|         self.assertEqual(t.i, 1) |         self.assertEqual(t.i, 1) | ||||||
|         self.assertEqual(t.s, 'foo') |         self.assertEqual(t.s, 'foo') | ||||||
|  |         self.assertEqual(curs.rownumber, 1) | ||||||
|  |         self.assertEqual(curs.rowcount, 3) | ||||||
|  | 
 | ||||||
|         t = i.next() |         t = i.next() | ||||||
|         self.assertEqual(t.i, 2) |         self.assertEqual(t.i, 2) | ||||||
|         self.assertEqual(t.s, 'bar') |         self.assertEqual(t.s, 'bar') | ||||||
|  |         self.assertEqual(curs.rownumber, 2) | ||||||
|  |         self.assertEqual(curs.rowcount, 3) | ||||||
|  | 
 | ||||||
|         t = i.next() |         t = i.next() | ||||||
|         self.assertEqual(t.i, 3) |         self.assertEqual(t.i, 3) | ||||||
|         self.assertEqual(t.s, 'baz') |         self.assertEqual(t.s, 'baz') | ||||||
|         self.assertRaises(StopIteration, i.next) |         self.assertRaises(StopIteration, i.next) | ||||||
|  |         self.assertEqual(curs.rownumber, 3) | ||||||
|  |         self.assertEqual(curs.rowcount, 3) | ||||||
| 
 | 
 | ||||||
|     def test_error_message(self): |     def test_error_message(self): | ||||||
|         try: |         try: | ||||||
|  | @ -385,6 +433,17 @@ class NamedTupleCursorTest(unittest.TestCase): | ||||||
|         self.assert_(recs[1].ts - recs[0].ts < timedelta(seconds=0.005)) |         self.assert_(recs[1].ts - recs[0].ts < timedelta(seconds=0.005)) | ||||||
|         self.assert_(recs[2].ts - recs[1].ts > timedelta(seconds=0.0099)) |         self.assert_(recs[2].ts - recs[1].ts > timedelta(seconds=0.0099)) | ||||||
| 
 | 
 | ||||||
|  |     @skip_if_no_namedtuple | ||||||
|  |     @skip_before_postgres(8, 0) | ||||||
|  |     def test_named_rownumber(self): | ||||||
|  |         curs = self.conn.cursor('tmp') | ||||||
|  |         # Only checking for dataset < itersize: | ||||||
|  |         # see CursorTests.test_iter_named_cursor_rownumber | ||||||
|  |         curs.itersize = 4 | ||||||
|  |         curs.execute("""select * from generate_series(1,3)""") | ||||||
|  |         for i, t in enumerate(curs): | ||||||
|  |             self.assertEqual(i + 1, curs.rownumber) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| def test_suite(): | def test_suite(): | ||||||
|     return unittest.TestLoader().loadTestsFromName(__name__) |     return unittest.TestLoader().loadTestsFromName(__name__) | ||||||
|  |  | ||||||
|  | @ -25,13 +25,12 @@ | ||||||
| import os | import os | ||||||
| import shutil | import shutil | ||||||
| import tempfile | import tempfile | ||||||
| from testutils import unittest, decorate_all_tests, skip_if_tpc_disabled |  | ||||||
| 
 | 
 | ||||||
| import psycopg2 | import psycopg2 | ||||||
| import psycopg2.extensions | import psycopg2.extensions | ||||||
| from psycopg2.extensions import b | from psycopg2.extensions import b | ||||||
| from testconfig import dsn, green | from testconfig import dsn, green | ||||||
| from testutils import unittest, decorate_all_tests | from testutils import unittest, decorate_all_tests, skip_if_tpc_disabled | ||||||
| 
 | 
 | ||||||
| def skip_if_no_lo(f): | def skip_if_no_lo(f): | ||||||
|     def skip_if_no_lo_(self): |     def skip_if_no_lo_(self): | ||||||
|  |  | ||||||
|  | @ -22,7 +22,8 @@ | ||||||
| # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public | # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public | ||||||
| # License for more details. | # License for more details. | ||||||
| 
 | 
 | ||||||
| from testutils import unittest | from testutils import unittest, skip_before_python | ||||||
|  | from testconfig import dsn | ||||||
| 
 | 
 | ||||||
| import psycopg2 | import psycopg2 | ||||||
| 
 | 
 | ||||||
|  | @ -127,6 +128,40 @@ class ConnectTestCase(unittest.TestCase): | ||||||
|         self.assertEqual(self.args[0], r"dbname='\\every thing\''") |         self.assertEqual(self.args[0], r"dbname='\\every thing\''") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class ExceptionsTestCase(unittest.TestCase): | ||||||
|  |     def setUp(self): | ||||||
|  |         self.conn = psycopg2.connect(dsn) | ||||||
|  | 
 | ||||||
|  |     def tearDown(self): | ||||||
|  |         self.conn.close() | ||||||
|  | 
 | ||||||
|  |     def test_attributes(self): | ||||||
|  |         cur = self.conn.cursor() | ||||||
|  |         try: | ||||||
|  |             cur.execute("select * from nonexist") | ||||||
|  |         except psycopg2.Error, exc: | ||||||
|  |             e = exc | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(e.pgcode, '42P01') | ||||||
|  |         self.assert_(e.pgerror) | ||||||
|  |         self.assert_(e.cursor is cur) | ||||||
|  | 
 | ||||||
|  |     @skip_before_python(2, 5) | ||||||
|  |     def test_pickle(self): | ||||||
|  |         import pickle | ||||||
|  |         cur = self.conn.cursor() | ||||||
|  |         try: | ||||||
|  |             cur.execute("select * from nonexist") | ||||||
|  |         except psycopg2.Error, exc: | ||||||
|  |             e = exc | ||||||
|  | 
 | ||||||
|  |         e1 = pickle.loads(pickle.dumps(e)) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(e.pgerror, e1.pgerror) | ||||||
|  |         self.assertEqual(e.pgcode, e1.pgcode) | ||||||
|  |         self.assert_(e1.cursor is None) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def test_suite(): | def test_suite(): | ||||||
|     return unittest.TestLoader().loadTestsFromName(__name__) |     return unittest.TestLoader().loadTestsFromName(__name__) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -45,8 +45,8 @@ class QuotingTestCase(unittest.TestCase): | ||||||
|     The tests also check that no warning is raised ('escape_string_warning' |     The tests also check that no warning is raised ('escape_string_warning' | ||||||
|     should be on). |     should be on). | ||||||
| 
 | 
 | ||||||
|     http://www.postgresql.org/docs/8.1/static/sql-syntax.html#SQL-SYNTAX-STRINGS |     http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS | ||||||
|     http://www.postgresql.org/docs/8.1/static/runtime-config-compatible.html |     http://www.postgresql.org/docs/current/static/runtime-config-compatible.html | ||||||
|     """ |     """ | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         self.conn = psycopg2.connect(dsn) |         self.conn = psycopg2.connect(dsn) | ||||||
|  |  | ||||||
|  | @ -82,13 +82,22 @@ class TypesExtrasTests(unittest.TestCase): | ||||||
| 
 | 
 | ||||||
|     def testINET(self): |     def testINET(self): | ||||||
|         psycopg2.extras.register_inet() |         psycopg2.extras.register_inet() | ||||||
|         i = "192.168.1.0/24"; |         i = psycopg2.extras.Inet("192.168.1.0/24") | ||||||
|         s = self.execute("SELECT %s AS foo", (i,)) |         s = self.execute("SELECT %s AS foo", (i,)) | ||||||
|         self.failUnless(i == s) |         self.failUnless(i.addr == s.addr) | ||||||
|         # must survive NULL cast to inet |         # must survive NULL cast to inet | ||||||
|         s = self.execute("SELECT NULL::inet AS foo") |         s = self.execute("SELECT NULL::inet AS foo") | ||||||
|         self.failUnless(s is None) |         self.failUnless(s is None) | ||||||
| 
 | 
 | ||||||
|  |     def testINETARRAY(self): | ||||||
|  |         psycopg2.extras.register_inet() | ||||||
|  |         i = psycopg2.extras.Inet("192.168.1.0/24") | ||||||
|  |         s = self.execute("SELECT %s AS foo", ([i],)) | ||||||
|  |         self.failUnless(i.addr == s[0].addr) | ||||||
|  |         # must survive NULL cast to inet | ||||||
|  |         s = self.execute("SELECT NULL::inet[] AS foo") | ||||||
|  |         self.failUnless(s is None) | ||||||
|  | 
 | ||||||
|     def test_inet_conform(self): |     def test_inet_conform(self): | ||||||
|         from psycopg2.extras import Inet |         from psycopg2.extras import Inet | ||||||
|         i = Inet("192.168.1.0/24") |         i = Inet("192.168.1.0/24") | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user