SVN repo up to date (1.1.16pre1).
							
								
								
									
										5
									
								
								AUTHORS
									
									
									
									
									
								
							
							
						
						|  | @ -1,8 +1,9 @@ | ||||||
| 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> (most of his changes are still in 2.0) |   Jason Erickson <jerickso@indian.com> | ||||||
| 
 | 
 | ||||||
| Additional Help: | Additional Help: | ||||||
|    |   Tom Jenkins <tjenkins@devis.com> (COPY FROM/COPY TO backport) | ||||||
|  |  | ||||||
							
								
								
									
										190
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						|  | @ -1,18 +1,184 @@ | ||||||
| Compiling and installing psycopg | Basic Installation | ||||||
| ******************************** | ================== | ||||||
| 
 | 
 | ||||||
| While psycopg 1.x used autoconf for its build process psycopg 2 switched to |    These are generic installation instructions. Before building and | ||||||
| the more pythoning setup.py. Currently both psycopg's author and distutils | installing make sure you read carefully the "Install" section in the | ||||||
| have some limitations so the file setup.cfg is almost unused and most build | README file.  | ||||||
| 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: |  | ||||||
| 
 | 
 | ||||||
|     python setup.py build |    The `configure' shell script attempts to guess correct values for | ||||||
|  | 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'). | ||||||
| 
 | 
 | ||||||
| to build in the local directory; and: |    If you need to do unusual things to compile the package, please try | ||||||
|  | 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. | ||||||
| 
 | 
 | ||||||
|     python setup.py install |    The file `configure.in' is used to create `configure' by a program | ||||||
|  | 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. | ||||||
|  |  | ||||||
							
								
								
									
										404
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						|  | @ -1,155 +1,355 @@ | ||||||
| What's new in psycopg 1.99.10 | psycopg news for 1.1.15 | ||||||
| ----------------------------- | ----------------------- | ||||||
| 
 | 
 | ||||||
| * The adapt() function now fully supports the adaptation protocol | * Interval typecasting eventually-eventually works the Right Way (TM). | ||||||
|   described in PEP 246. Note that the adapters registry now is indexed |  | ||||||
|   by (type, protocol) and not by type alone. Change your adapters |  | ||||||
|   accordingly. |  | ||||||
| 
 | 
 | ||||||
| * More configuration options moved from setup.py to setup.cfg. | * Fixed two bad memory leaks in QuotedString and Binary objects. | ||||||
| 
 | 
 | ||||||
| * Fixed two memory leaks: one in cursor deallocation and one in row | * Reverted change on rowcount attribute, now it is always set to the real | ||||||
|   fetching (.fetchXXX() methods.) |   number of affected columns. | ||||||
| 
 | 
 | ||||||
| What's new in psycopg 1.99.9 | psycopg news for 1.1.14 | ||||||
| ---------------------------- | ----------------------- | ||||||
| 
 | 
 | ||||||
| * Added simple pooling code (psycopg.pool module); see the reworked | * Interval typecasting eventually works the Right Way (TM). | ||||||
|   examples/threads.py for example code. |  | ||||||
| 
 | 
 | ||||||
| * Added DECIMAL typecaster to convert postgresql DECIMAL and NUMERIC | * ZPsycopgDA now support unicode strings and different backend encodings. | ||||||
|   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 back in and working using the new pooling code. | * ZPsycopgDA accept query data as an extra parameter to execute() (but | ||||||
|  |   still no way to give it extra data from inside a ZSQL Method.) | ||||||
| 
 | 
 | ||||||
| * Isn't that enough? :) | * Better DBAPI-2.0 compliance (rowcount attribute and argument passing.) | ||||||
| 
 | 
 | ||||||
| What's new in psycopg 1.99.8 | * Now builds on Fedora Core 2 (but remember that the real psycopg | ||||||
| ---------------------------- |   aficionado runs on Debian ;-P ) | ||||||
| 
 | 
 | ||||||
| * added support for UNICODE queries. | * COPY FROM raise an exception and return usefull information on error. | ||||||
| 
 | 
 | ||||||
| * added UNICODE typecaster; to activate it just do: | psycopg news for 1.1.13 | ||||||
|  | ----------------------- | ||||||
| 
 | 
 | ||||||
|     psycopg.extensions.register_type(psycopg.extensions.UNICODE) | * ZPsycopgDA works again. | ||||||
| 
 | 
 | ||||||
|   Note that the UNICODE typecaster override the STRING one, so it is | psycopg news for 1.1.12 | ||||||
|   not activated by default. | ----------------------- | ||||||
| 
 | 
 | ||||||
| * cursors now really support the iterator protocol. | * Fixed nasty segfault/deadlock in switch_isolation_level. | ||||||
| 
 | 
 | ||||||
| * solved the rounding errors in time conversions. | * 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. | ||||||
| 
 | 
 | ||||||
| * now cursors support .fileno() and .isready() methods, to be used in | * Added an "sslmode" parameter (look at PostgreSQL documentation for | ||||||
|   select() calls. |   possible values.) | ||||||
| 
 | 
 | ||||||
| * .copy_from() and .copy_in() methods are back in (still using the old | * .execute() now rise the right exception if called with a wrong | ||||||
|   protocol, will be updated to use new one in next releasae.) |    tuple/dict. Also, %% in queries does not raise an exception anymore. | ||||||
| 
 | 
 | ||||||
| * fixed memory corruption bug reported on win32 platform. | * Updated RPM specs (thanks to Mark McClain we now have updated RPMs on | ||||||
|  |   initd.org too.) | ||||||
| 
 | 
 | ||||||
| What's new in psycopg 1.99.7 | psycopg news for 1.1.11 | ||||||
| ---------------------------- | ----------------------- | ||||||
| 
 | 
 | ||||||
| * added support for tuple factories in cursor objects (removed factory | * a modern autoconf is now needed to build psycopg. | ||||||
|   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. |  | ||||||
| 
 | 
 | ||||||
| * added support for tzinfo objects in datetime.timestamp objects: the | * now an error during commit or rollback is correctly reported by raising  | ||||||
|   PostgreSQL type "timestamp with time zone" is converted to  |   an exception. | ||||||
|   datetime.timestamp with a FixedOffsetTimezone initialized as necessary. |  | ||||||
| 
 | 
 | ||||||
| What's new in psycopg 1.99.6 | * 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.) | ||||||
| 
 | 
 | ||||||
| * sslmode parameter from 1.1.x | * plugged a memory leak in copy_from(). | ||||||
| 
 | 
 | ||||||
| * various datetime conversion improvements. | * where did the news for 1.1.10 go? | ||||||
| 
 | 
 | ||||||
| * now psycopg should compile without mx or without native datetime | psycopg news for 1.1.9 | ||||||
|   (not both, obviously.) | ---------------------- | ||||||
| 
 | 
 | ||||||
| * included various win32/MSVC fixes (pthread.h changes, winsock2 | * psycopg distribution now includes the GeoTypes package by Richard Taylor | ||||||
|   library, include path in setup.py, etc.) |   (QinetiQ Plc)! | ||||||
| 
 | 
 | ||||||
| * ported interval fixes from 1.1.14/1.1.15. | * 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. | ||||||
| 
 | 
 | ||||||
| * the last query executed by a cursor is now available in the | * no more libpq 7.1.x linking problems related to PQfreeNotify. | ||||||
|   .query attribute. |  | ||||||
| 
 | 
 | ||||||
| * conversion of unicode strings to backend encoding now uses a table | psycopg news for 1.1.7 | ||||||
|   (that still need to be filled.) | ---------------------- | ||||||
| 
 | 
 | ||||||
| * cursors now have a .mogrify() method that return the query string | * added notifies and fileno methods to cursor objects. | ||||||
|   instead of executing it. |  | ||||||
| 
 | 
 | ||||||
| * connection objects now have a .dsn read-only attribute that holds the | * now execute accept any object that defined __getitem__ and not only | ||||||
|   connection string. |   dictionaries. | ||||||
| 
 | 
 | ||||||
| * moved psycopg C module to _psycopg and made psycopg a python module: | * little fix in ZPsycopgDA, should work with Zope 2.7. | ||||||
|   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.) |  | ||||||
| 
 | 
 | ||||||
| What's new in psycopg 1.99.3 | psycopg news for 1.1.6 | ||||||
| ---------------------------- | ---------------------- | ||||||
| 
 | 
 | ||||||
| * added support for python 2.3 datetime types (both ways) and made datetime | * cursor objects now have the .scroll() method. | ||||||
|   the default set of typecasters when available. |  | ||||||
| 
 | 
 | ||||||
| * added example: dt.py. | * NUL characters in strings are discarded in quoting; use a Binary object if | ||||||
|  |   you need strings with embedded NULs. | ||||||
| 
 | 
 | ||||||
| What's new in psycopg 1.99.3 | * Fixed another MT problem in .execute(). | ||||||
| ---------------------------- |  | ||||||
| 
 | 
 | ||||||
| * initial working support for unicode bound variables: UTF-8 and latin-1 | psycopg news for 1.1.5 | ||||||
|   backend encodings are natively supported (and the encoding.py example even | ---------------------- | ||||||
|   works!) |  | ||||||
| 
 | 
 | ||||||
| * added .set_client_encoding() method on the connection object. | * 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. | ||||||
| 
 | 
 | ||||||
| * added examples: encoding.py, binary.py, lastrowid.py. | * fixed problem with dictionary mogrification (i.e., specifying the same key | ||||||
|  |   multiple times and having the None value in the dict should work now.) | ||||||
| 
 | 
 | ||||||
| What's new in psycopg 1.99.2 | * fixed keeper status trashing problem: no more psycopg stuck in transaction | ||||||
| ---------------------------- |   (maybe this will also solve ZPsycopgDA problems: will see...) | ||||||
| 
 | 
 | ||||||
| * better typecasting: | * now copy_from and copy_to can be passed instances of classes with "readline" | ||||||
|   - DateTimeDelta used for postgresql TIME (merge from 1.1) |   and "write" methods and not only file instances. | ||||||
|   - BYTEA now is converted to a real buffer object, not to a string |  | ||||||
|   |   | ||||||
| * buffer objects are now adapted into Binary objects automatically. | psycopg news for 1.1.4 | ||||||
|  | ---------------------- | ||||||
| 
 | 
 | ||||||
| * ported scroll method from 1.1 (DBAPI-2.0 extension for cursors) | * Fixed various memory leak problems. | ||||||
| 
 | 
 | ||||||
| * initial support for some DBAPI-2.0 extensions: | * Implemented "statusmessage" attribute on cursors. | ||||||
|   - .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 | psycopg news for 1.1.3 | ||||||
| ---------------------------- | ---------------------- | ||||||
| 
 | 
 | ||||||
| * implemented microprotocols to adapt arbitrary types to the interface used by | * Fixed problem with psycopg always reporting IntegrityError. | ||||||
|   psycopg to bind variables in execute; |  | ||||||
| 
 | 
 | ||||||
| * moved qstring, pboolean and mxdatetime to the new adapter layout (binary is | * Fixed segfault in debug statements. | ||||||
|   still missing; python 2.3 datetime needs to be written). |  | ||||||
| 
 | 
 | ||||||
|  | * Now Python GIL is unlocked during PQconnectdb() calls (better | ||||||
|  |   multithreading.) | ||||||
| 
 | 
 | ||||||
| What's new in psycopg 1.99.0 | psycopg news for 1.1.2 | ||||||
| ---------------------------- | ---------------------- | ||||||
| 
 | 
 | ||||||
| * reorganized the whole source tree; | * Skipped version 1.1.1 (never released 'cause of a cvs tag error) | ||||||
| 
 | 
 | ||||||
| * async core is in place; | * Much better cursor.description fields (many thanks to William K. Volkman) | ||||||
| 
 | 
 | ||||||
| * splitted QuotedString objects from mx stuff; | * psycopg.connect() now takes keyword parameters for host, dbname, port, | ||||||
|  |   user and password (they are all strings, even "port".) | ||||||
| 
 | 
 | ||||||
| * dropped autotools and moved to pythonic setup.py (needs work.) | * 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.) | ||||||
|  | 
 | ||||||
|  | * 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
									
									
									
									
									
								
							
							
						
						|  | @ -1,26 +1,145 @@ | ||||||
| psycopg - Python-PostgreSQL Database Adapter | psycopg - Python-PostgreSQL Database Adapter | ||||||
| ******************************************** | ******************************************** | ||||||
| 
 | 
 | ||||||
| psycopg is a PostgreSQL database adapter for the Python programming | psycopg is a PostgreSQL database adapter for the Python programming language | ||||||
| language. This is version 2, a complete rewrite of the original code to | (just like pygresql and popy.) It was written from scratch with the aim of | ||||||
| provide new-style classes for connection and cursor objects and other sweet | being very small and fast, and stable as a rock. The main advantages of | ||||||
| candies. Like the original, psycopg 2 was written with the aim of being | psycopg are that it supports (well... *will* support) the full Python | ||||||
| very small and fast, and stable as a rock. | DBAPI-2.0 and being thread safe at level 2. | ||||||
| 
 | 
 | ||||||
| psycopg is different from the other database adapter because it was | psycopg is different from the other database adapter because it was designed | ||||||
| designed for heavily multi-threaded applications that create and destroy | for heavily multi-threaded applications that create and destroy lots of | ||||||
| lots of cursors and make a conspicuous number of concurrent INSERTs or | cursors and make a conspicuous number of concurrent INSERTs or UPDATEs.  | ||||||
| UPDATEs. psycopg 2 also provide full asycronous operations for the really | Every open Python connection keeps a pool of real (UNIX or TCP/IP) connections | ||||||
| brave programmer. | to the database. Every time a new cursor is created, a new connection does not | ||||||
|  | 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. | ||||||
| 
 | 
 | ||||||
| There are confirmed reports of psycopg 1.x compiling and running on Linux | psycopg now support the Python DBAPI-2.0 completely. There are confirmed | ||||||
| and FreeBSD on i386, Solaris, MacOS X and win32 architectures. psycopg 2 | reports of psycopg compiling and running on Linux and FreeBSD on i386, Solaris | ||||||
| does not introduce build-wise incompatible changes so it should be able to | and MacOS X. | ||||||
| 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 | ||||||
| ------- | ------- | ||||||
|  | @ -30,16 +149,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 code in | As a special exception, specific permission is granted for the GPLed | ||||||
| this distribition to be linked to OpenSSL and PostgreSQL libpq without | code in this distribition to be linked to OpenSSL and PostgreSQL libpq | ||||||
| invoking GPL clause 2(b). | without invoking GPL clause 2(b). | ||||||
| 
 | 
 | ||||||
| If you prefer you can use the Zope Database Adapter ZPsycopgDA (i.e., every | If you prefer you can use the Zope Database Adapter ZPsycopgDA (i.e., | ||||||
| file inside the ZPsycopgDA directory) under the ZPL license as published on | every file inside the ZPsycopgDA directory) user the ZPL license as  | ||||||
| the Zope web site, http://www.zope.org/Resources/ZPL. The ZPL is perfectly | published on the Zope web site, http://www.zope.org/Resources/ZPL. | ||||||
| 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. |  | ||||||
|  |  | ||||||
							
								
								
									
										427
									
								
								ZPsycopgDA/DA.py
									
									
									
									
									
								
							
							
						
						|  | @ -1,171 +1,128 @@ | ||||||
| # ZPsycopgDA/DA.py - ZPsycopgDA Zope product: Database Connection | ############################################################################## | ||||||
| #  | #  | ||||||
| # Copyright (C) 2004 Federico Di Gregorio <fog@initd.org> | # Zope Public License (ZPL) Version 1.0 | ||||||
|  | # ------------------------------------- | ||||||
| #  | #  | ||||||
| # 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 |  | ||||||
| # version. |  | ||||||
| #  | #  | ||||||
| # Or, at your option this program (ZPsycopgDA) can be distributed under the | # This license has been certified as Open Source(tm). | ||||||
| # Zope Public License (ZPL) Version 1.0, as published on the Zope web site, |  | ||||||
| # http://www.zope.org/Resources/ZPL. |  | ||||||
| #  | #  | ||||||
| # This program is distributed in the hope that it will be useful, but | # Redistribution and use in source and binary forms, with or without | ||||||
| # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY | # modification, are permitted provided that the following conditions are | ||||||
| # or FITNESS FOR A PARTICULAR PURPOSE. | # met: | ||||||
| #  | #  | ||||||
| # See the LICENSE file for details. | # 1. Redistributions in source code must retain the above copyright | ||||||
|  | #    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 | ||||||
| from Globals import DTMLFile | import Shared.DC.ZRDB.Connection, sys, DABase, time | ||||||
| from Globals import HTMLFile | from Globals import HTMLFile, ImageFile | ||||||
| from ImageFile import ImageFile |  | ||||||
| from ExtensionClass import Base | from ExtensionClass import Base | ||||||
| from DateTime import DateTime | 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 | ||||||
|  | except StandardError, err: | ||||||
|  |     print err | ||||||
|  | try: | ||||||
|  |     from App.Dialogs import MessageDialog | ||||||
|  | except: | ||||||
|  |     pass | ||||||
|  | import time | ||||||
| 
 | 
 | ||||||
| # import psycopg and functions/singletons needed for date/time conversions | manage_addZPsycopgConnectionForm = HTMLFile('connectionAdd', 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) | ||||||
| 
 | 
 | ||||||
| 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. | ||||||
| # add a new connection to a folder | def cast_DateTime(str): | ||||||
| 
 |  | ||||||
| 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, ' ') | ||||||
|  | @ -173,30 +130,158 @@ 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] | ||||||
|             return DateTime(join(dt[:2], ' ')) |             t = time.mktime(time.strptime(join(dt[:2], ' '), '%Y-%m-%d %H:%M:%S')) | ||||||
|         else: |         else: | ||||||
|             return DateTime(dt[0]) |             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 Zope DateTime object | # Convert an ISO date string from postgres to a DateTime(zope version) | ||||||
| def _cast_Date(str): | # object. | ||||||
|  | def cast_Date(str): | ||||||
|     if str: |     if str: | ||||||
|         return DateTime(str) |         return DateTime(time.mktime(time.strptime(str, '%Y-%m-%d'))) | ||||||
| 
 | 
 | ||||||
| # Convert a time string from postgres to a Zope DateTime object. | # Convert a time string from postgres to a DateTime(zope version) object. | ||||||
| # NOTE: we set the day as today before feeding to DateTime so | # WARNING: 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:])) | ||||||
| 
 | 
 | ||||||
| # TODO: DateTime does not support intervals: what's the best we can do? | # Convert a time string from postgres to a DateTime(zope version) object. | ||||||
| def _cast_Interval(str): | # 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 |     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()) | ||||||
|  |  | ||||||
|  | @ -1,61 +1,150 @@ | ||||||
| # ZPsycopgDA/DABase.py - ZPsycopgDA Zope product: Database inspection | ############################################################################## | ||||||
| #  | #  | ||||||
| # Copyright (C) 2004 Federico Di Gregorio <fog@initd.org> | # Zope Public License (ZPL) Version 1.0 | ||||||
|  | # ------------------------------------- | ||||||
| #  | #  | ||||||
| # 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 |  | ||||||
| # version. |  | ||||||
| #  | #  | ||||||
| # Or, at your option this program (ZPsycopgDA) can be distributed under the | # This license has been certified as Open Source(tm). | ||||||
| # Zope Public License (ZPL) Version 1.0, as published on the Zope web site, |  | ||||||
| # http://www.zope.org/Resources/ZPL. |  | ||||||
| #  | #  | ||||||
| # This program is distributed in the hope that it will be useful, but | # Redistribution and use in source and binary forms, with or without | ||||||
| # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY | # modification, are permitted provided that the following conditions are | ||||||
| # or FITNESS FOR A PARTICULAR PURPOSE. | # met: | ||||||
| #  | #  | ||||||
| # See the LICENSE file for details. | # 1. Redistributions in source code must retain the above copyright | ||||||
|  | #    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 | ||||||
| 
 | 
 | ||||||
| import sys | $Id: DABase.py 400 2003-01-20 14:39:34Z fog $''' | ||||||
| import Shared.DC.ZRDB.Connection | __version__='$Revision: 1.10 $'[11:-2] | ||||||
| 
 | 
 | ||||||
| from db import DB | 
 | ||||||
| from Globals import HTMLFile | import Shared.DC.ZRDB.Connection, sys | ||||||
| from ImageFile import ImageFile | from App.Dialogs import MessageDialog | ||||||
|  | from Globals import HTMLFile, ImageFile | ||||||
| from ExtensionClass import Base | from ExtensionClass import Base | ||||||
| from DateTime import DateTime | import Acquisition | ||||||
| 
 | from psycopg import NUMBER, ROWID, STRING, INTEGER, FLOAT | ||||||
| # import psycopg and functions/singletons needed for date/time conversions | from psycopg import BOOLEAN, DATETIME, LONGINTEGER | ||||||
| 
 |  | ||||||
| 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""" | ||||||
|  | @ -65,3 +154,116 @@ 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' | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | @ -1,32 +1,105 @@ | ||||||
| # ZPsycopgDA/__init__.py - ZPsycopgDA Zope product | ############################################################################## | ||||||
| #  | #  | ||||||
| # Copyright (C) 2004 Federico Di Gregorio <fog@initd.org> | # Zope Public License (ZPL) Version 1.0 | ||||||
|  | # ------------------------------------- | ||||||
| #  | #  | ||||||
| # 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 |  | ||||||
| # version. |  | ||||||
| #  | #  | ||||||
| # Or, at your option this program (ZPsycopgDA) can be distributed under the | # This license has been certified as Open Source(tm). | ||||||
| # Zope Public License (ZPL) Version 1.0, as published on the Zope web site, |  | ||||||
| # http://www.zope.org/Resources/ZPL. |  | ||||||
| #  | #  | ||||||
| # This program is distributed in the hope that it will be useful, but | # Redistribution and use in source and binary forms, with or without | ||||||
| # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY | # modification, are permitted provided that the following conditions are | ||||||
| # or FITNESS FOR A PARTICULAR PURPOSE. | # met: | ||||||
| #  | #  | ||||||
| # See the LICENSE file for details. | # 1. Redistributions in source code must retain the above copyright | ||||||
|  | #    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 | ||||||
| 
 | 
 | ||||||
| __doc__ = "ZPsycopg Database Adalper Registration."  | $Id: __init__.py 400 2003-01-20 14:39:34Z fog $''' | ||||||
| __version__ = '2.0' | __version__='$Revision: 1.11 $'[11:-2] | ||||||
| 
 | 
 | ||||||
| import sys | import sys, string | ||||||
| import string |  | ||||||
| import DA | import DA | ||||||
| 
 | 
 | ||||||
| methods    = DA.folder_methods | methods=DA.folder_methods | ||||||
| classes    = DA.classes | misc_ = DA.misc_ | ||||||
| meta_types = DA.meta_types |  | ||||||
| misc_      = DA.misc_ |  | ||||||
| 
 | 
 | ||||||
| __ac_permissions__=DA.__ac_permissions__ | def initialize(context): | ||||||
|  |     """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') | ||||||
|  |  | ||||||
							
								
								
									
										270
									
								
								ZPsycopgDA/db.py
									
									
									
									
									
								
							
							
						
						|  | @ -1,126 +1,171 @@ | ||||||
| # ZPsycopgDA/db.py - query execution | ############################################################################## | ||||||
| #  | #  | ||||||
| # Copyright (C) 2004 Federico Di Gregorio <fog@initd.org> | # Zope Public License (ZPL) Version 1.0 | ||||||
|  | # ------------------------------------- | ||||||
| #  | #  | ||||||
| # 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 |  | ||||||
| # version. |  | ||||||
| #  | #  | ||||||
| # Or, at your option this program (ZPsycopgDA) can be distributed under the | # This license has been certified as Open Source(tm). | ||||||
| # Zope Public License (ZPL) Version 1.0, as published on the Zope web site, |  | ||||||
| # http://www.zope.org/Resources/ZPL. |  | ||||||
| #  | #  | ||||||
| # This program is distributed in the hope that it will be useful, but | # Redistribution and use in source and binary forms, with or without | ||||||
| # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY | # modification, are permitted provided that the following conditions are | ||||||
| # or FITNESS FOR A PARTICULAR PURPOSE. | # met: | ||||||
| #  | #  | ||||||
| # See the LICENSE file for details. | # 1. Redistributions in source code must retain the above copyright | ||||||
|  | #    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 | ||||||
| 
 | 
 | ||||||
| from ZODB.POSException import ConflictError | import string, sys | ||||||
| 
 | from string import strip, split, find | ||||||
| import time | from time import time | ||||||
|  | from types import ListType | ||||||
| import site | import site | ||||||
| import pool |  | ||||||
| 
 | 
 | ||||||
| import psycopg | import psycopg | ||||||
| from psycopg.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN | from psycopg import NUMBER, STRING, INTEGER, FLOAT, DATETIME | ||||||
| from psycopg import NUMBER, STRING, ROWID, DATETIME  | from psycopg import BOOLEAN, ROWID, LONGINTEGER | ||||||
|  | from ZODB.POSException import ConflictError | ||||||
| 
 | 
 | ||||||
|  | class DB(TM,dbi_db.DB): | ||||||
| 
 |  | ||||||
| # 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, dsn, tilevel, enc='utf-8'): |     def __init__(self, connection, tilevel, enc='utf-8'): | ||||||
|         self.dsn = dsn |         self.connection = connection | ||||||
|         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 getconn(self, create=True): |     def connect(self, connection): | ||||||
|         conn = pool.getconn(self.dsn) |         o = psycopg.connect(connection) | ||||||
|         conn.set_isolation_level(int(self.tilevel)) |         o.set_isolation_level(int(self.tilevel)) | ||||||
|         return conn |         return o | ||||||
| 
 |  | ||||||
|     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): | ||||||
|         try: |         if hasattr(self, 'db') and self.db: | ||||||
|             conn = self.getconn(False) |             self.db.commit() | ||||||
|             conn.commit() |  | ||||||
|             self.putconn() |  | ||||||
|         except AttributeError: |  | ||||||
|             pass |  | ||||||
|              |              | ||||||
|     def _abort(self, *ignored): |     def _abort(self, *ignored): | ||||||
|         try: |         if hasattr(self, 'db') and self.db: | ||||||
|             conn = self.getconn(False) |             self.db.rollback() | ||||||
|             conn.rollback() |  | ||||||
|             self.putconn() |  | ||||||
|         except AttributeError: |  | ||||||
|             pass |  | ||||||
|              |              | ||||||
|     def open(self): |     def _cursor(self): | ||||||
|         # this will create a new pool for our DSN if not already existing, |         """Obtains a cursor in a safe way.""" | ||||||
|         # then get and immediately release a connection |         if not hasattr(self, 'db') or not self.db: | ||||||
|         self.getconn() |             self.db = self.connect(self.connection) | ||||||
|         self.putconn() |         return self.db.cursor() | ||||||
|          |  | ||||||
|     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.getcursor() |         c = self._cursor() | ||||||
|         c.execute( |         c.execute('SELECT t.tablename AS NAME, ' | ||||||
|             "SELECT t.tablename AS NAME, 'TABLE' AS TYPE " |                   '\'TABLE\' AS TYPE FROM pg_tables t ' | ||||||
|             "  FROM pg_tables t WHERE tableowner <> 'postgres' " |                   'WHERE tableowner <> \'postgres\' ' | ||||||
|             "UNION SELECT v.viewname AS NAME, 'VIEW' AS TYPE " |                   'UNION SELECT v.viewname AS NAME, ' | ||||||
|             "  FROM pg_views v WHERE viewowner <> 'postgres' " |                   '\'VIEW\' AS TYPE FROM pg_views v ' | ||||||
|             "UNION SELECT t.tablename AS NAME, 'SYSTEM_TABLE\' AS TYPE " |                   'WHERE viewowner <> \'postgres\' ' | ||||||
|             "  FROM pg_tables t WHERE tableowner = 'postgres' " |                   'UNION SELECT t.tablename AS NAME, ' | ||||||
|             "UNION SELECT v.viewname AS NAME, 'SYSTEM_TABLE' AS TYPE " |                   '\'SYSTEM_TABLE\' AS TYPE FROM pg_tables t ' | ||||||
|             "FROM pg_views v WHERE viewowner = 'postgres'") |                   'WHERE tableowner = \'postgres\' ' | ||||||
|         res = [] |                   'UNION SELECT v.viewname AS NAME, ' | ||||||
|  |                   '\'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: | ||||||
|                 res.append({'TABLE_NAME': name, 'TABLE_TYPE': typ}) |                 a({'TABLE_NAME': name, 'TABLE_TYPE': typ}) | ||||||
|         self.putconn() |         c.close() | ||||||
|         return res |         return r | ||||||
| 
 | 
 | ||||||
|     def columns(self, table_name): |     def columns(self, table_name): | ||||||
|         self._register() |         self._register() | ||||||
|         c = self.getcursor() |         c = self._cursor() | ||||||
|         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 () | ||||||
|         res = [] |         desc = c.description | ||||||
|         for name, type, width, ds, p, scale, null_ok in c.description: |         r = [] | ||||||
|  |         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 | ||||||
|  | @ -135,50 +180,46 @@ 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 = () | ||||||
|         res = [] |         result = [] | ||||||
|         nselects = 0 |         nselects = 0 | ||||||
|          |          | ||||||
|         c = self.getcursor() |         c = self._cursor() | ||||||
|          |          | ||||||
|         try: |         try: | ||||||
|             for qs in [x for x in query_string.split('\0') if x]: |             for qs in filter(None, map(strip, split(query_string, '\0'))): | ||||||
|                 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): | ||||||
|                         c.execute(qs, query_data) |                         r = c.execute(qs, query_data) | ||||||
|                     else: |                     else: | ||||||
|                         c.execute(qs) |                         r = c.execute(qs) | ||||||
|                 except (psycopg.ProgrammingError, psycopg.IntegrityError), e: |                 except (psycopg.ProgrammingError,psycopg.IntegrityError), perr: | ||||||
|                     if e.args[0].find("concurrent update") > -1: |                     if perr.args[0].find("concurrent update") > -1: | ||||||
|                         raise ConflictError |                         raise ConflictError | ||||||
|                     raise e |                     raise perr | ||||||
|                 if c.description is not None: |                 if c.description is not None: | ||||||
|                     nselects += 1 |                     nselects = nselects + 1 | ||||||
|                     if c.description != desc and nselects > 1: |                     if c.description != desc and nselects > 1: | ||||||
|                         raise psycopg.ProgrammingError( |                         raise 'Query Error', \ | ||||||
|                             'multiple selects in single query not allowed') |                               'Multiple select schema are not allowed' | ||||||
|                     if max_rows: |                     if max_rows: | ||||||
|                         res = c.fetchmany(max_rows) |                         result = c.fetchmany(max_rows) | ||||||
|                     else: |                     else: | ||||||
|                         res = c.fetchall() |                         result = c.fetchall() | ||||||
|                     desc = c.description |                     desc = c.description | ||||||
|             self.failures = 0 |             self.failures = 0 | ||||||
|              |              | ||||||
|  | @ -206,4 +247,13 @@ class DB(TM, dbi_db.DB): | ||||||
|                 'null': null_ok, |                 'null': null_ok, | ||||||
|                 }) |                 }) | ||||||
| 
 | 
 | ||||||
|         return items, res |         return items, result | ||||||
|  | 
 | ||||||
|  |     def close(self): | ||||||
|  |         """Close the connection.""" | ||||||
|  |         self.db.close() | ||||||
|  |         self.db = None | ||||||
|  |          | ||||||
|  |     def sortKey(self): | ||||||
|  |         """Zope 2.6 added this one.""" | ||||||
|  |         return 1 | ||||||
|  |  | ||||||
| Before Width: | Height: | Size: 924 B After Width: | Height: | Size: 924 B | 
| Before Width: | Height: | Size: 929 B After Width: | Height: | Size: 929 B | 
| Before Width: | Height: | Size: 918 B After Width: | Height: | Size: 918 B | 
| Before Width: | Height: | Size: 878 B After Width: | Height: | Size: 878 B | 
| Before Width: | Height: | Size: 918 B After Width: | Height: | Size: 918 B | 
| Before Width: | Height: | Size: 894 B After Width: | Height: | Size: 894 B |