Merge from 2.0 branch up to r839.

This commit is contained in:
Federico Di Gregorio 2006-09-30 06:57:35 +00:00
parent 52666ef5bd
commit 96f631d41e
39 changed files with 2208 additions and 98 deletions

View File

@ -1,3 +1,47 @@
2006-09-30 Federico Di Gregorio <fog@initd.org>
* ZpsycopgDA/DA.py: applied the infinity patch from 1.1 (fixes #122).
* psycopg/adapter_datetime.py: fixed conversion problem with seconds
in the (59,60) range (fixes #131).
* ZpsycopgDA/DA.py: we now split on GMT+, GMT-, + or -. This should
fix bug #129.
* psycopg/adapter_datetime.py: now TimeFromTicks and
TimestampFromTicks both accept fractionary seconds (fixes #130).
2006-09-23 Federico Di Gregorio <fog@initd.org>
* lib/errorcodes.py: added list of all PostgreSQL error codes
compiled by Johan Dahlin.
* psycopg/psycopg.h: applied compatibility macros from PEP 353.
* Applied patch 1/3 from Piet Delport; from his email:
psycopg2-Py_ssize_t-input.diff adjusts variables used for parameters
and return values. These changes only prevent overflowing on values
greater than 32-bits, so they're not as critical as the other two
patches. I tried to leave places unchanged where the input size is
already constrained to sizeof(int), but i might have missed a few
either way, not being too familiar with the codebase.
* Applied patch 2/3 from Piet Delport; from his email:
psycopg2-Py_ssize_t-output.diff adjusts variables used as outputs
from CPython API calls: without it the calls try to write 64 bits
to 32 bit locations, trampling over adjacent values/pointers,
and segfaulting later.
* Applied patch 1/3 from Piet Delport; from his email:
psycopg2-PyObject_HEAD.diff adds missing underscores to several
"PyObject_HEAD" declarations. As far as i can tell from gdb, the
"PyObject HEAD" versions end up accidentally meaning almost exactly
the same, but get aligned differently on AMD64, resulting in wrong
size calculation and memory corruption later.
2006-09-11 Federico Di Gregorio <fog@initd.org>
* lib/extras.py: ported syntax error fix from 2.0 (#123).

View File

@ -18,7 +18,8 @@
# See the LICENSE file for details.
ALLOWED_PSYCOPG_VERSIONS = ('2.0.1', '2.0.2', '2.0.3', '2.0.4', '2.0.5')
ALLOWED_PSYCOPG_VERSIONS = ('2.0.1', '2.0.2', '2.0.3', '2.0.4', '2.0.5',
'2.0.6')
import sys
import time
@ -220,7 +221,10 @@ for icon in ('table', 'view', 'stable', 'what', 'field', 'text', 'bin',
# convert an ISO timestamp string from postgres to a Zope DateTime object
def _cast_DateTime(iso, curs):
if iso:
return DateTime(re.split("GMT\+?|GMT-?", iso)[0])
if iso in ['-infinity', 'infinity']:
return iso
else:
return DateTime(re.split("GMT\+?|GMT-?|\+|-", iso)[0])
# this will split us into [date, time, GMT/AM/PM(if there)]
# dt = str.split(' ')
@ -235,14 +239,20 @@ def _cast_DateTime(iso, curs):
# convert an ISO date string from postgres to a Zope DateTime object
def _cast_Date(iso, curs):
if iso:
return DateTime(iso)
if iso in ['-infinity', 'infinity']:
return iso
else:
return DateTime(iso)
# Convert a time string from postgres to a Zope DateTime object.
# NOTE: we set the day as today before feeding to DateTime so
# that it has the same DST settings.
def _cast_Time(iso, curs):
if iso:
return DateTime(time.strftime('%Y-%m-%d %H:%M:%S',
if iso in ['-infinity', 'infinity']:
return iso
else:
return DateTime(time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime(time.time())[:3]+
time.strptime(iso[:8], "%H:%M:%S")[3:]))

7
debian/README.zpsycopgda2 vendored Normal file
View File

@ -0,0 +1,7 @@
ZPsycopgDA (in the Debian zope-psycopgda package) is a Zope Database
Adapter based on the psycopg Python/PostgreSQL driver. You'll find
more information and documentation in the pythonX.Y-psycopg package,
where X.Y is the version of your installed Python.
Details for ZPsycopgDA for Zope are found in the documentation of
the python2.3-psycopg package.

587
debian/changelog vendored
View File

@ -1,12 +1,585 @@
psycopg2 (1.99.12.1-1) experimental; urgency=low
psycopg2 (2.0.5.1-1) unstable; urgency=low
* Adapted from patches sent by W. Borgert.
* Renamed source package to psycopg2.
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Fri, 4 Mar 2005 13:11:43 +0100
-- Fabio Tranchitella <kobold@debian.org> Tue, 19 Sep 2006 08:22:36 +0200
psycopg2 (1.99.11-0.1) unstable; urgency=low
psycopg2 (2.0.4-1) unstable; urgency=low
* New upstream release.
* debian/control:
+ removed dependency on python-egenix-mxdatetime.
+ added ${shlibs:Depends} for the python-psycopg2 package.
(Closes: #381462)
-- Fabio Tranchitella <kobold@debian.org> Wed, 9 Aug 2006 10:28:30 +0200
psycopg2 (2.0.2-1) unstable; urgency=low
* New upstream major release, new source package. (Closes: #377956)
-- Fabio Tranchitella <kobold@debian.org> Sun, 16 Jul 2006 21:43:41 +0200
psycopg (1.1.21-8) unstable; urgency=low
* debian/zope-psycopgda.dzproduct: added 2.9 to the list of supported
zope versions. (Closes: #376538)
-- Fabio Tranchitella <kobold@debian.org> Fri, 14 Jul 2006 10:19:54 +0200
psycopg (1.1.21-7) unstable; urgency=low
* Moved dh_installzope within an arch-indep target. (Closes: #373842)
-- Fabio Tranchitella <kobold@debian.org> Fri, 16 Jun 2006 09:37:23 +0200
psycopg (1.1.21-6) unstable; urgency=low
* Python policy transition. (Closes: #373482)
-- Fabio Tranchitella <kobold@debian.org> Thu, 15 Jun 2006 19:09:36 +0200
psycopg (1.1.21-5) unstable; urgency=high
* ypemod.c, new_psyco_bufferobject():
- Escape quotes psycopg.Binary() results as '', not as \', since the
latter does not work any more with some client encodings with the latest
PostgreSQL (in some multi-byte encodings you can exploit \' escaping to
inject SQL code, see CVE-2006-2314). (Closes: #369230)
Thanks to Martin Pitt and Ubuntu security team for the patch.
-- Fabio Tranchitella <kobold@debian.org> Tue, 30 May 2006 22:15:06 +0200
psycopg (1.1.21-4) unstable; urgency=low
* debian/rules: remove *.o in the clean target. (Closes: #352835)
-- Fabio Tranchitella <kobold@debian.org> Thu, 16 Feb 2006 12:06:53 +0000
psycopg (1.1.21-3) unstable; urgency=low
* debian/control: removed build-dependency on postgresql-server-dev-8.0,
as suggested by Martin Pitt. (Closes: #339640)
-- Fabio Tranchitella <kobold@debian.org> Fri, 18 Nov 2005 08:44:26 +0000
psycopg (1.1.21-2) unstable; urgency=low
* debian/control: zope-psycopgda should depend on the same version of the
psycopg python module. (Closes: #336765)
-- Fabio Tranchitella <kobold@debian.org> Wed, 2 Nov 2005 12:07:33 +0000
psycopg (1.1.21-1) unstable; urgency=low
* New maintainer; Thanks Federico for your work, and be sure that I'll
take care of this package.
* New upstream release (Closes: #321592, #320618, #333638)
* debian/python2.4-psycopg.dirs: added. (Closes: #319509, #329115)
* debian/control: dropped support for python2.1 and
python2.2. (Closes: #333639)
* debian/control: Standards-Version bumped to 3.6.2, no changes required.
* debian/rules: make use of dh_installzope from zope-debhelper to build the
zope-psycopgda package.
(Closes: #158669, #323599, #268975, #292247, #327415)
* debian/control: added build-depends on postgresql-server-dev-8.0.
(Closes: #333638)
* Re-packaged upstream tarball replacing some broken images.
(Closes: #292008, #305392)
-- Fabio Tranchitella <kobold@debian.org> Fri, 28 Oct 2005 11:24:37 +0000
psycopg (1.1.19-1) unstable; urgency=low
* Experimental package.
* New upstream release.
* Applied patch from Martin Krafft to build Zope 2.7 packages.
* Modified to use the new PostgreSQL packages.
* Added python 2.4 package (Closes: #301403).
* Upstream applied various Ubuntu patches (Closes: #301947, #300893).
-- Federico Di Gregorio <fog@debian.org> Sat, 16 Jul 2005 20:47:08 +0200
psycopg (1.1.18-1) unstable; urgency=low
* New upstream release.
* 1.1.16 fixed rowcount bug (closes: #266299).
-- Federico Di Gregorio <fog@debian.org> Wed, 5 Jan 2005 21:05:15 +0100
psycopg (1.1.17-1) unstable; urgency=high
* Urgency is still high because 1.1.16 was never uploaded.
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Thu, 19 Nov 2004 01:14:30 +0200
psycopg (1.1.16-1) unstable; urgency=high
* New upstream release.
* Tagged with urgency=high because fix a grave bug (rowcount) introduced
in 1.1.15.
* Upstream fix: does not segfault when using COPY TO/COPY FROM in
.execute() (closes: #279222).
-- Federico Di Gregorio <fog@debian.org> Sat, 30 Oct 2004 02:35:30 +0200
psycopg (1.1.15-1) unstable; urgency=low
* New upstream release.
* Definitely fixed (ah ah) time interval problems (closes: #259213).
-- Federico Di Gregorio <fog@initd.org> Thu, 29 Jul 2004 23:43:59 +0200
psycopg (1.1.14-1) unstable; urgency=low
* New upstream release.
* Don't put two copies of changelog in every package anymore
(closes: #256662).
* Updated test script works as expected (closes: #231391).
* Changes from NMU incorporated in 1.1.12:
- zpsycopgda depends on python2.2-psycopg (closes: #227420, #227147).
- compiled with postgresql in unstable (close: #220527).
-- Federico Di Gregorio <fog@initd.org> Fri, 9 Jul 2004 23:01:40 +0200
psycopg (1.1.13-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Fri, 21 May 2004 10:33:54 +0200
psycopg (1.1.12-1) unstable; urgency=low
* New upstream release (the "martin you won't have this package"
release.)
* Integrated changes from NMU releases.
-- Federico Di Gregorio <fog@debian.org> Sun, 16 May 2004 10:14:47 +0200
psycopg (1.1.10-1.2) unstable; urgency=low
* Non-maintainer upload. Thinking about taking this package over...
* Changed dependency on pyscopgda Python module to Python version 2.2.
(closes: #227147, #227420)
* Added Lintian overrides for image-in-/usr/lib warnings -- Zope needs
these images...
-- martin f. krafft <madduck@debian.org> Thu, 15 Apr 2004 23:30:40 +0200
psycopg (1.1.10-1.1) unstable; urgency=low
* Non-maintainer upload.
* No changes - this upload is simply a rebuild against the current unstable
instead of experimental postgresql-dev.
(closes: #219927, #220141, #220173, #220527)
-- Peter Hawkins <peterh@debian.org> Sun, 28 Dec 2003 10:57:30 +1100
psycopg (1.1.10-1) unstable; urgency=low
* Added download location to debian/copyright file (Closes: #215880).
-- Federico Di Gregorio <fog@initd.org> Sat, 8 Nov 2003 23:32:40 +0100
psycopg (1.1.9-1) unstable; urgency=low
* New upstream release.
* Bug was agains an old 1.0.x version of psycopg (Closes: #208702).
-- Federico Di Gregorio <fog@initd.org> Wed, 10 Sep 2003 13:04:42 +0200
psycopg (1.1.8-1) unstable; urgency=low
* New upstream release.
* Integrated NMU from Matthias Klose (closes: #205746).
-- Federico Di Gregorio <fog@debian.org> Fri, 1 Aug 2003 11:50:57 +0200
psycopg (1.1.5.1-1.1) unstable; urgency=low
* NMU
* Update for python2.3 as the default python version (closes: #205746).
-- Matthias Klose <doko@debian.org> Fri, 22 Aug 2003 00:02:25 +0200
psycopg (1.1.7-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Sat, 26 Jul 2003 15:03:39 +0200
psycopg (1.1.6-1) unstable; urgency=low
* New upstream release.
* Upstream applied patch from BTS (Closes: #200161).
-- Federico Di Gregorio <fog@initd.org> Sun, 13 Jul 2003 23:36:04 +0200
psycopg (1.1.5.1-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@initd.org> Mon, 23 Jun 2003 00:37:33 +0200
psycopg (1.1.5-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@initd.org> Sun, 22 Jun 2003 21:30:01 +0200
psycopg (1.1.4-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Wed, 7 May 2003 15:21:31 +0200
psycopg (1.1.3-1) unstable; urgency=low
* New upstream release.
* Changed section in debian/control (-> python).
-- Federico Di Gregorio <fog@debian.org> Wed, 2 Apr 2003 10:33:36 +0200
psycopg (1.1.2-1) unstable; urgency=low
* New upstream release.
* Started to track the 1.1.x branch.
-- Federico Di Gregorio <fog@debian.org> Tue, 25 Feb 2003 01:06:08 +0100
psycopg (1.0.15.1-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Fri, 14 Feb 2003 16:09:50 +0100
psycopg (1.0.15-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Wed, 12 Feb 2003 23:49:51 +0100
psycopg (1.0.14-1) unstable; urgency=low
* Applied patch from John Goerzen to fix memory leak in executemany()
and callproc() (Closes: #169284).
* New upstream release (Closes: #170297).
-- Federico Di Gregorio <fog@debian.org> Mon, 25 Nov 2002 16:50:37 +0100
psycopg (1.0.13-1) unstable; urgency=low
* New upstream release.
* Python 2.3 package added (Closes: #160831)
* IntegrityError raised when needed (upstream, Closes: #165791)
* Packages are lintian clean again.
-- Federico Di Gregorio <fog@debian.org> Fri, 25 Oct 2002 11:54:19 +0200
psycopg (1.0.12-1) unstable; urgency=low
* New upstream release.
* Fixed wrong url in RELEASE-1.0. (Closes: #153840)
-- Federico Di Gregorio <fog@debian.org> Fri, 13 Sep 2002 13:16:36 +0200
psycopg (1.0.11.1-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Mon, 26 Aug 2002 10:41:54 +0200
psycopg (1.0.11-1) unstable; urgency=low
* New upstream release.
* The dummy python-psycopg package now depends on the new default debian
python (2.2) and on python2.2-psycopg.
* Removed support for python 1.5 (support for 2.3 has to wait for egenix
packages.)
-- Federico Di Gregorio <fog@debian.org> Fri, 23 Aug 2002 11:25:01 +0200
psycopg (1.0.10-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@initd.org> Mon, 22 Jul 2002 02:04:59 +0200
psycopg (1.0.9-1) unstable; urgency=low
* Resolved section override (main->interpreters).
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Thu, 20 Jun 2002 14:00:42 +0200
psycopg (1.0.8-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Tue, 23 Apr 2002 22:42:22 +0200
psycopg (1.0.7.1-2) unstable; urgency=low
* Moved to main.
-- Federico Di Gregorio <fog@debian.org> Fri, 19 Apr 2002 10:06:58 +0200
psycopg (1.0.7.1-1) unstable; urgency=low
* New upstream release.
* Fixed a bug in ./configure; closes: #141774.
-- Federico Di Gregorio <fog@debian.org> Mon, 8 Apr 2002 18:54:24 +0200
psycopg (1.0.7-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Fri, 29 Mar 2002 14:24:45 +0100
psycopg (1.0.6-1) unstable; urgency=low
* New upstream release.
* Builds with new libpq libraries and header layout.
-- Federico Di Gregorio <fog@debian.org> Thu, 7 Mar 2002 11:59:40 +0100
psycopg (1.0.5-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Mon, 4 Mar 2002 14:43:13 +0100
psycopg (1.0.4-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Wed, 20 Feb 2002 20:37:16 +0100
psycopg (1.0.3-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Fri, 8 Feb 2002 15:17:44 +0100
psycopg (1.0.2-1) unstable; urgency=low
* New upstream release.
* Added package for python2.2 (Closes: #132650).
-- Federico Di Gregorio <fog@debian.org> Fri, 8 Feb 2002 00:45:07 +0100
psycopg (1.0.1-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Sun, 20 Jan 2002 18:27:22 +0100
psycopg (1.0-4) unstable; urgency=low
* Added build depend on plain python, to really close the %£$! #121229
bug this time (Closes: #121229).
-- Federico Di Gregorio <fog@debian.org> Wed, 28 Nov 2001 10:50:06 +0100
psycopg (1.0-3) unstable; urgency=low
* Added explicit build depends on python 1.5 & 2.1 (Closes: #121229).
* Fixed bad dependency on python1.5-egenix-mxdatetime.
-- Federico Di Gregorio <fog@debian.org> Mon, 26 Nov 2001 17:18:41 +0100
psycopg (1.0-2) unstable; urgency=low
* Fixed dependencies as per python policy.
* Added default, unversioned psycopg package (python-psycopg).
* Added non-US/main and rebuilt after REJECT.
-- Federico Di Gregorio <fog@debian.org> Fri, 16 Nov 2001 01:14:54 +0100
psycopg (1.0-1) unstable; urgency=low
* New upstream release. 1.0!
* Now we build versioned packages for python 1.5 and 2.1.
-- Federico Di Gregorio <fog@debian.org> Tue, 13 Nov 2001 19:24:39 +0100
psycopg (0.99.7-1) unstable; urgency=low
* New upstream release fixing some little bugs.
* This version requires the mx DateTime packages that are not yet in
debian... waiting for them I'll distribute both psycopg and unofficial
packages on the initd psycopg page.
-- Federico Di Gregorio <fog@debian.org> Tue, 18 Sep 2001 23:28:51 +0200
psycopg (0.99.6-2) unstable; urgency=low
* Added suggested build-depends (Closes: #112112).
* Applied patch by Michael Weber to configure.in, to look for a compiler
(Closes: #112024).
-- Federico Di Gregorio <fog@debian.org> Thu, 13 Sep 2001 10:49:37 +0200
psycopg (0.99.6-1) unstable; urgency=low
* Added Build-depends line (Closes: #89798).
* Now zope-psycopgda requires python-psycopg, zope on debian still runs
with python 1.x only (Closes: #108890).
* Moved package to non-US (psycopg depends on postgresql that is in
non-US, sic).
-- Federico Di Gregorio <fog@debian.org> Mon, 3 Sep 2001 13:02:11 +0200
psycopg (0.99.5-1) unstable; urgency=low
* New upstream release with bound variables quoting (Closes: #102843).
* The build process set the correct path to DateTime module
(Closes: #102838).
* Removes .pyc files in prerm (Closes: #104382)
-- Federico Di Gregorio <fog@debian.org> Thu, 12 Jul 2001 12:56:38 +0200
psycopg (0.99.4-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Mon, 2 Jul 2001 15:33:29 +0200
psycopg (0.99.3-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Wed, 20 Jun 2001 12:55:47 +0200
psycopg (0.99.2-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Tue, 5 Jun 2001 15:37:50 +0200
psycopg (0.99.1-1) unstable; urgency=low
* New upstream release.
-- Federico Di Gregorio <fog@debian.org> Tue, 5 Jun 2001 12:46:18 +0200
psycopg (0.5.5-1) unstable; urgency=low
* New upstream release (ok, *we* are the upstream authors, but after
putting the -1 in the version i am supposed to say "new upstream
version" when the non-debian versions changes, right? ouch...)
-- Federico Di Gregorio <fog@debian.org> Fri, 1 Jun 2001 17:18:52 +0200
psycopg (0.5.4-1) unstable; urgency=low
* Another bugfixing release.
* Added debian revision to be able to release multiple versions with the
same upstream version.
-- Federico Di Gregorio <fog@debian.org> Fri, 18 May 2001 19:32:59 +0200
psycopg (0.5.3) unstable; urgency=low
* Some bugs fixed, new release.
-- Federico Di Gregorio <fog@debian.org> Fri, 4 May 2001 16:19:09 +0200
psycopg (0.5.2) unstable; urgency=low
* New bugfixing release.
-- Federico Di Gregorio <fog@debian.org> Fri, 27 Apr 2001 09:52:16 +0200
psycopg (0.5.1) unstable; urgency=low
* New bugfixing release.
-- Federico Di Gregorio <fog@debian.org> Tue, 3 Apr 2001 11:13:26 +0200
psycopg (0.5.0) unstable; urgency=low
* New release.
-- Federico Di Gregorio <fog@debian.org> Fri, 30 Mar 2001 12:54:42 +0200
psycopg (0.4.7) unstable; urgency=low
* New release.
* Lots of small bug fixes (see detailed ChangeLog.)
* Includes beginning of DBAPI-2.0 testsuite.
-- Federico Di Gregorio <fog@debian.org> Fri, 16 Mar 2001 18:29:03 +0100
psycopg (0.4.6) unstable; urgency=low
* New release.
* Fixed a little bug in debian/rules (does not create an examples
directory inside examples.)
-- Federico Di Gregorio <fog@debian.org> Wed, 14 Mar 2001 01:00:26 +0100
psycopg (0.4.5) unstable; urgency=low
* New upstream (mmm... but one of the upstream authors it is
*me*... mmm...) release.
-- Federico Di Gregorio <fog@debian.org> Mon, 12 Mar 2001 11:41:42 +0100
psycopg (0.4.4) unstable; urgency=low
* New release.
* Fixed Sections in debian/control.
-- Federico Di Gregorio <fog@debian.org> Fri, 9 Mar 2001 10:11:02 +0100
psycopg (0.4.3) unstable; urgency=low
* New release.
* Fixed typo in connectionAdd.dtml (Closes: #88817)
-- Federico Di Gregorio <fog@debian.org> Wed, 7 Mar 2001 15:54:35 +0100
psycopg (0.4.2) unstable; urgency=low
* New release (fixes bugs in ZPsycopgDA.)
-- Federico Di Gregorio <fog@debian.org> Mon, 5 Mar 2001 13:33:39 +0100
psycopg (0.4.1) unstable; urgency=low
* New release.
* we now create packages for both versions of python in debian
(1.5 and 2.0, packages python-* and python2-*)
-- Federico Di Gregorio <fog@debian.org> Fri, 2 Mar 2001 12:10:52 +0100
psycopg (0.4) unstable; urgency=low
* News release.
* Now debian/rules build the Zope Database Adapter zope-psycopgda too.
* Source name changed from python-psycopg to psycopg.
-- Federico Di Gregorio <fog@debian.org> Tue, 27 Feb 2001 15:11:04 +0100
python-psycopg (0.3) unstable; urgency=low
* New release. Tons of bugs fixed and new features, see ChangeLog for
details.
-- Federico Di Gregorio <fog@debian.org> Mon, 26 Feb 2001 21:22:23 +0100
python-psycopg (0.2) unstable; urgency=low
* New release. Fixed lots of bugs and memory leaks.
-- Federico Di Gregorio <fog@debian.org> Fri, 16 Feb 2001 11:04:17 +0100
python-psycopg (0.1) unstable; urgency=low
* Initial release.
-- Federico Di Gregorio <fog@debian.org> Mon, 12 Feb 2001 14:46:53 +0100
-- W. Borgert <debacle@debian.org> Sun, 09 Jan 2005 10:14:09 +0000

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
5

66
debian/control vendored
View File

@ -1,51 +1,35 @@
Source: psycopg2
Section: python
Priority: optional
Build-depends: postgresql-dev, debhelper (>> 3), python2.3-dev, cdbs
Maintainer: Federico Di Gregorio <fog@debian.org>
Standards-Version: 3.6.1.1
Build-Depends: debhelper (>= 5.0.37.2), python-all-dev, python-central (>= 0.5.0), python (>= 2.3.5-7), python-egenix-mx-base-dev, autoconf, libpq-dev
Build-Depends-Indep: zope-debhelper (>= 0.3.2.7)
Maintainer: Fabio Tranchitella <kobold@debian.org>
Standards-Version: 3.7.2
XS-Python-Version: all
Package: python-psycopg2
Architecture: any
Section: python
Depends: python (>= 2.3), python (<< 2.4), python2.3-psycopg2
Description: Python module for PostgreSQL [dummy package]
psycopg is a PostgreSQL database adapter for the Python programming
language. It was written from scratch with the aim of being very small
and fast, and stable as a rock. The main advantages of psycopg are that
it supports the full Python DBAPI-2.0 and being thread safe at level 2.
Depends: ${python:Depends}, ${shlibs:Depends}
Provides: ${python:Provides}
XB-Python-Version: ${python:Versions}
Description: Python module for PostgreSQL
psycopg is a PostgreSQL database adapter for the Python programming language
(just like pygresql and popy.) This is version 2, a complete rewrite of the
original code to provide new-style classes for connection and cursor objects
and other sweet candies. Like the original, psycopg 2 was written with the
aim of being very small and fast, and stable as a rock.
.
psycopg 2 is the next generation psycopg, implementing a much better
type system and even more DBAPI extensions:
.
* support for Python datetime and Decimal types;
* complete implementation of adapt() from PEP 246 to convert Python
types to PostgreSQL ones;
* COPY FROM/COPY TO support;
* inehritable connection and cursor objects and support for connection
and cursor factories;
* automatic encoding conversion and support for unicode queries.
.
This dummy package just depends on the right, default version of Python
and psycopg 2.
psycopg is different from the other database adapter because it was designed
for heavily multi-threaded applications that create and destroy lots of
cursors and make a conspicuous number of concurrent INSERTs or UPDATEs.
psycopg 2 also provides full asycronous operations for the really brave
programmer.
Package: python2.3-psycopg2
Architecture: any
Package: zope-psycopgda2
Architecture: all
Section: python
Depends: ${shlibs:Depends}, python2.3
Description: Python 2.3 module for PostgreSQL
psycopg is a PostgreSQL database adapter for the Python programming
language. It was written from scratch with the aim of being very small
and fast, and stable as a rock. The main advantages of psycopg are that
it supports the full Python DBAPI-2.0 and being thread safe at level 2.
.
psycopg 2 is the next generation psycopg, implementing a much better
type system and even more DBAPI extensions:
.
* support for Python datetime and Decimal types;
* complete implementation of adapt() from PEP 246 to convert Python
types to PostgreSQL ones;
* COPY FROM/COPY TO support;
* inehritable connection and cursor objects and support for connection
and cursor factories;
* automatic encoding conversion and support for unicode queries.
Depends: ${zope:Depends}, python-psycopg2 (>= ${Source-Version})
Description: Zope database adapter based on python-psycopg
The package contains the PostgreSQL database adapter for Zope 2.7, 2.8 and
2.9 based on the psycopg2 Python module.

106
debian/copyright vendored
View File

@ -1,10 +1,102 @@
psycopg 2 can be downloaded from:
This package was debianized by Fabio Tranchitella <kobold@debian.org> on
Sun, 16 Jul 2006 21:10:01 +0200.
http://initd.org/pub/software/psycopg/ALPHA/
psycopg2 can be downloaded from its homepage:
Copyright (c) 2001-2005 Federico Di Gregorio <fog@debian.org>
http://initd.org/projects/psycopg
The tarball has been re-packed to get rid of the upstream debian/ directory:
no other changes have been made to the tarball.
Copyright:
Copyright (C) 2001-2006 Federico Di Gregorio <fog@debian.org>
Copyright (C) 2001 Michele Comitini <mcm@initd.org>
For the files doc/copy_from.py and doc/copy_to.py:
Copyright (C) 2001-2005 Federico Di Gregorio <fog@debian.org>
Copyright (C) 2002 Tom Jenkins <tjenkins@devis.com>
For the file tests/dbapi20.py:
Copyright (C) 2003 Ian Bicking <ianb@colorstudy.com>
For the file scripts/ext2html.py:
Copyright (C) 2003 Daniele Varrazzo <daniele.varrazzo@gmail.com>
License for psycopg2 and ZPsycopgDA:
psycopg is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
On Debian GNU/Linux systems, the complete text of the GNU General
Public License can be found in '/usr/share/common-licenses/GPL'.
As a special exception, specific permission is granted for the GPLed
code in this distribition to be linked to OpenSSL and PostgreSQL libpq
without invoking GPL clause 2(b).
Note that the GPL was chosen to avoid proprietary adapters based on
psycopg code. Using psycopg in a proprietary product (even bundling
psycopg with the proprietary product) is fine as long as:
1. psycopg is called from Python only using only the provided API
(i.e., no linking with C code and no C modules based on it); and
2. all the other points of the GPL are respected (you offer a copy
of psycopg's source code, and so on.)
License for the files tests/dbapi20.py and scripts/ext2html.py:
These modules have been placed in the public domain.
Alternative licenses for ZPsycopgDA:
If you prefer you can use the Zope Database Adapter ZPsycopgDA (i.e.,
every file inside the ZPsycopgDA directory) user the ZPL license as
published on the Zope web site, http://www.zope.org/Resources/ZPL.
Alternative licenses for psycopg/adapter*.{j,c} and
psycopg/microprotocol*.{h.c}:
Also, the following BSD-like license applies (at your option) to the
files following the pattern psycopg/adapter*.{h,c} and
psycopg/microprotocol*.{h,c}:
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
psycopg is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Proprietary licenses:
A non-exclusive license is available for companies that want to include
psycopg in their proprietary products without respecting the spirit of the
GPL. The price of the license is one day of development done by the author,
at the consulting fee he applies to his usual customers at the day of the
request.
Please contact the upstream author (Federico Di Gregorio <fog@debian.org>)
for more information about this license.
This program is distributed under the GNU GPL.
On Debian GNU/Linux systems, the complete text of the GNU General
Public License can be found in '/usr/share/common-licenses/GPL'.

1
debian/pycompat vendored Normal file
View File

@ -0,0 +1 @@
2

78
debian/rules vendored
View File

@ -1,4 +1,78 @@
#!/usr/bin/make -f
# Sample debian/rules that uses debhelper.
# GNU copyright 1997 to 1999 by Joey Hess.
include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/class/python-distutils.mk
PYVERS=$(shell pyversions -r debian/control)
configure: configure-stamp
configure-stamp:
dh_testdir
rm -f configure
touch configure-stamp
build: configure build-stamp
build-stamp:
dh_testdir
for python in $(PYVERS); do \
$$python setup.py build ; \
done
touch build-stamp
clean: configure
dh_testdir
dh_testroot
rm -fr *-stamp build
for python in $(PYVERS); do \
$$python setup.py clean ; \
done
dh_clean
install-arch: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
# psycopg2
for python in $(PYVERS); \
do $$python setup.py install --root=$(CURDIR)/debian/python-psycopg2 --no-compile; \
done
install-indep: build
# Zope package
dh_installzope -p zope-psycopgda2 ZPsycopgDA
# Build architecture-independent files here.
binary-indep: build install-indep
dh_testdir
dh_testroot
dh_installdocs -i AUTHORS debian/README.zpsycopgda2
dh_installchangelogs -i
dh_link -i
dh_compress -i
dh_fixperms -i
dh_installdeb -i
dh_gencontrol -i
dh_md5sums -i
dh_builddeb -i
# Build architecture-dependent files here.
binary-arch: build install-arch
dh_testdir
dh_testroot
dh_installdocs -a README AUTHORS doc tests
dh_installchangelogs -a ChangeLog
dh_link -a
dh_strip -a
dh_compress -a
dh_fixperms -a
dh_makeshlibs -a
dh_pycentral -a
dh_python -a
dh_installdeb -a
dh_shlibdeps -a
dh_gencontrol -a
dh_md5sums -a
dh_builddeb -a
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure

4
debian/zope-psycopgda2.dzproduct vendored Normal file
View File

@ -0,0 +1,4 @@
Name: ZPsycopgDA
Directory: ZPsycopgDA:2
Package: zope-psycopgda2
ZopeVersions: 2.9 2.8 2.7

324
lib/errorcodes.py Normal file
View File

@ -0,0 +1,324 @@
"""Error codes for PostgresSQL
This module contains symbolic names for all PostgreSQL error codes.
"""
# psycopg2/errorcodes.py - PostgreSQL error codes
#
# Copyright (C) 2006 Johan Dahlin <jdahlin@async.com.br>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# Based on:
#
# http://www.postgresql.org/docs/8.1/static/errcodes-appendix.html
#
# Error classes
CLASS_SUCCESSFUL_COMPLETION = '00'
CLASS_WARNING = '01'
CLASS_NO_DATA = '02'
CLASS_SQL_STATEMENT_NOT_YET_COMPLETE = '03'
CLASS_CONNECTION_EXCEPTION = '08'
CLASS_TRIGGERED_ACTION_EXCEPTION = '09'
CLASS_FEATURE_NOT_SUPPORTED = '0A'
CLASS_INVALID_TRANSACTION_INITIATION = '0B'
CLASS_LOCATOR_EXCEPTION = '0F'
CLASS_INVALID_GRANTOR = '0L'
CLASS_INVALID_ROLE_SPECIFICATION = '0P'
CLASS_CARDINALITY_VIOLATION = '21'
CLASS_DATA_EXCEPTION = '22'
CLASS_INTEGRITY_CONSTRAINT_VIOLATION = '23'
CLASS_INVALID_CURSOR_STATE = '24'
CLASS_INVALID_TRANSACTION_STATE = '25'
CLASS_INVALID_SQL_STATEMENT_NAME = '26'
CLASS_TRIGGERED_DATA_CHANGE_VIOLATION = '27'
CLASS_INVALID_AUTHORIZATION_SPECIFICATION = '28'
CLASS_DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST = '2B'
CLASS_INVALID_TRANSACTION_TERMINATION = '2D'
CLASS_SQL_ROUTINE_EXCEPTION = '2F'
CLASS_INVALID_CURSOR_NAME = '34'
CLASS_EXTERNAL_ROUTINE_EXCEPTION = '38'
CLASS_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION = '39'
CLASS_SAVEPOINT_EXCEPTION = '3B'
CLASS_INVALID_CATALOG_NAME = '3D'
CLASS_INVALID_SCHEMA_NAME = '3F'
CLASS_TRANSACTION_ROLLBACK = '40'
CLASS_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION = '42'
CLASS_WITH_CHECK_OPTION_VIOLATION = '44'
CLASS_INSUFFICIENT_RESOURCES = '53'
CLASS_PROGRAM_LIMIT_EXCEEDED = '54'
CLASS_OBJECT_NOT_IN_PREREQUISITE_STATE = '55'
CLASS_OPERATOR_INTERVENTION = '57'
CLASS_SYSTEM_ERROR = '58'
CLASS_CONFIGURATION_FILE_ERROR = 'F0'
CLASS_PL_PGSQL_ERROR = 'P0'
CLASS_INTERNAL_ERROR = 'XX'
# Class 00 - Successful Completion
SUCCESSFUL_COMPLETION = '00'
# Class 01 - Warning
WARNING = '01000'
DYNAMIC_RESULT_SETS_RETURNED = '0100C'
IMPLICIT_ZERO_BIT_PADDING = '01008'
NULL_VALUE_ELIMINATED_IN_SET_FUNCTION = '01003'
PRIVILEGE_NOT_GRANTED = '01007'
PRIVILEGE_NOT_REVOKED = '01006'
STRING_DATA_RIGHT_TRUNCATION = '01004'
DEPRECATED_FEATURE = '01P01'
# Class 02 - No Data (this is also a warning class per the SQL standard)
NO_DATA = '02000'
NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED = '02001'
# Class 03 - SQL Statement Not Yet Complete
SQL_STATEMENT_NOT_YET_COMPLETE = '03000'
# Class 08 - Connection Exception
CONNECTION_EXCEPTION = '08000'
CONNECTION_DOES_NOT_EXIST = '08003'
CONNECTION_FAILURE = '08006'
SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION = '08001'
SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION = '08004'
TRANSACTION_RESOLUTION_UNKNOWN = '08007'
PROTOCOL_VIOLATION = '08P01'
# Class 09 - Triggered Action Exception
TRIGGERED_ACTION_EXCEPTION = '09000'
# Class 0A - Feature Not Supported
FEATURE_NOT_SUPPORTED = '0A000'
# Class 0B - Invalid Transaction Initiation
INVALID_TRANSACTION_INITIATION = '0B000'
# Class 0F - Locator Exception
LOCATOR_EXCEPTION = '0F000'
INVALID_LOCATOR_SPECIFICATION = '0F001'
# Class 0L - Invalid Grantor
INVALID_GRANTOR = '0L000'
INVALID_GRANT_OPERATION = '0LP01'
# Class 0P - Invalid Role Specification
INVALID_ROLE_SPECIFICATION = '0P000'
# Class 21 - Cardinality Violation
CARDINALITY_VIOLATION = '21000'
# Class 22 - Data Exception
DATA_EXCEPTION = '22000'
ARRAY_SUBSCRIPT_ERROR = '2202E'
CHARACTER_NOT_IN_REPERTOIRE = '22021'
DATETIME_FIELD_OVERFLOW = '22008'
DIVISION_BY_ZERO = '22012'
ERROR_IN_ASSIGNMENT = '22005'
ESCAPE_CHARACTER_CONFLICT = '2200B'
INDICATOR_OVERFLOW = '22022'
INTERVAL_FIELD_OVERFLOW = '22015'
INVALID_ARGUMENT_FOR_LOGARITHM = '2201E'
INVALID_ARGUMENT_FOR_POWER_FUNCTION = '2201F'
INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION = '2201G'
INVALID_CHARACTER_VALUE_FOR_CAST = '22018'
INVALID_DATETIME_FORMAT = '22007'
INVALID_ESCAPE_CHARACTER = '22019'
INVALID_ESCAPE_OCTET = '2200D'
INVALID_ESCAPE_SEQUENCE = '22025'
NONSTANDARD_USE_OF_ESCAPE_CHARACTER = '22P06'
INVALID_INDICATOR_PARAMETER_VALUE = '22010'
INVALID_LIMIT_VALUE = '22020'
INVALID_PARAMETER_VALUE = '22023'
INVALID_REGULAR_EXPRESSION = '2201B'
INVALID_TIME_ZONE_DISPLACEMENT_VALUE = '22009'
INVALID_USE_OF_ESCAPE_CHARACTER = '2200C'
MOST_SPECIFIC_TYPE_MISMATCH = '2200G'
NULL_VALUE_NOT_ALLOWED = '22004'
NULL_VALUE_NO_INDICATOR_PARAMETER = '22002'
NUMERIC_VALUE_OUT_OF_RANGE = '22003'
STRING_DATA_LENGTH_MISMATCH = '22026'
STRING_DATA_RIGHT_TRUNCATION = '22001'
SUBSTRING_ERROR = '22011'
TRIM_ERROR = '22027'
UNTERMINATED_C_STRING = '22024'
ZERO_LENGTH_CHARACTER_STRING = '2200F'
FLOATING_POINT_EXCEPTION = '22P01'
INVALID_TEXT_REPRESENTATION = '22P02'
INVALID_BINARY_REPRESENTATION = '22P03'
BAD_COPY_FILE_FORMAT = '22P04'
UNTRANSLATABLE_CHARACTER = '22P05'
# Class 23 - Integrity Constraint Violation
INTEGRITY_CONSTRAINT_VIOLATION = '23000'
RESTRICT_VIOLATION = '23001'
NOT_NULL_VIOLATION = '23502'
FOREIGN_KEY_VIOLATION = '23503'
UNIQUE_VIOLATION = '23505'
CHECK_VIOLATION = '23514'
# Class 24 - Invalid Cursor State
INVALID_CURSOR_STATE = '24000'
# Class 25 - Invalid Transaction State
INVALID_TRANSACTION_STATE = '25000'
ACTIVE_SQL_TRANSACTION = '25001'
BRANCH_TRANSACTION_ALREADY_ACTIVE = '25002'
HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL = '25008'
INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION = '25003'
INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION = '25004'
NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION = '25005'
READ_ONLY_SQL_TRANSACTION = '25006'
SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED = '25007'
NO_ACTIVE_SQL_TRANSACTION = '25P01'
IN_FAILED_SQL_TRANSACTION = '25P02'
# Class 26 - Invalid SQL Statement Name
INVALID_SQL_STATEMENT_NAME = '26000'
# Class 27 - Triggered Data Change Violation
TRIGGERED_DATA_CHANGE_VIOLATION = '27000'
# Class 28 - Invalid Authorization Specification
INVALID_AUTHORIZATION_SPECIFICATION = '28000'
# Class 2B - Dependent Privilege Descriptors Still Exist
DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST = '2B000'
DEPENDENT_OBJECTS_STILL_EXIST = '2BP01'
# Class 2D - Invalid Transaction Termination
INVALID_TRANSACTION_TERMINATION = '2D000'
# Class 2F - SQL Routine Exception
SQL_ROUTINE_EXCEPTION = '2F000'
FUNCTION_EXECUTED_NO_RETURN_STATEMENT = '2F005'
MODIFYING_SQL_DATA_NOT_PERMITTED = '2F002'
PROHIBITED_SQL_STATEMENT_ATTEMPTED = '2F003'
READING_SQL_DATA_NOT_PERMITTED = '2F004'
# Class 34 - Invalid Cursor Name
INVALID_CURSOR_NAME = '34000'
# Class 38 - External Routine Exception
EXTERNAL_ROUTINE_EXCEPTION = '38000'
CONTAINING_SQL_NOT_PERMITTED = '38001'
MODIFYING_SQL_DATA_NOT_PERMITTED = '38002'
PROHIBITED_SQL_STATEMENT_ATTEMPTED = '38003'
READING_SQL_DATA_NOT_PERMITTED = '38004'
# Class 39 - External Routine Invocation Exception
EXTERNAL_ROUTINE_INVOCATION_EXCEPTION = '39000'
INVALID_SQLSTATE_RETURNED = '39001'
NULL_VALUE_NOT_ALLOWED = '39004'
TRIGGER_PROTOCOL_VIOLATED = '39P01'
SRF_PROTOCOL_VIOLATED = '39P02'
# Class 3B - Savepoint Exception
SAVEPOINT_EXCEPTION = '3B000'
INVALID_SAVEPOINT_SPECIFICATION = '3B001'
# Class 3D - Invalid Catalog Name
INVALID_CATALOG_NAME = '3D000'
# Class 3F - Invalid Schema Name
INVALID_SCHEMA_NAME = '3F000'
# Class 40 - Transaction Rollback
TRANSACTION_ROLLBACK = '40000'
TRANSACTION_INTEGRITY_CONSTRAINT_VIOLATION = '40002'
SERIALIZATION_FAILURE = '40001'
STATEMENT_COMPLETION_UNKNOWN = '40003'
DEADLOCK_DETECTED = '40P01'
# Class 42 - Syntax Error or Access Rule Violation
SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION = '42000'
SYNTAX_ERROR = '42601'
INSUFFICIENT_PRIVILEGE = '42501'
CANNOT_COERCE = '42846'
GROUPING_ERROR = '42803'
INVALID_FOREIGN_KEY = '42830'
INVALID_NAME = '42602'
NAME_TOO_LONG = '42622'
RESERVED_NAME = '42939'
DATATYPE_MISMATCH = '42804'
INDETERMINATE_DATATYPE = '42P18'
WRONG_OBJECT_TYPE = '42809'
UNDEFINED_COLUMN = '42703'
UNDEFINED_FUNCTION = '42883'
UNDEFINED_TABLE = '42P01'
UNDEFINED_PARAMETER = '42P02'
UNDEFINED_OBJECT = '42704'
DUPLICATE_COLUMN = '42701'
DUPLICATE_CURSOR = '42P03'
DUPLICATE_DATABASE = '42P04'
DUPLICATE_FUNCTION = '42723'
DUPLICATE_PREPARED_STATEMENT = '42P05'
DUPLICATE_SCHEMA = '42P06'
DUPLICATE_TABLE = '42P07'
DUPLICATE_ALIAS = '42712'
DUPLICATE_OBJECT = '42710'
AMBIGUOUS_COLUMN = '42702'
AMBIGUOUS_FUNCTION = '42725'
AMBIGUOUS_PARAMETER = '42P08'
AMBIGUOUS_ALIAS = '42P09'
INVALID_COLUMN_REFERENCE = '42P10'
INVALID_COLUMN_DEFINITION = '42611'
INVALID_CURSOR_DEFINITION = '42P11'
INVALID_DATABASE_DEFINITION = '42P12'
INVALID_FUNCTION_DEFINITION = '42P13'
INVALID_PREPARED_STATEMENT_DEFINITION = '42P14'
INVALID_SCHEMA_DEFINITION = '42P15'
INVALID_TABLE_DEFINITION = '42P16'
INVALID_OBJECT_DEFINITION = '42P17'
# Class 44 - WITH CHECK OPTION Violation
WITH_CHECK_OPTION_VIOLATION = '44000'
# Class 53 - Insufficient Resources
INSUFFICIENT_RESOURCES = '53000'
DISK_FULL = '53100'
OUT_OF_MEMORY = '53200'
TOO_MANY_CONNECTIONS = '53300'
# Class 54 - Program Limit Exceeded
PROGRAM_LIMIT_EXCEEDED = '54000'
STATEMENT_TOO_COMPLEX = '54001'
TOO_MANY_COLUMNS = '54011'
TOO_MANY_ARGUMENTS = '54023'
# Class 55 - Object Not In Prerequisite State
OBJECT_NOT_IN_PREREQUISITE_STATE = '55000'
OBJECT_IN_USE = '55006'
CANT_CHANGE_RUNTIME_PARAM = '55P02'
LOCK_NOT_AVAILABLE = '55P03'
# Class 57 - Operator Intervention
OPERATOR_INTERVENTION = '57000'
QUERY_CANCELED = '57014'
ADMIN_SHUTDOWN = '57P01'
CRASH_SHUTDOWN = '57P02'
CANNOT_CONNECT_NOW = '57P03'
# Class 58 - System Error (errors external to PostgreSQL itself)
IO_ERROR = '58030'
UNDEFINED_FILE = '58P01'
DUPLICATE_FILE = '58P02'
# Class F0 - Configuration File Error
CONFIG_FILE_ERROR = 'F0000'
LOCK_FILE_EXISTS = 'F0001'
# Class P0 - PL/pgSQL Error
PLPGSQL_ERROR = 'P0000'
RAISE_EXCEPTION = 'P0001'
# Class XX - Internal Error
INTERNAL_ERROR = 'XX000'
DATA_CORRUPTED = 'XX001'
INDEX_CORRUPTED = 'XX002'

View File

@ -31,7 +31,7 @@ extern "C" {
extern PyTypeObject asisType;
typedef struct {
PyObject HEAD;
PyObject_HEAD;
/* this is the real object we wrap */
PyObject *wrapped;

View File

@ -134,7 +134,7 @@ binary_quote(binaryObject *self)
{
char *to;
const char *buffer;
int buffer_len;
Py_ssize_t buffer_len;
size_t len = 0;
/* if we got a plain string or a buffer we escape it and save the buffer */

View File

@ -32,7 +32,7 @@ extern "C" {
extern PyTypeObject binaryType;
typedef struct {
PyObject HEAD;
PyObject_HEAD;
PyObject *wrapped;
PyObject *buffer;

View File

@ -277,25 +277,26 @@ psyco_Date(PyObject *self, PyObject *args)
PyObject *
psyco_Time(PyObject *self, PyObject *args)
{
PyObject *res = NULL;
PyObject *res = NULL;
PyObject *tzinfo = NULL;
int hours, minutes=0;
double micro, seconds=0.0;
double micro, second=0.0;
PyObject* obj = NULL;
if (!PyArg_ParseTuple(args, "iid|O", &hours, &minutes, &seconds,
if (!PyArg_ParseTuple(args, "iid|O", &hours, &minutes, &second,
&tzinfo))
return NULL;
micro = (seconds - floor(seconds)) * 1000000.0;
micro = (second - floor(second)) * 1000000.0;
second = floor(second);
if (tzinfo == NULL)
obj = PyObject_CallFunction(pyTimeTypeP, "iiii",
hours, minutes, (int)round(seconds), (int)round(micro));
hours, minutes, (int)second, (int)round(micro));
else
obj = PyObject_CallFunction(pyTimeTypeP, "iiiiO",
hours, minutes, (int)round(seconds), (int)round(micro), tzinfo);
hours, minutes, (int)second, (int)round(micro), tzinfo);
if (obj) {
res = PyObject_CallFunction((PyObject *)&pydatetimeType,
@ -309,11 +310,11 @@ psyco_Time(PyObject *self, PyObject *args)
PyObject *
psyco_Timestamp(PyObject *self, PyObject *args)
{
PyObject *res = NULL;
PyObject *res = NULL;
PyObject *tzinfo = NULL;
int year, month, day;
int hour=0, minute=0; /* default to midnight */
double micro, second=0.0;
int hour=0, minute=0; /* default to midnight */
double micro, second=0.0;
PyObject* obj = NULL;
@ -322,14 +323,15 @@ psyco_Timestamp(PyObject *self, PyObject *args)
return NULL;
micro = (second - floor(second)) * 1000000.0;
second = floor(second);
if (tzinfo == NULL)
obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiii",
year, month, day, hour, minute, (int)round(second),
year, month, day, hour, minute, (int)second,
(int)round(micro));
else
obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiiiO",
year, month, day, hour, minute, (int)round(second),
year, month, day, hour, minute, (int)second,
(int)round(micro), tzinfo);
if (obj) {
@ -375,8 +377,10 @@ psyco_TimeFromTicks(PyObject *self, PyObject *args)
return NULL;
t = (time_t)round(ticks);
ticks -= (double)t;
if (localtime_r(&t, &tm)) {
args = Py_BuildValue("iid", tm.tm_hour, tm.tm_min, (double)tm.tm_sec);
args = Py_BuildValue("iid", tm.tm_hour, tm.tm_min,
(double)tm.tm_sec + ticks);
if (args) {
res = psyco_Time(self, args);
Py_DECREF(args);
@ -397,10 +401,12 @@ psyco_TimestampFromTicks(PyObject *self, PyObject *args)
return NULL;
t = (time_t)round(ticks);
ticks -= (double)t;
if (localtime_r(&t, &tm)) {
args = Py_BuildValue("iiiiidO",
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, (double)tm.tm_sec,
tm.tm_hour, tm.tm_min,
(double)tm.tm_sec + ticks,
pyPsycopgTzLOCAL);
if (args) {
res = psyco_Timestamp(self, args);

View File

@ -31,7 +31,7 @@ extern "C" {
extern PyTypeObject pydatetimeType;
typedef struct {
PyObject HEAD;
PyObject_HEAD;
PyObject *wrapped;
int type;

View File

@ -40,7 +40,7 @@ list_quote(listObject *self)
/* adapt the list by calling adapt() recursively and then wrapping
everything into "ARRAY[]" */
PyObject *tmp = NULL, *str = NULL, *joined = NULL, *res = NULL;
int i, len;
Py_ssize_t i, len;
len = PyList_GET_SIZE(self->wrapped);

View File

@ -31,7 +31,7 @@ extern "C" {
extern PyTypeObject listType;
typedef struct {
PyObject HEAD;
PyObject_HEAD;
PyObject *wrapped;
PyObject *connection;

View File

@ -31,7 +31,7 @@ extern "C" {
extern PyTypeObject mxdatetimeType;
typedef struct {
PyObject HEAD;
PyObject_HEAD;
PyObject *wrapped;
int type;

View File

@ -31,7 +31,7 @@ extern "C" {
extern PyTypeObject pbooleanType;
typedef struct {
PyObject HEAD;
PyObject_HEAD;
/* this is the real object we wrap */
PyObject *wrapped;

View File

@ -92,7 +92,7 @@ qstring_quote(qstringObject *self)
{
PyObject *str;
char *s, *buffer;
int len;
Py_ssize_t len;
/* if the wrapped object is an unicode object we can encode it to match
self->encoding but if the encoding is not specified we don't know what

View File

@ -31,7 +31,7 @@ extern "C" {
extern PyTypeObject qstringType;
typedef struct {
PyObject HEAD;
PyObject_HEAD;
PyObject *wrapped;
PyObject *buffer;

View File

@ -38,7 +38,7 @@ extern "C" {
extern PyTypeObject connectionType;
typedef struct {
PyObject HEAD;
PyObject_HEAD;
pthread_mutex_t lock; /* the global connection lock */

View File

@ -34,7 +34,7 @@ extern "C" {
extern PyTypeObject cursorType;
typedef struct {
PyObject HEAD;
PyObject_HEAD;
connectionObject *conn; /* connection owning the cursor */

View File

@ -77,7 +77,8 @@ _mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new)
{
PyObject *key, *value, *n, *item;
char *d, *c;
int index = 0, force = 0;
Py_ssize_t index = 0;
int force = 0;
/* from now on we'll use n and replace its value in *new only at the end,
just before returning. we also init *new to NULL to exit with an error
@ -872,7 +873,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
{
char *procname = NULL, *sql = NULL;
long int async = 0;
int i, nparameters = 0, sl = 0;
Py_ssize_t i, nparameters = 0, sl = 0;
PyObject *parameters = NULL;
PyObject *operation = NULL;
PyObject *res = NULL;
@ -1090,7 +1091,7 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
PyObject* collistiter = PyObject_GetIter(columns);
PyObject* col;
int collistlen = 2;
int colitemlen;
Py_ssize_t colitemlen;
char* colname;
if (collistiter == NULL) {
return NULL;

View File

@ -32,7 +32,7 @@ extern "C" {
extern PyTypeObject isqlquoteType;
typedef struct {
PyObject HEAD;
PyObject_HEAD;
PyObject *wrapped;

View File

@ -590,7 +590,8 @@ _pq_copy_in_v3(cursorObject *curs)
uses the new PQputCopyData() and can detect errors and set the correct
exception */
PyObject *o;
int length = 0, error = 0;
Py_ssize_t length = 0;
int error = 0;
while (1) {
o = PyObject_CallMethod(curs->copyfile, "read", "i", curs->copysize);

View File

@ -28,6 +28,13 @@
extern "C" {
#endif
/* Python 2.5 ssize_t compatibility */
#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
typedef int Py_ssize_t;
#define PY_SSIZE_T_MAX INT_MAX
#define PY_SSIZE_T_MIN INT_MIN
#endif
/* DBAPI compliance parameters */
#define APILEVEL "2.0"
#define THREADSAFETY 2

View File

@ -267,7 +267,7 @@ int
typecast_add(PyObject *obj, int binary)
{
PyObject *val;
int len, i;
Py_ssize_t len, i;
typecastObject *type = (typecastObject *)obj;
@ -302,7 +302,8 @@ typecast_cmp(PyObject *obj1, PyObject* obj2)
typecastObject *self = (typecastObject*)obj1;
typecastObject *other = NULL;
PyObject *number = NULL;
int i, j, res = -1;
Py_ssize_t i, j;
int res = -1;
if (PyObject_TypeCheck(obj2, &typecastType)) {
other = (typecastObject*)obj2;
@ -505,7 +506,7 @@ typecast_from_c(typecastObject_initlist *type, PyObject *dict)
{
PyObject *tuple, *base = NULL;
typecastObject *obj;
int i, len = 0;
Py_ssize_t i, len = 0;
/* before doing anything else we look for the base */
if (type->base) {
@ -538,7 +539,7 @@ typecast_from_c(typecastObject_initlist *type, PyObject *dict)
}
PyObject *
typecast_cast(PyObject *obj, char *str, int len, PyObject *curs)
typecast_cast(PyObject *obj, char *str, Py_ssize_t len, PyObject *curs)
{
PyObject *old, *res = NULL;
typecastObject *self = (typecastObject *)obj;

View File

@ -80,6 +80,6 @@ extern PyObject *typecast_from_python(
/* the function used to dispatch typecasting calls */
extern PyObject *typecast_cast(
PyObject *self, char *str, int len, PyObject *curs);
PyObject *self, char *str, Py_ssize_t len, PyObject *curs);
#endif /* !defined(PSYCOPG_TYPECAST_H) */

View File

@ -0,0 +1,2 @@
psycopg2
zope.app

24
psycopg2da/PACKAGE.cfg Normal file
View File

@ -0,0 +1,24 @@
# Load the license from an external source, so we don't have to keep a
# copy of it sitting around:
<load>
LICENSE.txt http://svn.zope.org/*checkout*/Zope3/trunk/ZopePublicLicense.txt?rev=25177
</load>
# Add a few things to the distribution root.
<distribution>
README.txt
</distribution>
# Specify what is included in the component.
<collection>
# Documentation files of the package:
*.txt
# Python modules from the package:
*.py
# Configuration files of the package:
*.zcml
</collection>

View File

@ -0,0 +1,9 @@
Metadata-Version: 1.0
Name: psycopg2da
Summary: Psycopg2 Database Adapter for Zope 3
Author: Fabio Tranchitella
Author-email: kobold@debian.org
License: ZPL 2.1
Description:
This package allows Zope 3 to connect to any PostGreSQL database via
the common Zope 3 RDB connection facilities.

79
psycopg2da/README.txt Normal file
View File

@ -0,0 +1,79 @@
==========
psycopg2da
==========
This file outlines the basics of using Zope3 with PostgreSQL via PsycopgDA.
Installing PsycopgDA
--------------------
1. Check out the psycopg2da package into a directory in your
PYTHONPATH. INSTANCE_HOME/lib/python or Zope3/src is usually the
most convenient place:
svn co svn://svn.zope.org/repos/main/psycopg2da/trunk psycopg2da
2. Copy `psycopg2-configure.zcml` to the `package-includes` directory
of your Zope instance.
Creating Database Connections
------------------------------
It is time to add some connections. A connection in Zope 3 is
registered as a utility.
3. Open a web browser on your Zope root folder (http://localhost:8080/
if you use the default settings in zope.conf.in).
4. Click on the 'Manage Site' action on the right side of the
screen. You should see a screen which reads 'Common Site Management
Tasks'
5. Around the middle of that page, you should see a link named 'Add
Utility'. Click on it.
6. Select 'Psycopg DA' and type in a name at the bottom of the page.
7. Enter the database connection string. It looks like this:
dbi://username:password@host:port/databasename
8. Click on the 'Add' button.
9. You should be on a page which reads 'Add Database Connection
Registration'. There you can configure the permission needed to use
the database connection, the name of the registration and the
registration status. You can use any name for 'Register As' field,
as long as it doesn't clash with an existing one. Choose a
permission. Choose between 'Registered' and 'Active' for the
'Registration Status'. Only one component of a kind can be 'Active'
at a time, so be careful.
10. You should be redirected to the 'Edit' screen of the connection
utility.
11. If you want to, you can go to the Test page and execute arbitrary
SQL queries to see whether the connection is working as expected.
Using SQL Scripts
-----------------
You can create SQL Scripts in the content space. For example:
12. Go to Zope root.
13. Add an SQL script (you can use the Common Tasks box on the left,
or the Add action on the right).
14. Click on the name of your new SQL script.
15. Choose a connection name (the one you entered in step 29) from the
drop-down.
16. Enter your query and click on the 'Save Changes' button.
17. You can test the script in the -- surprise! -- Test page.

0
psycopg2da/__init__.py Normal file
View File

425
psycopg2da/adapter.py Normal file
View File

@ -0,0 +1,425 @@
# psycopg2da
# Copyright (C) 2006 Fabio Tranchitella <fabio@tranchitella.it>
#
# Based on psycopgda:
#
# Copyright (c) 2002-2006 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# If you prefer you can use this package using the ZPL license as
# published on the Zope web site, http://www.zope.org/Resources/ZPL.
#
"""PostgreSQL Database Adapter for Zope 3"""
from zope.interface import implements
from zope.rdb import ZopeDatabaseAdapter, parseDSN, ZopeConnection, ZopeCursor
from zope.rdb.interfaces import DatabaseException, IZopeConnection
from zope.publisher.interfaces import Retry
from datetime import date, time, datetime, timedelta
import psycopg2
import psycopg2.extensions
import re
import sys
# OIDs from psycopg/pgtypes.h
DATE_OID = 1082
TIME_OID = 1083
TIMETZ_OID = 1266
TIMESTAMP_OID = 1114
TIMESTAMPTZ_OID = 1184
INTERVAL_OID = 1186
CHAR_OID = 18
TEXT_OID = 25
BPCHAR_OID = 1042
VARCHAR_OID = 1043
# date/time parsing functions
_dateFmt = re.compile(r"^(\d\d\d\d)-?([01]\d)-?([0-3]\d)$")
def parse_date(s):
"""Parses ISO-8601 compliant dates and returns a tuple (year, month,
day).
The following formats are accepted:
YYYY-MM-DD (extended format)
YYYYMMDD (basic format)
"""
m = _dateFmt.match(s)
if m is None:
raise ValueError, 'invalid date string: %s' % s
year, month, day = m.groups()
return int(year), int(month), int(day)
_timeFmt = re.compile(
r"^([0-2]\d)(?::?([0-5]\d)(?::?([0-5]\d)(?:[.,](\d+))?)?)?$")
def parse_time(s):
"""Parses ISO-8601 compliant times and returns a tuple (hour, minute,
second).
The following formats are accepted:
HH:MM:SS.ssss or HHMMSS.ssss
HH:MM:SS,ssss or HHMMSS,ssss
HH:MM:SS or HHMMSS
HH:MM or HHMM
HH
"""
m = _timeFmt.match(s)
if m is None:
raise ValueError, 'invalid time string: %s' % s
hr, mn, sc, msc = m.groups(0)
if msc != 0:
sc = float("%s.%s" % (sc, msc))
else:
sc = int(sc)
return int(hr), int(mn), sc
_tzFmt = re.compile(r"^([+-])([0-2]\d)(?::?([0-5]\d))?$")
def parse_tz(s):
"""Parses ISO-8601 timezones and returns the offset east of UTC in
minutes.
The following formats are accepted:
+/-HH:MM
+/-HHMM
+/-HH
Z (equivalent to +0000)
"""
if s == 'Z':
return 0
m = _tzFmt.match(s)
if m is None:
raise ValueError, 'invalid time zone: %s' % s
d, hoff, moff = m.groups(0)
if d == "-":
return - int(hoff) * 60 - int(moff)
return int(hoff) * 60 + int(moff)
_tzPos = re.compile(r"[Z+-]")
def parse_timetz(s):
"""Parses ISO-8601 compliant times that may include timezone information
and returns a tuple (hour, minute, second, tzoffset).
tzoffset is the offset east of UTC in minutes. It will be None if s does
not include time zone information.
Formats accepted are those listed in the descriptions of parse_time() and
parse_tz(). Time zone should immediatelly follow time without intervening
spaces.
"""
m = _tzPos.search(s)
if m is None:
return parse_time(s) + (None,)
pos = m.start()
return parse_time(s[:pos]) + (parse_tz(s[pos:]),)
_datetimeFmt = re.compile(r"[T ]")
def _split_datetime(s):
"""Split date and time parts of ISO-8601 compliant timestamp and
return a tuple (date, time).
' ' or 'T' used to separate date and time parts.
"""
m = _datetimeFmt.search(s)
if m is None:
raise ValueError, 'time part of datetime missing: %s' % s
pos = m.start()
return s[:pos], s[pos + 1:]
def parse_datetime(s):
"""Parses ISO-8601 compliant timestamp and returns a tuple (year, month,
day, hour, minute, second).
Formats accepted are those listed in the descriptions of parse_date() and
parse_time() with ' ' or 'T' used to separate date and time parts.
"""
dt, tm = _split_datetime(s)
return parse_date(dt) + parse_time(tm)
def parse_datetimetz(s):
"""Parses ISO-8601 compliant timestamp that may include timezone
information and returns a tuple (year, month, day, hour, minute, second,
tzoffset).
tzoffset is the offset east of UTC in minutes. It will be None if s does
not include time zone information.
Formats accepted are those listed in the descriptions of parse_date() and
parse_timetz() with ' ' or 'T' used to separate date and time parts.
"""
dt, tm = _split_datetime(s)
return parse_date(dt) + parse_timetz(tm)
def parse_interval(s):
"""Parses PostgreSQL interval notation and returns a tuple (years, months,
days, hours, minutes, seconds).
Values accepted:
interval ::= date
| time
| date time
date ::= date_comp
| date date_comp
date_comp ::= 1 'day'
| number 'days'
| 1 'month'
| 1 'mon'
| number 'months'
| number 'mons'
| 1 'year'
| number 'years'
time ::= number ':' number
| number ':' number ':' number
| number ':' number ':' number '.' fraction
"""
years = months = days = 0
hours = minutes = seconds = 0
elements = s.split()
# Tests with 7.4.6 on Ubuntu 5.4 interval output returns 'mon' and 'mons'
# and not 'month' or 'months' as expected. I've fixed this and left
# the original matches there too in case this is dependant on
# OS or PostgreSQL release.
for i in range(0, len(elements) - 1, 2):
count, unit = elements[i:i+2]
if unit == 'day' and count == '1':
days += 1
elif unit == 'days':
days += int(count)
elif unit == 'month' and count == '1':
months += 1
elif unit == 'mon' and count == '1':
months += 1
elif unit == 'months':
months += int(count)
elif unit == 'mons':
months += int(count)
elif unit == 'year' and count == '1':
years += 1
elif unit == 'years':
years += int(count)
else:
raise ValueError, 'unknown time interval %s %s' % (count, unit)
if len(elements) % 2 == 1:
hours, minutes, seconds = parse_time(elements[-1])
return (years, months, days, hours, minutes, seconds)
# Type conversions
def _conv_date(s, cursor):
if s:
return date(*parse_date(s))
def _conv_time(s, cursor):
if s:
hr, mn, sc = parse_time(s)
sc, micro = divmod(sc, 1.0)
micro = round(micro * 1000000)
return time(hr, mn, int(sc), int(micro))
def _conv_timetz(s, cursor):
if s:
from zope.datetime import tzinfo
hr, mn, sc, tz = parse_timetz(s)
sc, micro = divmod(sc, 1.0)
micro = round(micro * 1000000)
if tz: tz = tzinfo(tz)
return time(hr, mn, int(sc), int(micro), tz)
def _conv_timestamp(s, cursor):
if s:
y, m, d, hr, mn, sc = parse_datetime(s)
sc, micro = divmod(sc, 1.0)
micro = round(micro * 1000000)
return datetime(y, m, d, hr, mn, int(sc), int(micro))
def _conv_timestamptz(s, cursor):
if s:
from zope.datetime import tzinfo
y, m, d, hr, mn, sc, tz = parse_datetimetz(s)
sc, micro = divmod(sc, 1.0)
micro = round(micro * 1000000)
if tz: tz = tzinfo(tz)
return datetime(y, m, d, hr, mn, int(sc), int(micro), tz)
def _conv_interval(s, cursor):
if s:
y, m, d, hr, mn, sc = parse_interval(s)
if (y, m) != (0, 0):
# XXX: Currently there's no way to represent years and months as
# timedeltas
return s
else:
return timedelta(days=d, hours=hr, minutes=mn, seconds=sc)
def _get_string_conv(encoding):
def _conv_string(s, cursor):
if s is not None:
s = s.decode(encoding)
return s
return _conv_string
# User-defined types
DATE = psycopg2.extensions.new_type((DATE_OID,), "ZDATE", _conv_date)
TIME = psycopg2.extensions.new_type((TIME_OID,), "ZTIME", _conv_time)
TIMETZ = psycopg2.extensions.new_type((TIMETZ_OID,), "ZTIMETZ", _conv_timetz)
TIMESTAMP = psycopg2.extensions.new_type((TIMESTAMP_OID,), "ZTIMESTAMP", _conv_timestamp)
TIMESTAMPTZ = psycopg2.extensions.new_type((TIMESTAMPTZ_OID,), "ZTIMESTAMPTZ", _conv_timestamptz)
INTERVAL = psycopg2.extensions.new_type((INTERVAL_OID,), "ZINTERVAL", _conv_interval)
def registerTypes(encoding):
"""Register type conversions for psycopg"""
psycopg2.extensions.register_type(DATE)
psycopg2.extensions.register_type(TIME)
psycopg2.extensions.register_type(TIMETZ)
psycopg2.extensions.register_type(TIMESTAMP)
psycopg2.extensions.register_type(TIMESTAMPTZ)
psycopg2.extensions.register_type(INTERVAL)
STRING = psycopg2.extensions.new_type((CHAR_OID, TEXT_OID, BPCHAR_OID, VARCHAR_OID), "ZSTRING", _get_string_conv(encoding))
psycopg2.extensions.register_type(STRING)
dsn2option_mapping = {'host': 'host',
'port': 'port',
'dbname': 'dbname',
'username': 'user',
'password': 'password'}
class Psycopg2Adapter(ZopeDatabaseAdapter):
"""A psycopg2 adapter for Zope3.
The following type conversions are performed:
DATE -> datetime.date
TIME -> datetime.time
TIMETZ -> datetime.time
TIMESTAMP -> datetime.datetime
TIMESTAMPTZ -> datetime.datetime
XXX: INTERVAL cannot be represented exactly as datetime.timedelta since
it might be something like '1 month', which is a variable number of days.
"""
def connect(self):
if not self.isConnected():
try:
self._v_connection = Psycopg2Connection(
self._connection_factory(), self
)
except psycopg2.Error, error:
raise DatabaseException, str(error)
def registerTypes(self):
registerTypes(self.getEncoding())
def _connection_factory(self):
"""Create a psycopg2 DBI connection based on the DSN"""
self.registerTypes()
conn_info = parseDSN(self.dsn)
conn_list = []
for dsnname, optname in dsn2option_mapping.iteritems():
if conn_info[dsnname]:
conn_list.append('%s=%s' % (optname, conn_info[dsnname]))
conn_str = ' '.join(conn_list)
connection = psycopg2.connect(conn_str)
connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE)
return connection
def disconnect(self):
if self.isConnected():
try:
self._v_connection.close()
except psycopg2.InterfaceError:
pass
self._v_connection = None
def _handle_psycopg_exception(error):
"""Called from a exception handler for psycopg2.Error.
If we have a serialization exception or a deadlock, we should retry the
transaction by raising a Retry exception. Otherwise, we reraise.
"""
if not error.args:
raise
msg = error.args[0]
# These messages are from PostgreSQL 8.0. They may change between
# PostgreSQL releases - if so, the different messages should be added
# rather than the existing ones changed so this logic works with
# different versions.
if msg.startswith(
'ERROR: could not serialize access due to concurrent update'
):
raise Retry(sys.exc_info())
if msg.startswith('ERROR: deadlock detected'):
raise Retry(sys.exc_info())
raise
class IPsycopg2ZopeConnection(IZopeConnection):
"""A marker interface stating that this connection uses PostgreSQL."""
class Psycopg2Connection(ZopeConnection):
implements(IPsycopg2ZopeConnection)
def cursor(self):
"""See IZopeConnection"""
return Psycopg2Cursor(self.conn.cursor(), self)
def commit(self):
try:
ZopeConnection.commit(self)
except psycopg2.Error, error:
_handle_psycopg_exception(error)
class Psycopg2Cursor(ZopeCursor):
def execute(self, operation, parameters=None):
"""See IZopeCursor"""
try:
return ZopeCursor.execute(self, operation, parameters)
except psycopg2.Error, error:
_handle_psycopg_exception(error)
def executemany(operation, seq_of_parameters=None):
"""See IZopeCursor"""
raise RuntimeError, 'Oos'
try:
return ZopeCursor.execute(self, operation, seq_of_parameters)
except psycopg2.Error, error:
_handle_psycopg_exception(error)

51
psycopg2da/configure.zcml Normal file
View File

@ -0,0 +1,51 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
i18n_domain="psycopg2da">
<class class=".adapter.Psycopg2Adapter">
<factory id="zope.da.Psycopg2DA" />
<require
permission="zope.rdb.Use"
interface="zope.rdb.interfaces.IZopeDatabaseAdapter"
/>
<require
permission="zope.ManageServices"
interface="zope.rdb.interfaces.IZopeDatabaseAdapterManagement"
/>
</class>
<class class=".adapter.Psycopg2Connection">
<require
permission="zope.rdb.Use"
interface="zope.rdb.interfaces.IZopeConnection"
/>
</class>
<class class=".adapter.Psycopg2Cursor">
<require
permission="zope.rdb.Use"
interface="zope.rdb.interfaces.IZopeCursor"
/>
</class>
<browser:addform
name="AddPsycopg2DA"
schema="zope.rdb.interfaces.IManageableZopeDatabaseAdapter"
label="Add Psycopg2 (PostGreSQL) Database Adapter"
content_factory=".adapter.Psycopg2Adapter"
arguments="dsn"
fields="dsn"
permission="zope.ManageContent"
/>
<!-- Menu entry for "add utility" menu -->
<browser:addMenuItem
class=".adapter.Psycopg2Adapter"
title="Psycopg2 DA"
description="A PostgreSQL Database Adapter using the Psycopg2 driver"
permission="zope.ManageApplication"
view="AddPsycopg2DA"
/>
</configure>

View File

@ -0,0 +1 @@
<include package="psycopg2da" />

389
psycopg2da/tests.py Normal file
View File

@ -0,0 +1,389 @@
# psycopg2da
# Copyright (C) 2006 Fabio Tranchitella <fabio@tranchitella.it>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""Unit tests for Psycopg2DA."""
from unittest import TestCase, TestSuite, main, makeSuite
from datetime import tzinfo, timedelta
import psycopg2
import psycopg2.extensions
class Stub(object):
def __init__(self, **kw):
self.__dict__.update(kw)
class TZStub(tzinfo):
def __init__(self, h, m):
self.offset = h * 60 + m
def utcoffset(self, dt):
return timedelta(minutes=self.offset)
def dst(self, dt):
return 0
def tzname(self, dt):
return ''
def __repr__(self):
return 'tzinfo(%d)' % self.offset
def __reduce__(self):
return type(self), (), self.__dict__
class ConnectionStub(object):
def set_isolation_level(self, level):
pass
class Psycopg2Stub(object):
__shared_state = {} # 'Borg' design pattern
DATE = psycopg2.extensions.DATE
TIME = psycopg2.extensions.TIME
DATETIME = psycopg2.DATETIME
INTERVAL = psycopg2.extensions.INTERVAL
ISOLATION_LEVEL_SERIALIZABLE = psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE
def __init__(self):
self.__dict__ = self.__shared_state
self.types = {}
def connect(self, connection_string):
self.last_connection_string = connection_string
return ConnectionStub()
def new_type(self, values, name, converter):
return Stub(name=name, values=values)
def register_type(self, type):
for typeid in type.values:
self.types[typeid] = type
def getExtensions(self):
return self
extensions = property(getExtensions)
class TestPsycopg2TypeConversion(TestCase):
def test_conv_date(self):
from psycopg2da.adapter import _conv_date
from datetime import date
def c(s):
return _conv_date(s, None)
self.assertEquals(c(''), None)
self.assertEquals(c('2001-03-02'), date(2001, 3, 2))
def test_conv_time(self):
from psycopg2da.adapter import _conv_time
from datetime import time
def c(s):
return _conv_time(s, None)
self.assertEquals(c(''), None)
self.assertEquals(c('23:17:57'), time(23, 17, 57))
self.assertEquals(c('23:17:57.037'), time(23, 17, 57, 37000))
def test_conv_timetz(self):
from psycopg2da.adapter import _conv_timetz
from datetime import time
def c(s):
return _conv_timetz(s, None)
self.assertEquals(c(''), None)
self.assertEquals(c('12:44:01+01:00'), time(12, 44, 01, 0, TZStub(1,0)))
self.assertEquals(c('12:44:01.037-00:30'), time(12, 44, 01, 37000, TZStub(0,-30)))
def test_conv_timestamp(self):
from psycopg2da.adapter import _conv_timestamp
from datetime import datetime
def c(s):
return _conv_timestamp(s, None)
self.assertEquals(c(''), None)
self.assertEquals(c('2001-03-02 12:44:01'),
datetime(2001, 3, 2, 12, 44, 01))
self.assertEquals(c('2001-03-02 12:44:01.037'),
datetime(2001, 3, 2, 12, 44, 01, 37000))
self.assertEquals(c('2001-03-02 12:44:01.000001'),
datetime(2001, 3, 2, 12, 44, 01, 1))
def test_conv_timestamptz(self):
from psycopg2da.adapter import _conv_timestamptz
from datetime import datetime
def c(s):
return _conv_timestamptz(s, None)
self.assertEquals(c(''), None)
self.assertEquals(c('2001-03-02 12:44:01+01:00'),
datetime(2001, 3, 2, 12, 44, 01, 0, TZStub(1,0)))
self.assertEquals(c('2001-03-02 12:44:01.037-00:30'),
datetime(2001, 3, 2, 12, 44, 01, 37000, TZStub(0,-30)))
self.assertEquals(c('2001-03-02 12:44:01.000001+12:00'),
datetime(2001, 3, 2, 12, 44, 01, 1, TZStub(12,0)))
self.assertEquals(c('2001-06-25 12:14:00-07'),
datetime(2001, 6, 25, 12, 14, 00, 0, TZStub(-7,0)))
def test_conv_interval(self):
from psycopg2da.adapter import _conv_interval
from datetime import timedelta
def c(s):
return _conv_interval(s, None)
self.assertEquals(c(''), None)
self.assertEquals(c('01:00'), timedelta(hours=1))
self.assertEquals(c('00:15'), timedelta(minutes=15))
self.assertEquals(c('00:00:47'), timedelta(seconds=47))
self.assertEquals(c('00:00:00.037'), timedelta(microseconds=37000))
self.assertEquals(c('00:00:00.111111'), timedelta(microseconds=111111))
self.assertEquals(c('1 day'), timedelta(days=1))
self.assertEquals(c('2 days'), timedelta(days=2))
self.assertEquals(c('374 days'), timedelta(days=374))
self.assertEquals(c('2 days 03:20:15.123456'),
timedelta(days=2, hours=3, minutes=20,
seconds=15, microseconds=123456))
# XXX There's a problem with years and months. Currently timedelta
# cannot represent them accurately
self.assertEquals(c('1 month'), '1 month')
self.assertEquals(c('2 months'), '2 months')
self.assertEquals(c('1 mon'), '1 mon')
self.assertEquals(c('2 mons'), '2 mons')
self.assertEquals(c('1 year'), '1 year')
self.assertEquals(c('3 years'), '3 years')
# Later we might be able to use
## self.assertEquals(c('1 month'), timedelta(months=1))
## self.assertEquals(c('2 months'), timedelta(months=2))
## self.assertEquals(c('1 year'), timedelta(years=1))
## self.assertEquals(c('3 years'), timedelta(years=3))
self.assertRaises(ValueError, c, '2 day')
self.assertRaises(ValueError, c, '2days')
self.assertRaises(ValueError, c, '123')
def test_conv_string(self):
from psycopg2da.adapter import _get_string_conv
_conv_string = _get_string_conv("utf-8")
def c(s):
return _conv_string(s, None)
self.assertEquals(c(None), None)
self.assertEquals(c(''), u'')
self.assertEquals(c('c'), u'c')
self.assertEquals(c('\xc3\x82\xc2\xa2'), u'\xc2\xa2')
self.assertEquals(c('c\xc3\x82\xc2\xa2'), u'c\xc2\xa2')
class TestPsycopg2Adapter(TestCase):
def setUp(self):
import psycopg2da.adapter as adapter
self.real_psycopg2 = adapter.psycopg2
adapter.psycopg2 = self.psycopg2_stub = Psycopg2Stub()
def tearDown(self):
import psycopg2da.adapter as adapter
adapter.psycopg2 = self.real_psycopg2
def test_connection_factory(self):
from psycopg2da.adapter import Psycopg2Adapter
a = Psycopg2Adapter('dbi://username:password@hostname:port/dbname;junk=ignored')
c = a._connection_factory()
args = self.psycopg2_stub.last_connection_string.split()
args.sort()
self.assertEquals(args, ['dbname=dbname', 'host=hostname',
'password=password', 'port=port',
'user=username'])
def test_registerTypes(self):
import psycopg2da.adapter as adapter
from psycopg2da.adapter import Psycopg2Adapter
a = Psycopg2Adapter('dbi://')
a.registerTypes()
for typename in ('DATE', 'TIME', 'TIMETZ', 'TIMESTAMP',
'TIMESTAMPTZ', 'INTERVAL'):
typeid = getattr(adapter, '%s_OID' % typename)
result = self.psycopg2_stub.types.get(typeid, None)
if not result:
# comparing None with psycopg2.type object segfaults
self.fail("did not register %s (%d): got None, not Z%s"
% (typename, typeid, typename))
else:
result_name = getattr(result, 'name', 'None')
self.assertEquals(result, getattr(adapter, typename),
"did not register %s (%d): got %s, not Z%s"
% (typename, typeid, result_name, typename))
class TestISODateTime(TestCase):
# Test if date/time parsing functions accept a sensible subset of ISO-8601
# compliant date/time strings.
#
# Resources:
# http://www.cl.cam.ac.uk/~mgk25/iso-time.html
# http://www.mcs.vuw.ac.nz/technical/software/SGML/doc/iso8601/ISO8601.html
# http://www.w3.org/TR/NOTE-datetime
# http://www.ietf.org/rfc/rfc3339.txt
basic_dates = (('20020304', (2002, 03, 04)),
('20000229', (2000, 02, 29)))
extended_dates = (('2002-03-04', (2002, 03, 04)),
('2000-02-29', (2000, 02, 29)))
basic_times = (('12', (12, 0, 0)),
('1234', (12, 34, 0)),
('123417', (12, 34, 17)),
('123417.5', (12, 34, 17.5)),
('123417,5', (12, 34, 17.5)))
extended_times = (('12', (12, 0, 0)),
('12:34', (12, 34, 0)),
('12:34:17', (12, 34, 17)),
('12:34:17.5', (12, 34, 17.5)),
('12:34:17,5', (12, 34, 17.5)))
basic_tzs = (('Z', 0),
('+02', 2*60),
('+1130', 11*60+30),
('-05', -5*60),
('-0030', -30))
extended_tzs = (('Z', 0),
('+02', 2*60),
('+11:30', 11*60+30),
('-05', -5*60),
('-00:30', -30))
time_separators = (' ', 'T')
bad_dates = ('', 'foo', 'XXXXXXXX', 'XXXX-XX-XX', '2001-2-29',
'1990/13/14')
bad_times = ('', 'foo', 'XXXXXX', '12:34,5', '12:34:56,')
bad_timetzs = ('12+12 34', '15:45 +1234', '18:00-12:34:56', '18:00+123', '18:00Q')
bad_datetimes = ('', 'foo', '2002-03-0412:33')
bad_datetimetzs = ('', 'foo', '2002-03-04T12:33 +1200')
exception_type = ValueError
# We need the following funcions:
# parse_date -> (year, month, day)
# parse_time -> (hour, minute, second)
# parse_timetz -> (hour, minute, second, tzoffset)
# parse_datetime -> (year, month, day, hour, minute, second)
# parse_datetimetz -> (year, month, day, hour, minute, second, tzoffset)
# second can be a float, all other values are ints
# tzoffset is offset in minutes east of UTC
def setUp(self):
from psycopg2da.adapter import parse_date, parse_time, \
parse_timetz, parse_datetime, parse_datetimetz
self.parse_date = parse_date
self.parse_time = parse_time
self.parse_timetz = parse_timetz
self.parse_datetime = parse_datetime
self.parse_datetimetz = parse_datetimetz
def test_basic_date(self):
for s, d in self.basic_dates:
self.assertEqual(self.parse_date(s), d)
def test_extended_date(self):
for s, d in self.extended_dates:
self.assertEqual(self.parse_date(s), d)
def test_bad_date(self):
for s in self.bad_dates:
self.assertRaises(self.exception_type, self.parse_date, s)
def test_basic_time(self):
for s, t in self.basic_times:
self.assertEqual(self.parse_time(s), t)
def test_extended_time(self):
for s, t in self.extended_times:
self.assertEqual(self.parse_time(s), t)
def test_bad_time(self):
for s in self.bad_times:
self.assertRaises(self.exception_type, self.parse_time, s)
def test_basic_timetz(self):
for s, t in self.basic_times:
for tz, off in self.basic_tzs:
self.assertEqual(self.parse_timetz(s+tz), t + (off,))
def test_extended_timetz(self):
for s, t in self.extended_times:
for tz, off in self.extended_tzs:
self.assertEqual(self.parse_timetz(s+tz), t + (off,))
def test_bad_timetzs(self):
for s in self.bad_timetzs:
self.assertRaises(self.exception_type, self.parse_timetz, s)
def test_basic_datetime(self):
for ds, d in self.basic_dates:
for ts, t in self.basic_times:
for sep in self.time_separators:
self.assertEqual(self.parse_datetime(ds+sep+ts), d + t)
def test_extended_datetime(self):
for ds, d in self.extended_dates:
for ts, t in self.extended_times:
for sep in self.time_separators:
self.assertEqual(self.parse_datetime(ds+sep+ts), d + t)
def test_bad_datetimes(self):
for s in self.bad_datetimes:
self.assertRaises(self.exception_type, self.parse_datetime, s)
def test_basic_datetimetz(self):
for ds, d in self.basic_dates:
for ts, t in self.basic_times:
for tz, off in self.basic_tzs:
for sep in self.time_separators:
self.assertEqual(self.parse_datetimetz(ds+sep+ts+tz),
d + t + (off,))
def test_extended_datetimetz(self):
for ds, d in self.extended_dates:
for ts, t in self.extended_times:
for tz, off in self.extended_tzs:
for sep in self.time_separators:
self.assertEqual(self.parse_datetimetz(ds+sep+ts+tz),
d + t + (off,))
def test_bad_datetimetzs(self):
for s in self.bad_datetimetzs:
self.assertRaises(self.exception_type, self.parse_datetimetz, s)
def test_suite():
return TestSuite((
makeSuite(TestPsycopg2TypeConversion),
makeSuite(TestPsycopg2Adapter),
makeSuite(TestISODateTime),
))
if __name__=='__main__':
main(defaultTest='test_suite')