Undo of wrong commit of 1.1.x source code over 2.x.

This commit is contained in:
Federico Di Gregorio 2004-10-29 16:15:45 +00:00
parent c89f821126
commit 091270db2a
15 changed files with 807 additions and 3361 deletions

View File

@ -1,9 +1,8 @@
Main authors: Main authors:
Michele Comitini <mcm@initd.org>
Federico Di Gregorio <fog@debian.org> Federico Di Gregorio <fog@debian.org>
For the win32 port: For the win32 port:
Jason Erickson <jerickso@indian.com> Jason Erickson <jerickso@indian.com> (most of his changes are still in 2.0)
Additional Help: Additional Help:
Tom Jenkins <tjenkins@devis.com> (COPY FROM/COPY TO backport)

2216
ChangeLog

File diff suppressed because it is too large Load Diff

192
INSTALL
View File

@ -1,184 +1,18 @@
Basic Installation Compiling and installing psycopg
================== ********************************
These are generic installation instructions. Before building and While psycopg 1.x used autoconf for its build process psycopg 2 switched to
installing make sure you read carefully the "Install" section in the the more pythoning setup.py. Currently both psycopg's author and distutils
README file. have some limitations so the file setup.cfg is almost unused and most build
options are hidden in setup.py. Before building psycopg look at the very
first lines of setup.py and change any settings to follow your system (or
taste); then:
The `configure' shell script attempts to guess correct values for python setup.py build
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try to build in the local directory; and:
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program python setup.py install
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'. to install system-wide.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.

432
NEWS
View File

@ -1,355 +1,155 @@
psycopg news for 1.1.15 What's new in psycopg 1.99.10
----------------------- -----------------------------
* Interval typecasting eventually-eventually works the Right Way (TM). * The adapt() function now fully supports the adaptation protocol
described in PEP 246. Note that the adapters registry now is indexed
by (type, protocol) and not by type alone. Change your adapters
accordingly.
* Fixed two bad memory leaks in QuotedString and Binary objects. * More configuration options moved from setup.py to setup.cfg.
* Reverted change on rowcount attribute, now it is always set to the real * Fixed two memory leaks: one in cursor deallocation and one in row
number of affected columns. fetching (.fetchXXX() methods.)
psycopg news for 1.1.14 What's new in psycopg 1.99.9
----------------------- ----------------------------
* Interval typecasting eventually works the Right Way (TM). * Added simple pooling code (psycopg.pool module); see the reworked
examples/threads.py for example code.
* ZPsycopgDA now support unicode strings and different backend encodings. * Added DECIMAL typecaster to convert postgresql DECIMAL and NUMERIC
types (i.e, all types with an OID of NUMERICOID.) Note that the
DECIMAL typecaster does not set scale and precision on the created
objects but uses Python defaults.
* ZPsycopgDA accept query data as an extra parameter to execute() (but * ZPsycopgDA back in and working using the new pooling code.
still no way to give it extra data from inside a ZSQL Method.)
* Better DBAPI-2.0 compliance (rowcount attribute and argument passing.) * Isn't that enough? :)
* Now builds on Fedora Core 2 (but remember that the real psycopg What's new in psycopg 1.99.8
aficionado runs on Debian ;-P ) ----------------------------
* COPY FROM raise an exception and return usefull information on error. * added support for UNICODE queries.
psycopg news for 1.1.13 * added UNICODE typecaster; to activate it just do:
-----------------------
psycopg.extensions.register_type(psycopg.extensions.UNICODE)
* ZPsycopgDA works again.
psycopg news for 1.1.12
-----------------------
* Fixed nasty segfault/deadlock in switch_isolation_level.
* Now the PostgreSQL TIME type is correctly converted to a DateTimeDelta
instead of a DateTime. This is much better because you can now add two
times and a time and a date.
* Added an "sslmode" parameter (look at PostgreSQL documentation for
possible values.)
* .execute() now rise the right exception if called with a wrong
tuple/dict. Also, %% in queries does not raise an exception anymore.
* Updated RPM specs (thanks to Mark McClain we now have updated RPMs on
initd.org too.)
psycopg news for 1.1.11
-----------------------
* a modern autoconf is now needed to build psycopg.
* now an error during commit or rollback is correctly reported by raising
an exception.
* when the libpq protocol 3.0 is available, psycopg uses a smater method
to determine exception type (unfortunately the old string compare method
is still neede for postgresql <= 7.3.x.)
* plugged a memory leak in copy_from().
* where did the news for 1.1.10 go?
psycopg news for 1.1.9
----------------------
* psycopg distribution now includes the GeoTypes package by Richard Taylor
(QinetiQ Plc)!
* Problems with sequences and mappings non correctly used in .execute()
should be gone (mogrification code completely rewritten.) Many thanks
to Richard Taylor and Vsevolod Lobko that helped by testing the "pre"
releases.
* no more libpq 7.1.x linking problems related to PQfreeNotify.
psycopg news for 1.1.7
----------------------
* added notifies and fileno methods to cursor objects.
* now execute accept any object that defined __getitem__ and not only
dictionaries.
* little fix in ZPsycopgDA, should work with Zope 2.7.
psycopg news for 1.1.6
----------------------
* cursor objects now have the .scroll() method.
* NUL characters in strings are discarded in quoting; use a Binary object if
you need strings with embedded NULs.
* Fixed another MT problem in .execute().
psycopg news for 1.1.5
----------------------
* ZPsycopgDA now rollback before raising an exception; should be a backward
compatible change for people that really want to continue executing queries
after an exception.
* fixed problem with dictionary mogrification (i.e., specifying the same key
multiple times and having the None value in the dict should work now.)
* fixed keeper status trashing problem: no more psycopg stuck in transaction
(maybe this will also solve ZPsycopgDA problems: will see...)
* now copy_from and copy_to can be passed instances of classes with "readline"
and "write" methods and not only file instances.
psycopg news for 1.1.4
----------------------
* Fixed various memory leak problems.
* Implemented "statusmessage" attribute on cursors.
psycopg news for 1.1.3
----------------------
* Fixed problem with psycopg always reporting IntegrityError.
* Fixed segfault in debug statements.
* Now Python GIL is unlocked during PQconnectdb() calls (better
multithreading.)
psycopg news for 1.1.2
----------------------
* Skipped version 1.1.1 (never released 'cause of a cvs tag error)
* Much better cursor.description fields (many thanks to William K. Volkman)
* psycopg.connect() now takes keyword parameters for host, dbname, port,
user and password (they are all strings, even "port".)
* connection.set_isolation_level() implemented to help switching from default
isolation to other levels supported by PostgreSQL. [autocommit now simply
does a set_isolation_level(0)]
* Implemented .lastrowid attribute for cursors.
* Now psycopg should build on win32/cygwin, thank to Hajime Nakagami patches.
* Includes every fix from 1.0.x up to 1.0.15.1:
- Fixed connection-stay-open-when-i-do-conn.close() bug.
- Better DBAPI-2.0 compliance for setinputsizes and setoutputsize methods.
- Better support for build on MacOS X.
- Fixed problem with formats in string mogrification.
- Fixed other miscellaneous buglets in Zope Adapter.
- Fixed small memory leak in .fetchXXX() methods.
- Fixed serialization problem in ZPsycopgDA reported by Dieter Maurer.
psycopg news for 1.1
--------------------
* COPY TO/COPY FROM implemented by Tom Jenkins
* Merged changes from 1.0.13.
psycopg news for 1.0.12
-----------------------
* Maintenance release fixing some little buglets:
- Fixed memory leak in .execute().
- Better configure under MacOS X.
- DA-browser now works even with tables with mixed-case names.
- timestamps time is now set to correct value instead of 0.
psycopg news for 1.0.11.1
-------------------------
* Fixed orrible bug in ZPsycopgDA not acception psycopg 1.0.11 as a valid
version.
psycopg news for 1.0.11
-----------------------
* last problems from "None passed to typecasters" (introduced in 1.0.9) in
ZPsycopgDA solved (hopefully.)
* psycopg now reports meaningfull exception types for some errors (like
IntegrityError for duplicate insertions in unique indices, etc.)
psycopg news for 1.0.10
-----------------------
* fixed an exception problem introduced in 1.0.9 (patch by Matt
Hoskins.)
* ZPsycopgDA now checks psycopg version and raise an exception if it
does not match.
psycopg news for 1.0.9
----------------------
* fixed problem with connection left in invalid state by applying
Tom Jenkins patch.
* None values passed to the typecasters, it is now possible to
translate None into "" to achieve pygrsql compatibilty.
* applied 'seconds as a float' patch from Jelle.
psycopg news for 1.0.8
----------------------
* fixed a segfault introduced in 1.0.7 and another little bug when
dealing with empty strings in QuotedString objects.
* Added win32 compatibility (many many thanks to Jason Erickson).
psycopg news for 1.0.7
----------------------
* Fixed little bugs in type management (infinity problems and the
TIMESTAMPTZ type) and Zope import. Better configure script.
* Now psycopg really close the physical connection to PostgreSQL on
connection .close().
psycopg news for 1.0.5
----------------------
* Applied a little patch to make table browser in zope show system tables
correctly.
* Infinity values are now converted the correct way.
psycopg news for 1.0.4
----------------------
* ZPsycopgDA does not duplicate itself anymore.
* Table browsing works again.
psycopg news for 1.0.3
----------------------
* bugfix for b0rken ZPsycopgDA in 1.0.2.
psycopg news for 1.0.2
----------------------
* Fixed problem with incorrect interpretation of hundredths of a second.
psycopg news for 1.0.1
----------------------
* fixed two little memory leaks, see ChangeLog for details.
* fixed problem with garbled passwords when using crypt autentication.
psycopg news for 1.0
--------------------
* added regression tests, first result is much better conversion of date and
time types.
* fixed last know segfault (psycopg runs stable for a lot of people now.) Note that the UNICODE typecaster override the STRING one, so it is
not activated by default.
* psycopg compile and run on FreeBSD and MacOS X. * cursors now really support the iterator protocol.
* much better binary objects, they use less memory and quoting is faster, * solved the rounding errors in time conversions.
thank to the new, smarter memory allocator.
* fixed all reported buglets (mostly dbapi and type-system related.)
* hey, this is one-dot-oh! * now cursors support .fileno() and .isready() methods, to be used in
select() calls.
* the following features are missing from psycopg 1.0 and will be added when * .copy_from() and .copy_in() methods are back in (still using the old
we have a little more time (i.e., there will be no _feature_ releases after protocol, will be updated to use new one in next releasae.)
1.0, only bugfixes):
- documentation is incomplete (we are slowly writing it, track CVS if you * fixed memory corruption bug reported on win32 platform.
want up-to-date docs)
- dbapi-2.0 testsuite is incomplete (need to move code to the unittest What's new in psycopg 1.99.7
framework) ----------------------------
- psycopg needs a full suite of regression tests to be sure we don't break * added support for tuple factories in cursor objects (removed factory
things while implementing new features (i think we'll add them _while_ argument in favor of a .tuple_factory attribute on the cursor object);
writing new features :) see the new module psycopg.extras for a cursor (DictCursor) that
return rows as objects that support indexing both by position and
column name.
psycopg news for 0.99.7 * added support for tzinfo objects in datetime.timestamp objects: the
----------------------- PostgreSQL type "timestamp with time zone" is converted to
datetime.timestamp with a FixedOffsetTimezone initialized as necessary.
* time intervals are correctly recognized and converted into DateTimeInterval What's new in psycopg 1.99.6
objects. ----------------------------
* almost complete (bugs apart) DBAPI-2.0 support. switched psycopg to use * sslmode parameter from 1.1.x
QuotedString for every string passed as a bound argument. Binary now works
(but still consumes lots of memory).
* added doc/ to hold documentation. * various datetime conversion improvements.
* added lastoid() method to cursor objects, to retrieve the OID of the last * now psycopg should compile without mx or without native datetime
inserted row. (not both, obviously.)
psycopg news for 0.99.4 * included various win32/MSVC fixes (pthread.h changes, winsock2
----------------------- library, include path in setup.py, etc.)
* psycopg is approaching 1.0, so only DBAPI compliance patches and bug fixes * ported interval fixes from 1.1.14/1.1.15.
are getting in.
* added Binary and QuotedString objects. note that sometime before 1.0 we'll * the last query executed by a cursor is now available in the
switch turn every string passed to psycopg into a QuotedString, possibily .query attribute.
breaking Zope compatibility and old scripts doing their own quoting.
psycopg news for 0.5.x * conversion of unicode strings to backend encoding now uses a table
---------------------- (that still need to be filled.)
* this is the development branch, if you want stability, stick with 0.4.6. * cursors now have a .mogrify() method that return the query string
instead of executing it.
* added pthread locks so that different threads (cursors) can use the same * connection objects now have a .dsn read-only attribute that holds the
postgres connection (this was done *only* to respect the dbapi on cursor connection string.
isolation.)
* now the default for the .cursor() method is to associate every cursor to * moved psycopg C module to _psycopg and made psycopg a python module:
the same physical connection, to avoid isolation (as the DBAPI-2.0 specify), this allows for a neat separation of DBAPI-2.0 functionality and psycopg
you can change that by calling the .serialize() method on the connection and extensions; the psycopg namespace will be also used to provide
giving it 0 as the argument, e.g., "o.serialize(0)". python-only extensions (like the pooling code, some ZPsycopgDA support
functions and the like.)
psycopg news for 0.4.1 What's new in psycopg 1.99.3
---------------------- ----------------------------
* autocommit mode is now supported on cursors and connections. * added support for python 2.3 datetime types (both ways) and made datetime
the default set of typecasters when available.
psycopg news for 0.4 * added example: dt.py.
--------------------
* implemented all the remaining DBAPI-2.0 type singletons (DATETIME and What's new in psycopg 1.99.3
BINARY included) ----------------------------
psycopg news for 0.3 * initial working support for unicode bound variables: UTF-8 and latin-1
-------------------- backend encodings are natively supported (and the encoding.py example even
works!)
* threading problems resolved * added .set_client_encoding() method on the connection object.
* added type casting from postgres to python (the user can now specify * added examples: encoding.py, binary.py, lastrowid.py.
its own casting objects, the default singletons NUMBER and STRING are
included [and act as default cast objects] plus INTEGER and FLOAT as
an extension to the DBAPI-2.0.)
investigate the code in examples/usercast_test.py to understand how to
add your own types...
* beginning of the Zope Database Adapter: give it a try even it it is What's new in psycopg 1.99.2
broken! ----------------------------
* better typecasting:
- DateTimeDelta used for postgresql TIME (merge from 1.1)
- BYTEA now is converted to a real buffer object, not to a string
* buffer objects are now adapted into Binary objects automatically.
* ported scroll method from 1.1 (DBAPI-2.0 extension for cursors)
* initial support for some DBAPI-2.0 extensions:
- .rownumber attribute for cursors
- .connection attribute for cursors
- .next() and .__iter__() methods to have cursors support the iterator
protocol
- all exception objects are exported to the connection object
What's new in psycopg 1.99.1
----------------------------
* implemented microprotocols to adapt arbitrary types to the interface used by
psycopg to bind variables in execute;
* moved qstring, pboolean and mxdatetime to the new adapter layout (binary is
still missing; python 2.3 datetime needs to be written).
What's new in psycopg 1.99.0
----------------------------
* reorganized the whole source tree;
* async core is in place;
* splitted QuotedString objects from mx stuff;
* dropped autotools and moved to pythonic setup.py (needs work.)

173
README
View File

@ -1,145 +1,26 @@
psycopg - Python-PostgreSQL Database Adapter psycopg - Python-PostgreSQL Database Adapter
******************************************** ********************************************
psycopg is a PostgreSQL database adapter for the Python programming language psycopg is a PostgreSQL database adapter for the Python programming
(just like pygresql and popy.) It was written from scratch with the aim of language. This is version 2, a complete rewrite of the original code to
being very small and fast, and stable as a rock. The main advantages of provide new-style classes for connection and cursor objects and other sweet
psycopg are that it supports (well... *will* support) the full Python candies. Like the original, psycopg 2 was written with the aim of being
DBAPI-2.0 and being thread safe at level 2. very small and fast, and stable as a rock.
psycopg is different from the other database adapter because it was designed psycopg is different from the other database adapter because it was
for heavily multi-threaded applications that create and destroy lots of designed for heavily multi-threaded applications that create and destroy
cursors and make a conspicuous number of concurrent INSERTs or UPDATEs. lots of cursors and make a conspicuous number of concurrent INSERTs or
Every open Python connection keeps a pool of real (UNIX or TCP/IP) connections UPDATEs. psycopg 2 also provide full asycronous operations for the really
to the database. Every time a new cursor is created, a new connection does not brave programmer.
need to be opened; instead one of the unused connections from the pool is
used. That makes psycopg very fast in typical client-server applications that
create a servicing thread every time a client request arrives.
psycopg now support the Python DBAPI-2.0 completely. There are confirmed There are confirmed reports of psycopg 1.x compiling and running on Linux
reports of psycopg compiling and running on Linux and FreeBSD on i386, Solaris and FreeBSD on i386, Solaris, MacOS X and win32 architectures. psycopg 2
and MacOS X. does not introduce build-wise incompatible changes so it should be able to
compile on all architectures just as its predecessor did.
Now go read the INSTALL file. More information about psycopg extensions to
the DBAPI-2.0 is available in the files located in the doc/ direcory.
Extensions to the Python DBAPI-2.0
----------------------------------
psycopg offers some little extensions on the Python DBAPI-2.0. Note that the
extension do not make psycopg incompatible and you can still use it without
ever knowing the extensions are here.
The DBAPI-2.0 mandates that cursors derived from the same connection are not
isolated, i.e., changes done to the database by one of them should be
immediately visible by all the others. This is done by serializing the queries
on the same physical connection to the database (PGconn struct in C.)
Serializing queries when the network latencies are hight (and network speed is
low) dramatically lowers performance, so it is possible to put a connection
into not-serialized mode, by calling the .serialize() method giving it a
0-value argument or by creating a connection using the following code:
conn = psycopg.connect("dbname=...", serialize=0)
After that every cursor will get its own physical connection to the database
and multiple threads will go at full speed. Note that this feature makes the
new cursors non-compliant respect to the DBAPI-2.0.
The main extension is that we support (on not-serialized cursors) per-cursor
commits. If you do a commit() on the connection all the changes on all the
cursors derived from that connection are committed to the database (in random
order, so take your care.) But you can also call commit() on a single cursor
to commit just the operations done on that cursor. Pretty nice.
Note that you *do have* to call .commit() on the cursors or on the connection
if you want to change your database. Note also that you *do have* to call
commit() on a cursor even before a SELECT if you want to see the changes
apported by other threads to the database.
Also note that you *can't* (I repeat: *you* *can't*) call .commit() on cursor
derived from a serialized connection: trying that will give you an exception
with the message: "serialized connection: cannot commit on this cursor". If
you want to use the per-cursor commit feature you need to create a
non-serialized connection, as explained above.
From version 0.4.1 psycopg supports autocommit mode. You can set the default
mode for new cursor by setting the 'autocommit' variable to 0 or 1 on the
connection before creating a new cursor with the cursor() method. On an
already created cursor you can change the commit mode by calling the
autocommit() method. Giving no arguments or 1 switches autocommit on, 0
switches it off.
Obviously everything said about commit is valid for rollbacks too.
The type system
---------------
The DBAPI-2.0 specify that should be possible to check for the column type
reported in the second field of the description tuple of the cursor used for a
SELECT using 'singletons' like NUMBER, STRING, etc. While this is fully
supported by psycopg from release 0.3 on, we went forward and implemented
support for custom typecasting from PostgreSQL to Python types using
user-defined functions. See the examples test/check_types.py and
doc/examples/usercast.py for more information. In particular usercast_test.py
shows how to implement a callback that translates the PostgreSQL box type to
an ad-hoc Python class with instances created automagically on SELECT.
Compile-time configuration options
----------------------------------
To build psycopg you will need a C compiler (gcc), the Python development
files (headers and libraries), the PostgreSQL header and libraries and the
mxDateTime header files (and the mxDateTime Python package installed, version
>= 2.0.0, of curse.)
The following options are specific to psycopg and can be set when running
configure before issuing 'make' to compile the package.
--with-postgres-libraries=DIR
PostgreSQL 7.x libraries (libpq.so) are in directory DIR
--with-postgres-includes=DIR
PostgreSQL 7.x header files are located in directory DIR
--with-mxdatetime-includes=DIR
MXDateTime Python extension header files are located in directory DIR
--with-zope=DIR
install the ZPsycopgDA Zope Product into DIR (use 'make install-zope')
--enable-devel[=yes/no]
Enable developer features like debugging output and extra assertions.
Some random notes about python versions and paths:
1/ If possible, don't use the configure arguments --with-python-prefix
and --with-python-exec-prefix; the configure script is able to guess
the correct values from you python installation.
2/ If you have more than one Python version installed, use the arguments
--with-python (giving it the *full*, *absolute* path to the Python
interpreter) and --with-python-version (giving it the corresponding
version, like 1.5 or 2.1.)
Common problems while building psycopg:
1/ if your compiler does not find some postgres headers try copying all the
headers from the postgres _source_ distribution to a single place. Also,
if building postgresql from source, make sure to install all headers by
the "make install-all-headers" target.
2/ if you have the same problem with mx.DateTime, try using the source
directory again; the install script does not copy all the headers, same
way as postgres install procedure does.
3/ under MacOS X you may need to run the runlib program on the posgres
installed libraries before trying to compile psycopg. Also, if you
get compilation errors there is a change your python was not compiled
correctly and psycopg is grabbing the wrong compile-time options from
python's Makefile. try setting the OPT and LDFLAG environment variables
to something usefull, as in the next example:
OPT="-no-cpp-precomp" LDFLAGS="-flat-namespace" ./configure ...
Licence Licence
------- -------
@ -149,16 +30,16 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See file COPYING for details. (at your option) any later version. See file COPYING for details.
As a special exception, specific permission is granted for the GPLed As a special exception, specific permission is granted for the GPLed code in
code in this distribition to be linked to OpenSSL and PostgreSQL libpq this distribition to be linked to OpenSSL and PostgreSQL libpq without
without invoking GPL clause 2(b). invoking GPL clause 2(b).
If you prefer you can use the Zope Database Adapter ZPsycopgDA (i.e., If you prefer you can use the Zope Database Adapter ZPsycopgDA (i.e., every
every file inside the ZPsycopgDA directory) user the ZPL license as file inside the ZPsycopgDA directory) under the ZPL license as published on
published on the Zope web site, http://www.zope.org/Resources/ZPL. the Zope web site, http://www.zope.org/Resources/ZPL. The ZPL is perfectly
compatible with the GPL
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.
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.

View File

@ -1,128 +1,171 @@
############################################################################## # ZPsycopgDA/DA.py - ZPsycopgDA Zope product: Database Connection
# #
# Zope Public License (ZPL) Version 1.0 # Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
# ------------------------------------- #
# # This program is free software; you can redistribute it and/or modify
# Copyright (c) Digital Creations. All rights reserved. # 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
# This license has been certified as Open Source(tm). # version.
# #
# Redistribution and use in source and binary forms, with or without # Or, at your option this program (ZPsycopgDA) can be distributed under the
# modification, are permitted provided that the following conditions are # Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
# met: # http://www.zope.org/Resources/ZPL.
# #
# 1. Redistributions in source code must retain the above copyright # This program is distributed in the hope that it will be useful, but
# notice, this list of conditions, and the following disclaimer. # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# # or FITNESS FOR A PARTICULAR PURPOSE.
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions, and the following disclaimer in # See the LICENSE file for details.
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
database_type='Psycopg'
__doc__='''%s Database Connection
$Id: DA.py 531 2004-09-18 09:54:40Z fog $''' % database_type
__version__='$Revision: 1.20.2.14 $'[11:-2]
__psycopg_versions__ = ('1.1.12', '1.1.13', '1.1.14', '1.1.15', '1.1.16')
ALLOWED_PSYCOPG_VERSIONS = ('1.99.9',)
import sys
import db
import DABase
import Shared.DC.ZRDB.Connection
from db import DB from db import DB
import Shared.DC.ZRDB.Connection, sys, DABase, time from Globals import DTMLFile
from Globals import HTMLFile, ImageFile from Globals import HTMLFile
from ImageFile import ImageFile
from ExtensionClass import Base from ExtensionClass import Base
from string import find, join, split, rindex from DateTime import DateTime
try:
import psycopg
from psycopg import new_type, register_type, DATETIME, TIME, DATE, INTERVAL
except StandardError, err:
print err
try:
from DateTime import DateTime
except StandardError, err:
print err
try:
from App.Dialogs import MessageDialog
except:
pass
import time
manage_addZPsycopgConnectionForm = HTMLFile('connectionAdd', globals()) # import psycopg and functions/singletons needed for date/time conversions
def manage_addZPsycopgConnection(self, id, title,
connection_string, zdatetime=None,
tilevel=2, check=None, REQUEST=None):
"""Add a DB connection to a folder"""
self._setObject(id, Connection(id, title, connection_string, zdatetime,
check, tilevel))
if REQUEST is not None: return self.manage_main(self,REQUEST)
import psycopg
from psycopg import DATETIME
from psycopg.extensions import TIME, DATE, INTERVAL
from psycopg.extensions import new_type, register_type
# Convert an ISO timestamp string from postgres to a DateTime (zope version)
# object.
def cast_DateTime(str): # add a new connection to a folder
manage_addZPsycopgConnectionForm = DTMLFile('dtml/add',globals())
def manage_addZPsycopgConnection(self, id, title, connection_string,
zdatetime=None, tilevel=2,
check=None, REQUEST=None):
"""Add a DB connection to a folder."""
self._setObject(id, Connection(id, title, connection_string,
zdatetime, check, tilevel))
if REQUEST is not None: return self.manage_main(self, REQUEST)
# the connection object
class Connection(DABase.Connection):
"""ZPsycopg Connection."""
id = 'Psycopg_database_connection'
database_type = 'Psycopg'
meta_type = title = 'Z Psycopg Database Connection'
icon = 'misc_/ZPsycopg/conn'
def __init__(self, id, title, connection_string,
zdatetime, check=None, tilevel=2, encoding=''):
self.zdatetime = zdatetime
self.id = str(id)
self.edit(title, connection_string, zdatetime,
check=check, tilevel=tilevel, encoding=encoding)
def factory(self):
return DB
def table_info(self):
return self._v_database_connection.table_info()
def edit(self, title, connection_string,
zdatetime, check=None, tilevel=2, encoding=''):
self.title = title
self.connection_string = connection_string
self.zdatetime = zdatetime
self.tilevel = tilevel
self.encoding = encoding
self.set_type_casts()
if check: self.connect(self.connection_string)
manage_properties = DTMLFile('dtml/edit', globals())
def manage_edit(self, title, connection_string,
zdatetime=None, check=None, tilevel=2, encoding='UTF-8',
REQUEST=None):
"""Edit the DB connection."""
self.edit(title, connection_string, zdatetime,
check=check, tilevel=tilevel, encoding=encoding)
if REQUEST is not None:
msg = "Connection edited."
return self.manage_main(self,REQUEST,manage_tabs_message=msg)
def connect(self, s):
try:
self._v_database_connection.close()
except:
pass
# check psycopg version and raise exception if does not match
if psycopg.__version__ not in ALLOWED_PSYCOPG_VERSIONS:
raise ImportError("psycopg version mismatch (imported %s)" +
psycopg.__version__)
self.set_type_casts()
self._v_connected = ''
dbf = self.factory()
# TODO: let the psycopg exception propagate, or not?
self._v_database_connection = dbf(
self.connection_string, self.tilevel, self.encoding)
self._v_database_connection.open()
self._v_connected = DateTime()
return self
def set_type_casts(self):
# note that in both cases order *is* important
if self.zdatetime:
# use zope internal datetime routines
register_type(ZDATETIME)
register_type(ZDATE)
register_type(ZTIME)
register_type(ZINTERVAL)
else:
# use the standard
register_type(DATETIME)
register_type(DATE)
register_type(TIME)
register_type(INTERVAL)
# database connection registration data
classes = (Connection,)
meta_types = ({'name':'Z Psycopg Database Connection',
'action':'manage_addZPsycopgConnectionForm'},)
folder_methods = {
'manage_addZPsycopgConnection': manage_addZPsycopgConnection,
'manage_addZPsycopgConnectionForm': manage_addZPsycopgConnectionForm}
__ac_permissions__ = (
('Add Z Psycopg Database Connections',
('manage_addZPsycopgConnectionForm', 'manage_addZPsycopgConnection')),)
# add icons
misc_={'conn': ImageFile('Shared/DC/ZRDB/www/DBAdapterFolder_icon.gif')}
for icon in ('table', 'view', 'stable', 'what', 'field', 'text', 'bin',
'int', 'float', 'date', 'time', 'datetime'):
misc_[icon] = ImageFile('icons/%s.gif' % icon, globals())
# zope-specific psycopg typecasters
# convert an ISO timestamp string from postgres to a Zope DateTime object
def _cast_DateTime(str):
if str: if str:
# this will split us into [date, time, GMT/AM/PM(if there)] # this will split us into [date, time, GMT/AM/PM(if there)]
dt = split(str, ' ') dt = split(str, ' ')
@ -130,158 +173,30 @@ def cast_DateTime(str):
# we now should split out any timezone info # we now should split out any timezone info
dt[1] = split(dt[1], '-')[0] dt[1] = split(dt[1], '-')[0]
dt[1] = split(dt[1], '+')[0] dt[1] = split(dt[1], '+')[0]
t = time.mktime(time.strptime(join(dt[:2], ' '), '%Y-%m-%d %H:%M:%S')) return DateTime(join(dt[:2], ' '))
else: else:
t = time.mktime(time.strptime(dt[0], '%Y-%m-%d %H:%M:%S')) return DateTime(dt[0])
return DateTime(t)
# Convert an ISO date string from postgres to a DateTime(zope version) # convert an ISO date string from postgres to a Zope DateTime object
# object. def _cast_Date(str):
def cast_Date(str):
if str: if str:
return DateTime(time.mktime(time.strptime(str, '%Y-%m-%d'))) return DateTime(str)
# Convert a time string from postgres to a DateTime(zope version) object. # Convert a time string from postgres to a Zope DateTime object.
# WARNING: We set the day as today before feeding to DateTime so # NOTE: we set the day as today before feeding to DateTime so
# that it has the same DST settings. # that it has the same DST settings.
def cast_Time(str): def _cast_Time(str):
if str: if str:
return DateTime(time.strftime('%Y-%m-%d %H:%M:%S', return DateTime(time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime(time.time())[:3]+ time.localtime(time.time())[:3]+
time.strptime(str[:8], "%H:%M:%S")[3:])) time.strptime(str[:8], "%H:%M:%S")[3:]))
# Convert a time string from postgres to a DateTime(zope version) object. # TODO: DateTime does not support intervals: what's the best we can do?
# WARNING: We set the day as the epoch day (1970-01-01) since this def _cast_Interval(str):
# DateTime does not support time deltas. (EXPERIMENTAL USE WITH CARE!)
def cast_Interval(str):
return str return str
ZDATETIME = new_type((1184, 1114), "ZDATETIME", _cast_DateTime)
ZINTERVAL = new_type((1186,), "ZINTERVAL", _cast_Interval)
ZDATE = new_type((1082,), "ZDATE", _cast_Date)
ZTIME = new_type((1083,), "ZTIME", _cast_Time)
class Connection(DABase.Connection):
"The connection class."
database_type = database_type
id = '%s_database_connection' % database_type
meta_type = title = 'Z %s Database Connection' % database_type
icon = 'misc_/Z%sDA/conn' % database_type
def __init__(self, id, title, connection_string, zdatetime,
check=None, tilevel=2, encoding='UTF-8'):
self.zdatetime=zdatetime
self.id=str(id)
self.edit(title, connection_string, zdatetime,
check=check, tilevel=tilevel, encoding=encoding)
def edit(self, title, connection_string, zdatetime,
check=1, tilevel=2, encoding='UTF-8'):
self.title=title
self.connection_string=connection_string
self.zdatetime=zdatetime
self.tilevel=tilevel
self.encoding=encoding
self.set_type_casts()
if check: self.connect(connection_string)
manage_properties=HTMLFile('connectionEdit', globals())
def manage_edit(self, title, connection_string,
zdatetime=None, check=None, tilevel=2, encoding='UTF-8',
REQUEST=None):
"""Change connection
"""
self.edit(title, connection_string, zdatetime,
check=check, tilevel=tilevel, encoding=encoding)
if REQUEST is not None:
return MessageDialog(
title='Edited',
message='<strong>%s</strong> has been edited.' % self.id,
action ='./manage_main',
)
def set_type_casts(self):
"Make changes to psycopg default typecast list"
if self.zdatetime:
#use zope internal datetime routines
ZDATETIME=new_type((1184,1114), "ZDATETIME", cast_DateTime)
ZDATE=new_type((1082,), "ZDATE", cast_Date)
ZTIME=new_type((1083,), "ZTIME", cast_Time)
ZINTERVAL=new_type((1186,), "ZINTERVAL", cast_Interval)
register_type(ZDATETIME)
register_type(ZDATE)
register_type(ZTIME)
register_type(ZINTERVAL)
else:
#use the standard. WARN: order is important!
register_type(DATETIME)
register_type(DATE)
register_type(TIME)
register_type(INTERVAL)
def factory(self):
return DB
def table_info(self):
return self._v_database_connection.table_info()
def connect(self,s):
try: self._v_database_connection.close()
except: pass
# check psycopg version and raise exception if does not match
if psycopg.__version__ not in __psycopg_versions__:
raise ImportError("psycopg version mismatch: " +
psycopg.__version__)
self.set_type_casts()
self._v_connected=''
DB=self.factory()
try:
try:
# this is necessary when upgrading from old installs without
# having to recreate the connection object
if not hasattr(self, 'tilevel'):
self.tilevel = 2
if not hasattr(self, 'encoding'):
self.encoding = 'UTF-8'
self._v_database_connection=DB(s, self.tilevel, self.encoding)
except:
t, v, tb = sys.exc_info()
raise 'BadRequest', (
'<strong>Could not open connection.<br>'
'Connection string: </strong><CODE>%s</CODE><br>\n'
'<pre>\n%s\n%s\n</pre>\n'
% (s,t,v)), tb
finally: tb=None
self._v_connected=DateTime()
return self
def sql_quote__(self, v):
# quote dictionary
quote_dict = {"\'": "''", "\\": "\\\\"}
for dkey in quote_dict.keys():
if find(v, dkey) >= 0:
v=join(split(v,dkey),quote_dict[dkey])
return "'%s'" % v
classes = ('DA.Connection',)
meta_types=(
{'name':'Z %s Database Connection' % database_type,
'action':'manage_addZ%sConnectionForm' % database_type},)
folder_methods={
'manage_addZPsycopgConnection': manage_addZPsycopgConnection,
'manage_addZPsycopgConnectionForm': manage_addZPsycopgConnectionForm}
__ac_permissions__=(
('Add Z Psycopg Database Connections',
('manage_addZPsycopgConnectionForm', 'manage_addZPsycopgConnection')),)
misc_={
'conn': ImageFile('Shared/DC/ZRDB/www/DBAdapterFolder_icon.gif')}
for icon in ('table', 'view', 'stable', 'what',
'field', 'text','bin','int','float',
'date','time','datetime'):
misc_[icon] = ImageFile('icons/%s.gif' % icon, globals())

View File

@ -1,150 +1,61 @@
############################################################################## # ZPsycopgDA/DABase.py - ZPsycopgDA Zope product: Database inspection
# #
# Zope Public License (ZPL) Version 1.0 # Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
# ------------------------------------- #
# # This program is free software; you can redistribute it and/or modify
# Copyright (c) Digital Creations. All rights reserved. # 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
# This license has been certified as Open Source(tm). # version.
# #
# Redistribution and use in source and binary forms, with or without # Or, at your option this program (ZPsycopgDA) can be distributed under the
# modification, are permitted provided that the following conditions are # Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
# met: # http://www.zope.org/Resources/ZPL.
# #
# 1. Redistributions in source code must retain the above copyright # This program is distributed in the hope that it will be useful, but
# notice, this list of conditions, and the following disclaimer. # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# # or FITNESS FOR A PARTICULAR PURPOSE.
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions, and the following disclaimer in # See the LICENSE file for details.
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
__doc__='''Database Connection
$Id: DABase.py 400 2003-01-20 14:39:34Z fog $''' import sys
__version__='$Revision: 1.10 $'[11:-2] import Shared.DC.ZRDB.Connection
from db import DB
import Shared.DC.ZRDB.Connection, sys from Globals import HTMLFile
from App.Dialogs import MessageDialog from ImageFile import ImageFile
from Globals import HTMLFile, ImageFile
from ExtensionClass import Base from ExtensionClass import Base
import Acquisition from DateTime import DateTime
from psycopg import NUMBER, ROWID, STRING, INTEGER, FLOAT
from psycopg import BOOLEAN, DATETIME, LONGINTEGER # import psycopg and functions/singletons needed for date/time conversions
import psycopg
from psycopg.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN
from psycopg import NUMBER, STRING, ROWID, DATETIME
class Connection(Shared.DC.ZRDB.Connection.Connection): class Connection(Shared.DC.ZRDB.Connection.Connection):
_isAnSQLConnection = 1 _isAnSQLConnection = 1
info = None
manage_options=Shared.DC.ZRDB.Connection.Connection.manage_options+( #manage_options = Shared.DC.ZRDB.Connection.Connection.manage_options + (
{'label': 'Browse', 'action':'manage_browse'}, # {'label': 'Browse', 'action':'manage_browse'},)
# {'label': 'Design', 'action':'manage_tables'}
)
manage_tables = HTMLFile('tables',globals()) #manage_tables = HTMLFile('tables', globals())
manage_browse = HTMLFile('browse',globals()) #manage_browse = HTMLFile('browse',globals())
info=None
def tpValues(self):
#if hasattr(self, '_v_tpValues'): return self._v_tpValues
r=[]
# self._v_tables=tables=TableBrowserCollection()
#tables=tables.__dict__
c = self._v_database_connection
try:
for d in c.tables(rdb=0):
try:
name=d['TABLE_NAME']
b=TableBrowser()
b.__name__=name
b._d=d
b._c=c
# b._columns=c.columns(name)
try: b.icon=table_icons[d['TABLE_TYPE']]
except: pass
r.append(b)
# tables[name]=b
except:
# print d['TABLE_NAME'], sys.exc_type, sys.exc_value
pass
finally: pass #print sys.exc_type, sys.exc_value
#self._v_tpValues=r
return r
def __getitem__(self, name): def __getitem__(self, name):
if name=='tableNamed': if name == 'tableNamed':
if not hasattr(self, '_v_tables'): self.tpValues() if not hasattr(self, '_v_tables'): self.tpValues()
return self._v_tables.__of__(self) return self._v_tables.__of__(self)
raise KeyError, name raise KeyError, name
## old stuff from ZPsycopgDA 1.1 (never implemented) ##
def manage_wizard(self, tables): def manage_wizard(self, tables):
" " "Wizard of what? Oozing?"
def manage_join(self, tables, select_cols, join_cols, REQUEST=None): def manage_join(self, tables, select_cols, join_cols, REQUEST=None):
"""Create an SQL join""" """Create an SQL join"""
@ -154,116 +65,3 @@ class Connection(Shared.DC.ZRDB.Connection.Connection):
def manage_update(self, table, keys, cols, REQUEST=None): def manage_update(self, table, keys, cols, REQUEST=None):
"""Create an SQL update""" """Create an SQL update"""
class TableBrowserCollection(Acquisition.Implicit):
"Helper class for accessing tables via URLs"
pass
class Browser(Base):
def __getattr__(self, name):
try: return self._d[name]
except KeyError: raise AttributeError, name
class values:
def len(self): return 1
def __getitem__(self, i):
try: return self._d[i]
except AttributeError:
pass
self._d=self._f()
return self._d[i]
class TableBrowser(Browser, Acquisition.Implicit):
icon='what'
Description=check=''
info=HTMLFile('table_info',globals())
menu=HTMLFile('table_menu',globals())
def tpValues(self):
v=values()
v._f=self.tpValues_
return v
def tpValues_(self):
r=[]
tname=self.__name__
for d in self._c.columns(tname):
b=ColumnBrowser()
b._d=d
try: b.icon=field_icons[d['Type']]
except: pass
b.TABLE_NAME=tname
r.append(b)
return r
def tpId(self): return self._d['TABLE_NAME']
def tpURL(self): return "Table/%s" % self._d['TABLE_NAME']
def Name(self): return self._d['TABLE_NAME']
def Type(self): return self._d['TABLE_TYPE']
manage_designInput=HTMLFile('designInput',globals())
def manage_buildInput(self, id, source, default, REQUEST=None):
"Create a database method for an input form"
args=[]
values=[]
names=[]
columns=self._columns
for i in range(len(source)):
s=source[i]
if s=='Null': continue
c=columns[i]
d=default[i]
t=c['Type']
n=c['Name']
names.append(n)
if s=='Argument':
values.append("<dtml-sqlvar %s type=%s>'" %
(n, vartype(t)))
a='%s%s' % (n, boboType(t))
if d: a="%s=%s" % (a,d)
args.append(a)
elif s=='Property':
values.append("<dtml-sqlvar %s type=%s>'" %
(n, vartype(t)))
else:
if isStringType(t):
if find(d,"\'") >= 0: d=join(split(d,"\'"),"''")
values.append("'%s'" % d)
elif d:
values.append(str(d))
else:
raise ValueError, (
'no default was given for <em>%s</em>' % n)
class ColumnBrowser(Browser):
icon='field'
def check(self):
return ('\t<input type=checkbox name="%s.%s">' %
(self.TABLE_NAME, self._d['Name']))
def tpId(self): return self._d['Name']
def tpURL(self): return "Column/%s" % self._d['Name']
def Description(self):
d=self._d
if d['Scale']:
return " %(Type)s(%(Precision)s,%(Scale)s) %(Nullable)s" % d
else:
return " %(Type)s(%(Precision)s) %(Nullable)s" % d
table_icons={
'TABLE': 'table',
'VIEW':'view',
'SYSTEM_TABLE': 'stable',
}
field_icons={
NUMBER.name: 'int',
STRING.name: 'text',
DATETIME.name: 'date',
INTEGER.name: 'int',
FLOAT.name: 'float',
BOOLEAN.name: 'bin',
ROWID.name: 'int'
}

View File

@ -1,105 +1,32 @@
############################################################################## # ZPsycopgDA/__init__.py - ZPsycopgDA Zope product
# #
# Zope Public License (ZPL) Version 1.0 # Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
# ------------------------------------- #
# # This program is free software; you can redistribute it and/or modify
# Copyright (c) Digital Creations. All rights reserved. # 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
# This license has been certified as Open Source(tm). # version.
# #
# Redistribution and use in source and binary forms, with or without # Or, at your option this program (ZPsycopgDA) can be distributed under the
# modification, are permitted provided that the following conditions are # Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
# met: # http://www.zope.org/Resources/ZPL.
# #
# 1. Redistributions in source code must retain the above copyright # This program is distributed in the hope that it will be useful, but
# notice, this list of conditions, and the following disclaimer. # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# # or FITNESS FOR A PARTICULAR PURPOSE.
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions, and the following disclaimer in # See the LICENSE file for details.
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
# Modified by mcm@initd.net for the psycopg driver
__doc__='''Generic Database Adapter Package Registration
$Id: __init__.py 400 2003-01-20 14:39:34Z fog $''' __doc__ = "ZPsycopg Database Adalper Registration."
__version__='$Revision: 1.11 $'[11:-2] __version__ = '2.0'
import sys, string import sys
import string
import DA import DA
methods=DA.folder_methods methods = DA.folder_methods
misc_ = DA.misc_ classes = DA.classes
meta_types = DA.meta_types
misc_ = DA.misc_
def initialize(context): __ac_permissions__=DA.__ac_permissions__
"""Initialize the DBA product.
"""
context.registerClass(
DA.Connection,
permission = 'Add Z Psycopg Database Connections',
constructors = (DA.manage_addZPsycopgConnectionForm,
DA.manage_addZPsycopgConnection),
icon = SOFTWARE_HOME + '/Shared/DC/ZRDB/www/DBAdapterFolder_icon.gif')

View File

@ -1,171 +1,126 @@
############################################################################## # ZPsycopgDA/db.py - query execution
# #
# Zope Public License (ZPL) Version 1.0 # Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
# ------------------------------------- #
# # This program is free software; you can redistribute it and/or modify
# Copyright (c) Digital Creations. All rights reserved. # 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
# This license has been certified as Open Source(tm). # version.
# #
# Redistribution and use in source and binary forms, with or without # Or, at your option this program (ZPsycopgDA) can be distributed under the
# modification, are permitted provided that the following conditions are # Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
# met: # http://www.zope.org/Resources/ZPL.
# #
# 1. Redistributions in source code must retain the above copyright # This program is distributed in the hope that it will be useful, but
# notice, this list of conditions, and the following disclaimer. # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# # or FITNESS FOR A PARTICULAR PURPOSE.
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions, and the following disclaimer in # See the LICENSE file for details.
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
'''$Id: db.py 532 2004-09-27 18:35:25Z fog $'''
__version__='$Revision: 1.31.2.7 $'[11:-2]
from Shared.DC.ZRDB.TM import TM from Shared.DC.ZRDB.TM import TM
from Shared.DC.ZRDB import dbi_db from Shared.DC.ZRDB import dbi_db
import string, sys
from string import strip, split, find
from time import time
from types import ListType
import site
import psycopg
from psycopg import NUMBER, STRING, INTEGER, FLOAT, DATETIME
from psycopg import BOOLEAN, ROWID, LONGINTEGER
from ZODB.POSException import ConflictError from ZODB.POSException import ConflictError
class DB(TM,dbi_db.DB): import time
import site
import pool
import psycopg
from psycopg.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN
from psycopg import NUMBER, STRING, ROWID, DATETIME
# the DB object, managing all the real query work
class DB(TM, dbi_db.DB):
_p_oid = _p_changed = _registered = None _p_oid = _p_changed = _registered = None
def __init__(self, connection, tilevel, enc='utf-8'): def __init__(self, dsn, tilevel, enc='utf-8'):
self.connection = connection self.dsn = dsn
self.tilevel = tilevel self.tilevel = tilevel
self.encoding = enc self.encoding = enc
self.db = self.connect(self.connection)
self.failures = 0 self.failures = 0
self.calls = 0 self.calls = 0
def connect(self, connection): def getconn(self, create=True):
o = psycopg.connect(connection) conn = pool.getconn(self.dsn)
o.set_isolation_level(int(self.tilevel)) conn.set_isolation_level(int(self.tilevel))
return o return conn
def putconn(self, close=False):
try:
conn = pool.getconn(self.dsn, False)
except AttributeError:
pass
pool.putconn(self.dsn, conn, close)
def getcursor(self):
conn = self.getconn()
return conn.cursor()
def _finish(self, *ignored): def _finish(self, *ignored):
if hasattr(self, 'db') and self.db: try:
self.db.commit() conn = self.getconn(False)
conn.commit()
self.putconn()
except AttributeError:
pass
def _abort(self, *ignored): def _abort(self, *ignored):
if hasattr(self, 'db') and self.db: try:
self.db.rollback() conn = self.getconn(False)
conn.rollback()
def _cursor(self): self.putconn()
"""Obtains a cursor in a safe way.""" except AttributeError:
if not hasattr(self, 'db') or not self.db: pass
self.db = self.connect(self.connection)
return self.db.cursor() def open(self):
# this will create a new pool for our DSN if not already existing,
# then get and immediately release a connection
self.getconn()
self.putconn()
def close(self):
# FIXME: if this connection is closed we flush all the pool associated
# with the current DSN; does this makes sense?
pool.flushpool(self.dsn)
def sortKey(self):
return 1
## tables and rows ##
def tables(self, rdb=0, _care=('TABLE', 'VIEW')): def tables(self, rdb=0, _care=('TABLE', 'VIEW')):
self._register() self._register()
c = self._cursor() c = self.getcursor()
c.execute('SELECT t.tablename AS NAME, ' c.execute(
'\'TABLE\' AS TYPE FROM pg_tables t ' "SELECT t.tablename AS NAME, 'TABLE' AS TYPE "
'WHERE tableowner <> \'postgres\' ' " FROM pg_tables t WHERE tableowner <> 'postgres' "
'UNION SELECT v.viewname AS NAME, ' "UNION SELECT v.viewname AS NAME, 'VIEW' AS TYPE "
'\'VIEW\' AS TYPE FROM pg_views v ' " FROM pg_views v WHERE viewowner <> 'postgres' "
'WHERE viewowner <> \'postgres\' ' "UNION SELECT t.tablename AS NAME, 'SYSTEM_TABLE\' AS TYPE "
'UNION SELECT t.tablename AS NAME, ' " FROM pg_tables t WHERE tableowner = 'postgres' "
'\'SYSTEM_TABLE\' AS TYPE FROM pg_tables t ' "UNION SELECT v.viewname AS NAME, 'SYSTEM_TABLE' AS TYPE "
'WHERE tableowner = \'postgres\' ' "FROM pg_views v WHERE viewowner = 'postgres'")
'UNION SELECT v.viewname AS NAME, ' res = []
'\'SYSTEM_TABLE\' AS TYPE FROM pg_views v '
'WHERE viewowner = \'postgres\' ' )
r = []
a = r.append
for name, typ in c.fetchall(): for name, typ in c.fetchall():
if typ in _care: if typ in _care:
a({'TABLE_NAME': name, 'TABLE_TYPE': typ}) res.append({'TABLE_NAME': name, 'TABLE_TYPE': typ})
c.close() self.putconn()
return r return res
def columns(self, table_name): def columns(self, table_name):
self._register() self._register()
c = self._cursor() c = self.getcursor()
try: try:
r = c.execute('select * from "%s" where 1=0' % table_name) r = c.execute('SELECT * FROM "%s" WHERE 1=0' % table_name)
except: except:
return () return ()
desc = c.description res = []
r = [] for name, type, width, ds, p, scale, null_ok in c.description:
a = r.append
for name, type, width, ds, p, scale, null_ok in desc:
if type == NUMBER: if type == NUMBER:
if type == INTEGER: if type == INTEGER:
type = INTEGER type = INTEGER
@ -180,49 +135,53 @@ class DB(TM,dbi_db.DB):
type = DATETIME type = DATETIME
else: else:
type = STRING type = STRING
a({ 'Name': name,
'Type': type.name, res.append({'Name': name,
'Precision': 0, 'Type': type.name,
'Scale': 0, 'Precision': 0,
'Nullable': 0}) 'Scale': 0,
return r 'Nullable': 0})
self.putconn()
return res
## query execution ##
def query(self, query_string, max_rows=None, query_data=None): def query(self, query_string, max_rows=None, query_data=None):
self._register() self._register()
self.calls = self.calls+1 self.calls = self.calls+1
desc = () desc = ()
result = [] res = []
nselects = 0 nselects = 0
c = self._cursor() c = self.getcursor()
try: try:
for qs in filter(None, map(strip, split(query_string, '\0'))): for qs in [x for x in query_string.split('\0') if x]:
if type(qs) == unicode: if type(qs) == unicode:
if self.encoding: if self.encoding:
qs = qs.encode(self.encoding) qs = qs.encode(self.encoding)
try: try:
if (query_data): if (query_data):
r = c.execute(qs, query_data) c.execute(qs, query_data)
else: else:
r = c.execute(qs) c.execute(qs)
except (psycopg.ProgrammingError,psycopg.IntegrityError), perr: except (psycopg.ProgrammingError, psycopg.IntegrityError), e:
if perr.args[0].find("concurrent update") > -1: if e.args[0].find("concurrent update") > -1:
raise ConflictError raise ConflictError
raise perr raise e
if c.description is not None: if c.description is not None:
nselects = nselects + 1 nselects += 1
if c.description != desc and nselects > 1: if c.description != desc and nselects > 1:
raise 'Query Error', \ raise psycopg.ProgrammingError(
'Multiple select schema are not allowed' 'multiple selects in single query not allowed')
if max_rows: if max_rows:
result = c.fetchmany(max_rows) res = c.fetchmany(max_rows)
else: else:
result = c.fetchall() res = c.fetchall()
desc = c.description desc = c.description
self.failures = 0 self.failures = 0
except StandardError, err: except StandardError, err:
self._abort() self._abort()
raise err raise err
@ -247,13 +206,4 @@ class DB(TM,dbi_db.DB):
'null': null_ok, 'null': null_ok,
}) })
return items, result return items, res
def close(self):
"""Close the connection."""
self.db.close()
self.db = None
def sortKey(self):
"""Zope 2.6 added this one."""
return 1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 924 B

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 929 B

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 878 B

After

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 894 B

After

Width:  |  Height:  |  Size: 894 B