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)

2248
ChangeLog

File diff suppressed because it is too large Load Diff

190
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'.
The simplest way to compile this package is: to install system-wide.
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.

404
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:
-----------------------
* ZPsycopgDA works again. psycopg.extensions.register_type(psycopg.extensions.UNICODE)
psycopg news for 1.1.12 Note that the UNICODE typecaster override the STRING one, so it is
----------------------- not activated by default.
* Fixed nasty segfault/deadlock in switch_isolation_level. * cursors now really support the iterator protocol.
* Now the PostgreSQL TIME type is correctly converted to a DateTimeDelta * solved the rounding errors in time conversions.
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 * now cursors support .fileno() and .isready() methods, to be used in
possible values.) select() calls.
* .execute() now rise the right exception if called with a wrong * .copy_from() and .copy_in() methods are back in (still using the old
tuple/dict. Also, %% in queries does not raise an exception anymore. protocol, will be updated to use new one in next releasae.)
* Updated RPM specs (thanks to Mark McClain we now have updated RPMs on * fixed memory corruption bug reported on win32 platform.
initd.org too.)
psycopg news for 1.1.11 What's new in psycopg 1.99.7
----------------------- ----------------------------
* a modern autoconf is now needed to build psycopg. * added support for tuple factories in cursor objects (removed factory
argument in favor of a .tuple_factory attribute on the cursor object);
see the new module psycopg.extras for a cursor (DictCursor) that
return rows as objects that support indexing both by position and
column name.
* now an error during commit or rollback is correctly reported by raising * added support for tzinfo objects in datetime.timestamp objects: the
an exception. PostgreSQL type "timestamp with time zone" is converted to
datetime.timestamp with a FixedOffsetTimezone initialized as necessary.
* when the libpq protocol 3.0 is available, psycopg uses a smater method What's new in psycopg 1.99.6
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(). * sslmode parameter from 1.1.x
* where did the news for 1.1.10 go? * various datetime conversion improvements.
psycopg news for 1.1.9 * now psycopg should compile without mx or without native datetime
---------------------- (not both, obviously.)
* psycopg distribution now includes the GeoTypes package by Richard Taylor * included various win32/MSVC fixes (pthread.h changes, winsock2
(QinetiQ Plc)! library, include path in setup.py, etc.)
* Problems with sequences and mappings non correctly used in .execute() * ported interval fixes from 1.1.14/1.1.15.
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. * the last query executed by a cursor is now available in the
.query attribute.
psycopg news for 1.1.7 * conversion of unicode strings to backend encoding now uses a table
---------------------- (that still need to be filled.)
* added notifies and fileno methods to cursor objects. * cursors now have a .mogrify() method that return the query string
instead of executing it.
* now execute accept any object that defined __getitem__ and not only * connection objects now have a .dsn read-only attribute that holds the
dictionaries. connection string.
* little fix in ZPsycopgDA, should work with Zope 2.7. * moved psycopg C module to _psycopg and made psycopg a python module:
this allows for a neat separation of DBAPI-2.0 functionality and psycopg
extensions; the psycopg namespace will be also used to provide
python-only extensions (like the pooling code, some ZPsycopgDA support
functions and the like.)
psycopg news for 1.1.6 What's new in psycopg 1.99.3
---------------------- ----------------------------
* cursor objects now have the .scroll() method. * added support for python 2.3 datetime types (both ways) and made datetime
the default set of typecasters when available.
* NUL characters in strings are discarded in quoting; use a Binary object if * added example: dt.py.
you need strings with embedded NULs.
* Fixed another MT problem in .execute(). What's new in psycopg 1.99.3
----------------------------
psycopg news for 1.1.5 * initial working support for unicode bound variables: UTF-8 and latin-1
---------------------- backend encodings are natively supported (and the encoding.py example even
works!)
* ZPsycopgDA now rollback before raising an exception; should be a backward * added .set_client_encoding() method on the connection object.
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 * added examples: encoding.py, binary.py, lastrowid.py.
multiple times and having the None value in the dict should work now.)
* fixed keeper status trashing problem: no more psycopg stuck in transaction What's new in psycopg 1.99.2
(maybe this will also solve ZPsycopgDA problems: will see...) ----------------------------
* now copy_from and copy_to can be passed instances of classes with "readline" * better typecasting:
and "write" methods and not only file instances. - DateTimeDelta used for postgresql TIME (merge from 1.1)
- BYTEA now is converted to a real buffer object, not to a string
psycopg news for 1.1.4 * buffer objects are now adapted into Binary objects automatically.
----------------------
* Fixed various memory leak problems. * ported scroll method from 1.1 (DBAPI-2.0 extension for cursors)
* Implemented "statusmessage" attribute on 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
psycopg news for 1.1.3 What's new in psycopg 1.99.1
---------------------- ----------------------------
* Fixed problem with psycopg always reporting IntegrityError. * implemented microprotocols to adapt arbitrary types to the interface used by
psycopg to bind variables in execute;
* Fixed segfault in debug statements. * moved qstring, pboolean and mxdatetime to the new adapter layout (binary is
still missing; python 2.3 datetime needs to be written).
* Now Python GIL is unlocked during PQconnectdb() calls (better
multithreading.)
psycopg news for 1.1.2 What's new in psycopg 1.99.0
---------------------- ----------------------------
* Skipped version 1.1.1 (never released 'cause of a cvs tag error) * reorganized the whole source tree;
* Much better cursor.description fields (many thanks to William K. Volkman) * async core is in place;
* psycopg.connect() now takes keyword parameters for host, dbname, port, * splitted QuotedString objects from mx stuff;
user and password (they are all strings, even "port".)
* connection.set_isolation_level() implemented to help switching from default * dropped autotools and moved to pythonic setup.py (needs work.)
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.)
* psycopg compile and run on FreeBSD and MacOS X.
* much better binary objects, they use less memory and quoting is faster,
thank to the new, smarter memory allocator.
* fixed all reported buglets (mostly dbapi and type-system related.)
* hey, this is one-dot-oh!
* the following features are missing from psycopg 1.0 and will be added when
we have a little more time (i.e., there will be no _feature_ releases after
1.0, only bugfixes):
- documentation is incomplete (we are slowly writing it, track CVS if you
want up-to-date docs)
- dbapi-2.0 testsuite is incomplete (need to move code to the unittest
framework)
- psycopg needs a full suite of regression tests to be sure we don't break
things while implementing new features (i think we'll add them _while_
writing new features :)
psycopg news for 0.99.7
-----------------------
* time intervals are correctly recognized and converted into DateTimeInterval
objects.
* almost complete (bugs apart) DBAPI-2.0 support. switched psycopg to use
QuotedString for every string passed as a bound argument. Binary now works
(but still consumes lots of memory).
* added doc/ to hold documentation.
* added lastoid() method to cursor objects, to retrieve the OID of the last
inserted row.
psycopg news for 0.99.4
-----------------------
* psycopg is approaching 1.0, so only DBAPI compliance patches and bug fixes
are getting in.
* added Binary and QuotedString objects. note that sometime before 1.0 we'll
switch turn every string passed to psycopg into a QuotedString, possibily
breaking Zope compatibility and old scripts doing their own quoting.
psycopg news for 0.5.x
----------------------
* this is the development branch, if you want stability, stick with 0.4.6.
* added pthread locks so that different threads (cursors) can use the same
postgres connection (this was done *only* to respect the dbapi on cursor
isolation.)
* now the default for the .cursor() method is to associate every cursor to
the same physical connection, to avoid isolation (as the DBAPI-2.0 specify),
you can change that by calling the .serialize() method on the connection and
giving it 0 as the argument, e.g., "o.serialize(0)".
psycopg news for 0.4.1
----------------------
* autocommit mode is now supported on cursors and connections.
psycopg news for 0.4
--------------------
* implemented all the remaining DBAPI-2.0 type singletons (DATETIME and
BINARY included)
psycopg news for 0.3
--------------------
* threading problems resolved
* added type casting from postgres to python (the user can now specify
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
broken!

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,274 +1,150 @@
############################################################################## # ZPsycopgDA/DA.py - ZPsycopgDA Zope product: Database Connection
# #
# Zope Public License (ZPL) Version 1.0 # Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
# -------------------------------------
# #
# Copyright (c) Digital Creations. All rights reserved. # 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 license has been certified as Open Source(tm). # Or, at your option this program (ZPsycopgDA) can be distributed under the
# Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
# http://www.zope.org/Resources/ZPL.
# #
# Redistribution and use in source and binary forms, with or without # This program is distributed in the hope that it will be useful, but
# modification, are permitted provided that the following conditions are # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# met: # or FITNESS FOR A PARTICULAR PURPOSE.
# #
# 1. Redistributions in source code must retain the above copyright # See the LICENSE file for details.
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# 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
try:
import psycopg
from psycopg import new_type, register_type, DATETIME, TIME, DATE, INTERVAL
except StandardError, err:
print err
try:
from DateTime import DateTime 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, import psycopg
tilevel=2, check=None, REQUEST=None): from psycopg import DATETIME
"""Add a DB connection to a folder""" from psycopg.extensions import TIME, DATE, INTERVAL
self._setObject(id, Connection(id, title, connection_string, zdatetime, from psycopg.extensions import new_type, register_type
check, tilevel))
# 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) if REQUEST is not None: return self.manage_main(self, REQUEST)
# Convert an ISO timestamp string from postgres to a DateTime (zope version) # the connection object
# object.
def cast_DateTime(str):
if str:
# this will split us into [date, time, GMT/AM/PM(if there)]
dt = split(str, ' ')
if len(dt) > 1:
# we now should split out any timezone info
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'))
else:
t = time.mktime(time.strptime(dt[0], '%Y-%m-%d %H:%M:%S'))
return DateTime(t)
# Convert an ISO date string from postgres to a DateTime(zope version)
# object.
def cast_Date(str):
if str:
return DateTime(time.mktime(time.strptime(str, '%Y-%m-%d')))
# Convert a time string from postgres to a DateTime(zope version) object.
# WARNING: We set the day as today before feeding to DateTime so
# that it has the same DST settings.
def cast_Time(str):
if str:
return DateTime(time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime(time.time())[:3]+
time.strptime(str[:8], "%H:%M:%S")[3:]))
# Convert a time string from postgres to a DateTime(zope version) object.
# WARNING: We set the day as the epoch day (1970-01-01) since this
# DateTime does not support time deltas. (EXPERIMENTAL USE WITH CARE!)
def cast_Interval(str):
return str
class Connection(DABase.Connection): class Connection(DABase.Connection):
"The connection class." """ZPsycopg Connection."""
database_type = database_type id = 'Psycopg_database_connection'
id = '%s_database_connection' % database_type database_type = 'Psycopg'
meta_type = title = 'Z %s Database Connection' % database_type meta_type = title = 'Z Psycopg Database Connection'
icon = 'misc_/Z%sDA/conn' % database_type icon = 'misc_/ZPsycopg/conn'
def __init__(self, id, title, connection_string, zdatetime, def __init__(self, id, title, connection_string,
check=None, tilevel=2, encoding='UTF-8'): zdatetime, check=None, tilevel=2, encoding=''):
self.zdatetime = zdatetime self.zdatetime = zdatetime
self.id = str(id) self.id = str(id)
self.edit(title, connection_string, zdatetime, self.edit(title, connection_string, zdatetime,
check=check, tilevel=tilevel, encoding=encoding) 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): def factory(self):
return DB return DB
def table_info(self): def table_info(self):
return self._v_database_connection.table_info() 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): def connect(self, s):
try: self._v_database_connection.close() try:
except: pass self._v_database_connection.close()
except:
pass
# check psycopg version and raise exception if does not match # check psycopg version and raise exception if does not match
if psycopg.__version__ not in __psycopg_versions__: if psycopg.__version__ not in ALLOWED_PSYCOPG_VERSIONS:
raise ImportError("psycopg version mismatch: " + raise ImportError("psycopg version mismatch (imported %s)" +
psycopg.__version__) psycopg.__version__)
self.set_type_casts() self.set_type_casts()
self._v_connected = '' self._v_connected = ''
DB=self.factory() dbf = self.factory()
try:
try: # TODO: let the psycopg exception propagate, or not?
# this is necessary when upgrading from old installs without self._v_database_connection = dbf(
# having to recreate the connection object self.connection_string, self.tilevel, self.encoding)
if not hasattr(self, 'tilevel'): self._v_database_connection.open()
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() self._v_connected = DateTime()
return self return self
def sql_quote__(self, v): def set_type_casts(self):
# quote dictionary # note that in both cases order *is* important
quote_dict = {"\'": "''", "\\": "\\\\"} if self.zdatetime:
for dkey in quote_dict.keys(): # use zope internal datetime routines
if find(v, dkey) >= 0: register_type(ZDATETIME)
v=join(split(v,dkey),quote_dict[dkey]) register_type(ZDATE)
return "'%s'" % v 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 = ('DA.Connection',) classes = (Connection,)
meta_types=( meta_types = ({'name':'Z Psycopg Database Connection',
{'name':'Z %s Database Connection' % database_type, 'action':'manage_addZPsycopgConnectionForm'},)
'action':'manage_addZ%sConnectionForm' % database_type},)
folder_methods = { folder_methods = {
'manage_addZPsycopgConnection': manage_addZPsycopgConnection, 'manage_addZPsycopgConnection': manage_addZPsycopgConnection,
@ -278,10 +154,49 @@ __ac_permissions__=(
('Add Z Psycopg Database Connections', ('Add Z Psycopg Database Connections',
('manage_addZPsycopgConnectionForm', 'manage_addZPsycopgConnection')),) ('manage_addZPsycopgConnectionForm', 'manage_addZPsycopgConnection')),)
misc_={ # add icons
'conn': ImageFile('Shared/DC/ZRDB/www/DBAdapterFolder_icon.gif')}
for icon in ('table', 'view', 'stable', 'what', misc_={'conn': ImageFile('Shared/DC/ZRDB/www/DBAdapterFolder_icon.gif')}
'field', 'text','bin','int','float',
'date','time','datetime'): for icon in ('table', 'view', 'stable', 'what', 'field', 'text', 'bin',
'int', 'float', 'date', 'time', 'datetime'):
misc_[icon] = ImageFile('icons/%s.gif' % icon, globals()) 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:
# this will split us into [date, time, GMT/AM/PM(if there)]
dt = split(str, ' ')
if len(dt) > 1:
# we now should split out any timezone info
dt[1] = split(dt[1], '-')[0]
dt[1] = split(dt[1], '+')[0]
return DateTime(join(dt[:2], ' '))
else:
return DateTime(dt[0])
# convert an ISO date string from postgres to a Zope DateTime object
def _cast_Date(str):
if str:
return DateTime(str)
# 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(str):
if str:
return DateTime(time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime(time.time())[:3]+
time.strptime(str[:8], "%H:%M:%S")[3:]))
# TODO: DateTime does not support intervals: what's the best we can do?
def _cast_Interval(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)

View File

@ -1,141 +1,49 @@
############################################################################## # ZPsycopgDA/DABase.py - ZPsycopgDA Zope product: Database inspection
# #
# Zope Public License (ZPL) Version 1.0 # Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
# -------------------------------------
# #
# Copyright (c) Digital Creations. All rights reserved. # 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 license has been certified as Open Source(tm). # Or, at your option this program (ZPsycopgDA) can be distributed under the
# Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
# http://www.zope.org/Resources/ZPL.
# #
# Redistribution and use in source and binary forms, with or without # This program is distributed in the hope that it will be useful, but
# modification, are permitted provided that the following conditions are # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# met: # or FITNESS FOR A PARTICULAR PURPOSE.
# #
# 1. Redistributions in source code must retain the above copyright # See the LICENSE file for details.
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# 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
manage_options=Shared.DC.ZRDB.Connection.Connection.manage_options+(
{'label': 'Browse', 'action':'manage_browse'},
# {'label': 'Design', 'action':'manage_tables'}
)
manage_tables = HTMLFile('tables',globals())
manage_browse = HTMLFile('browse',globals())
info = None info = None
def tpValues(self): #manage_options = Shared.DC.ZRDB.Connection.Connection.manage_options + (
#if hasattr(self, '_v_tpValues'): return self._v_tpValues # {'label': 'Browse', 'action':'manage_browse'},)
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 #manage_tables = HTMLFile('tables', globals())
#self._v_tpValues=r #manage_browse = HTMLFile('browse',globals())
return r
def __getitem__(self, name): def __getitem__(self, name):
if name == 'tableNamed': if name == 'tableNamed':
@ -143,8 +51,11 @@ class Connection(Shared.DC.ZRDB.Connection.Connection):
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>
# -------------------------------------
# #
# Copyright (c) Digital Creations. All rights reserved. # 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 license has been certified as Open Source(tm). # Or, at your option this program (ZPsycopgDA) can be distributed under the
# Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
# http://www.zope.org/Resources/ZPL.
# #
# Redistribution and use in source and binary forms, with or without # This program is distributed in the hope that it will be useful, but
# modification, are permitted provided that the following conditions are # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# met: # or FITNESS FOR A PARTICULAR PURPOSE.
# #
# 1. Redistributions in source code must retain the above copyright # See the LICENSE file for details.
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# 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
classes = DA.classes
meta_types = DA.meta_types
misc_ = DA.misc_ 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>
# -------------------------------------
# #
# Copyright (c) Digital Creations. All rights reserved. # 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 license has been certified as Open Source(tm). # Or, at your option this program (ZPsycopgDA) can be distributed under the
# Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
# http://www.zope.org/Resources/ZPL.
# #
# Redistribution and use in source and binary forms, with or without # This program is distributed in the hope that it will be useful, but
# modification, are permitted provided that the following conditions are # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# met: # or FITNESS FOR A PARTICULAR PURPOSE.
# #
# 1. Redistributions in source code must retain the above copyright # See the LICENSE file for details.
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# 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 ZODB.POSException import ConflictError
from string import strip, split, find
from time import time import time
from types import ListType
import site import site
import pool
import psycopg import psycopg
from psycopg import NUMBER, STRING, INTEGER, FLOAT, DATETIME from psycopg.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN
from psycopg import BOOLEAN, ROWID, LONGINTEGER from psycopg import NUMBER, STRING, ROWID, DATETIME
from ZODB.POSException import ConflictError
# the DB object, managing all the real query work
class DB(TM, dbi_db.DB): 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()
self.putconn()
except AttributeError:
pass
def _cursor(self): def open(self):
"""Obtains a cursor in a safe way.""" # this will create a new pool for our DSN if not already existing,
if not hasattr(self, 'db') or not self.db: # then get and immediately release a connection
self.db = self.connect(self.connection) self.getconn()
return self.db.cursor() 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,46 +135,50 @@ class DB(TM,dbi_db.DB):
type = DATETIME type = DATETIME
else: else:
type = STRING type = STRING
a({ 'Name': name,
res.append({'Name': name,
'Type': type.name, 'Type': type.name,
'Precision': 0, 'Precision': 0,
'Scale': 0, 'Scale': 0,
'Nullable': 0}) 'Nullable': 0})
return r 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
@ -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