mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-01-31 17:34:08 +03:00
Merge remote-tracking branch 'piro/devel' into devel
Conflicts: psycopg/lobject_int.c
This commit is contained in:
commit
550130b19e
6
INSTALL
6
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,7 +16,7 @@ then:
|
||||||
to build in the local directory; and:
|
to build in the local directory; and:
|
||||||
|
|
||||||
python setup.py install
|
python setup.py install
|
||||||
|
|
||||||
to install system-wide.
|
to install system-wide.
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ Dev-C++ (http://www.bloodshed.net/devcpp.html) and Code::Blocks
|
||||||
You need a PostgreSQL with include and libary files installed. At least v8.0
|
You need a PostgreSQL with include and libary files installed. At least v8.0
|
||||||
is required.
|
is required.
|
||||||
|
|
||||||
First you need to create a libpython2X.a as described in
|
First you need to create a libpython2X.a as described in
|
||||||
http://starship.python.net/crew/kernr/mingw32/Notes.html. Then run:
|
http://starship.python.net/crew/kernr/mingw32/Notes.html. Then run:
|
||||||
|
|
||||||
python setup.py build_ext --compiler=mingw32 install
|
python setup.py build_ext --compiler=mingw32 install
|
||||||
|
|
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,31 +117,30 @@ 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.
|
||||||
|
|
||||||
|
.. doctest::
|
||||||
|
:options: +NORMALIZE_WHITESPACE
|
||||||
|
|
||||||
|
>>> try:
|
||||||
|
... cur.execute("SELECT * FROM barf")
|
||||||
|
... except Exception, e:
|
||||||
|
... pass
|
||||||
|
|
||||||
|
>>> e.pgcode
|
||||||
|
'42P01'
|
||||||
|
>>> print e.pgerror
|
||||||
|
ERROR: relation "barf" does not exist
|
||||||
|
LINE 1: SELECT * FROM barf
|
||||||
|
^
|
||||||
|
.. attribute:: cursor
|
||||||
|
|
||||||
|
The cursor the exception was raised from; `None` if not applicable.
|
||||||
|
|
||||||
.. extension::
|
.. extension::
|
||||||
|
|
||||||
The `~Error.pgerror` and `~Error.pgcode` attributes are
|
The `~Error.pgerror`, `~Error.pgcode`, and `~Error.cursor` attributes
|
||||||
Psycopg extensions.
|
are Psycopg extensions.
|
||||||
|
|
||||||
.. doctest::
|
|
||||||
:options: +NORMALIZE_WHITESPACE
|
|
||||||
|
|
||||||
>>> try:
|
|
||||||
... cur.execute("SELECT * FROM barf")
|
|
||||||
... except Exception, e:
|
|
||||||
... pass
|
|
||||||
|
|
||||||
>>> e.pgcode
|
|
||||||
'42P01'
|
|
||||||
>>> print e.pgerror
|
|
||||||
ERROR: relation "barf" does not exist
|
|
||||||
LINE 1: SELECT * FROM barf
|
|
||||||
^
|
|
||||||
|
|
||||||
.. versionchanged:: 2.0.7 added `Error.pgerror` and
|
|
||||||
`Error.pgcode` attributes.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. exception:: InterfaceError
|
.. exception:: InterfaceError
|
||||||
|
|
||||||
Exception raised for errors that are related to the database interface
|
Exception raised for errors that are related to the database interface
|
||||||
|
|
|
@ -294,9 +294,9 @@ the SQL string that would be sent to the database.
|
||||||
`bytea_output`__ configuration parameter to ``escape``, either in the
|
`bytea_output`__ configuration parameter to ``escape``, either in the
|
||||||
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)
|
||||||
|
@ -505,13 +498,13 @@ class Inet(object):
|
||||||
"""
|
"""
|
||||||
def __init__(self, addr):
|
def __init__(self, addr):
|
||||||
self.addr = addr
|
self.addr = addr
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%r)" % (self.__class__.__name__, self.addr)
|
return "%s(%r)" % (self.__class__.__name__, self.addr)
|
||||||
|
|
||||||
def prepare(self, conn):
|
def prepare(self, conn):
|
||||||
self._conn = conn
|
self._conn = conn
|
||||||
|
|
||||||
def getquoted(self):
|
def getquoted(self):
|
||||||
obj = _A(self.addr)
|
obj = _A(self.addr)
|
||||||
if hasattr(obj, 'prepare'):
|
if hasattr(obj, 'prepare'):
|
||||||
|
@ -524,13 +517,32 @@ class Inet(object):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
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):
|
||||||
|
|
24
lib/tz.py
24
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 = conn;
|
||||||
self->conn = (PyObject*)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) */
|
||||||
PyList_Insert(self->notice_list, nnotices, msg);
|
if (msg) {
|
||||||
Py_DECREF(msg);
|
PyList_Insert(self->notice_list, nnotices, 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,25 +432,20 @@ _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;
|
/* Py_XDECREF(operation) is safe because the original reference passed
|
||||||
/* Fall through to cleanup */
|
by the caller was overwritten with either NULL or a new
|
||||||
cleanup:
|
reference */
|
||||||
/* Py_XDECREF(operation) is safe because the original reference passed
|
Py_XDECREF(operation);
|
||||||
by the caller was overwritten with either NULL or a new
|
Py_XDECREF(cvt);
|
||||||
reference */
|
|
||||||
Py_XDECREF(operation);
|
|
||||||
|
|
||||||
Py_XDECREF(cvt);
|
return res;
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -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,59 +686,59 @@ _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)
|
);
|
||||||
);
|
if (istuple) {
|
||||||
if (istuple) {
|
PyTuple_SET_ITEM(res, i, val);
|
||||||
PyTuple_SET_ITEM(res, i, val);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
err = PySequence_SetItem(res, i, val);
|
|
||||||
Py_DECREF(val);
|
|
||||||
if (err == -1) {
|
|
||||||
Py_DECREF(res);
|
|
||||||
res = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* an error occurred in the type system, we return NULL to raise
|
err = PySequence_SetItem(res, i, val);
|
||||||
an exception. the typecast code should already have set the
|
Py_DECREF(val);
|
||||||
exception type and text */
|
if (err == -1) { goto exit; }
|
||||||
Py_DECREF(res);
|
|
||||||
res = NULL;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
if (new_oid != InvalidOid)
|
/* Use lo_creat when possible to be more middleware-friendly.
|
||||||
|
See ticket #88. */
|
||||||
|
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;
|
||||||
|
@ -164,7 +164,7 @@ pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres)
|
||||||
"psycopg went psycotic and raised a null error");
|
"psycopg went psycotic and raised a null error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if the connection has somehow beed broken, we mark the connection
|
/* if the connection has somehow beed broken, we mark the connection
|
||||||
object as closed but requiring cleanup */
|
object as closed but requiring cleanup */
|
||||||
if (conn->pgconn != NULL && PQstatus(conn->pgconn) == CONNECTION_BAD)
|
if (conn->pgconn != NULL && PQstatus(conn->pgconn) == CONNECTION_BAD)
|
||||||
|
@ -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);
|
||||||
|
@ -264,11 +266,13 @@ pq_resolve_critical(connectionObject *conn, int close)
|
||||||
|
|
||||||
/* we don't want to destroy this connection but just close it */
|
/* we don't want to destroy this connection but just close it */
|
||||||
if (close == 1) conn_close(conn);
|
if (close == 1) conn_close(conn);
|
||||||
|
|
||||||
/* 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 {
|
||||||
|
conn->mark += 1;
|
||||||
|
retvalue = pq_execute_command_locked(conn, "COMMIT", &pgres, &error, &_save);
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
pthread_mutex_lock(&conn->lock);
|
|
||||||
conn->mark += 1;
|
|
||||||
|
|
||||||
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,15 +627,17 @@ 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);
|
||||||
|
@ -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,10 +7,10 @@ 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
|
||||||
# uncommenting the following line and setting its value to the right path.
|
# uncommenting the following line and setting its value to the right path.
|
||||||
#mx_include_dir=
|
#mx_include_dir=
|
||||||
|
|
||||||
|
@ -28,14 +28,14 @@ have_ssl=0
|
||||||
# set it to the pg_config full path.
|
# set it to the pg_config full path.
|
||||||
#pg_config=
|
#pg_config=
|
||||||
|
|
||||||
# If "pg_config" is not available, "include_dirs" can be used to locate
|
# If "pg_config" is not available, "include_dirs" can be used to locate
|
||||||
# postgresql headers and libraries. Some extra checks on sys.platform will
|
# postgresql headers and libraries. Some extra checks on sys.platform will
|
||||||
# still be done in setup.py.
|
# still be done in setup.py.
|
||||||
# The next line is the default as used on psycopg author Debian laptop:
|
# The next line is the default as used on psycopg author Debian laptop:
|
||||||
#include_dirs=/usr/include/postgresql:/usr/include/postgresql/server
|
#include_dirs=/usr/include/postgresql:/usr/include/postgresql/server
|
||||||
|
|
||||||
# Uncomment next line on Mandrake 10.x (and comment previous ones):
|
# Uncomment next line on Mandrake 10.x (and comment previous ones):
|
||||||
#include_dirs=/usr/include/pgsql/8.0:/usr/include/pgsql/8.0/server
|
#include_dirs=/usr/include/pgsql/8.0:/usr/include/pgsql/8.0/server
|
||||||
|
|
||||||
# Uncomment next line on SUSE 9.3 (and comment previous ones):
|
# Uncomment next line on SUSE 9.3 (and comment previous ones):
|
||||||
#include_dirs=/usr/include/pgsql:/usr/include/pgsql/server
|
#include_dirs=/usr/include/pgsql:/usr/include/pgsql/server
|
||||||
|
|
|
@ -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