From peter_e at gmx.net Mon Apr 7 23:21:55 2014 From: peter_e at gmx.net (Peter Eisentraut) Date: Mon, 07 Apr 2014 17:21:55 -0400 Subject: [DB-SIG] Prepared statements in python drivers In-Reply-To: References: Message-ID: <534316F3.2080803@gmx.net> On 3/24/14, 12:53 PM, Daniele Varrazzo wrote: > - is there enough consensus - not only in the Python world - about how > to implement a prepared statements interface on a db driver? In other languages, there is often a parameter on the connection handle saying whether (the analogue of) a prepare+execute call should be only a parameter substitution or a full prepared statement. I think this is due to the historical confusion between these aspects and therefore not a good idea for a new API. In Python, adding an explicit prepare function and having that actually prepare in all cases sounds like a decent idea to me. From vernondcole at gmail.com Tue Apr 8 08:52:32 2014 From: vernondcole at gmail.com (Vernon D. Cole) Date: Tue, 8 Apr 2014 00:52:32 -0600 Subject: [DB-SIG] Prepared statements in python drivers In-Reply-To: <534316F3.2080803@gmx.net> References: <534316F3.2080803@gmx.net> Message-ID: Let me (as the maintainer of a competing product) be the one to say this: If prepared statements were to become standardized (either by an extension of PEP-249 or by a new Python3 compatible PEP) it should be simply a codification of the existing API used by mxodbc. (see mxODBC.pdf). It is a good system, well thought out, simple, proven, and already implemented for numerous databases. Here is a brief description: A cursor "X" has a method "X.prepare()" which does nothing except create side effects. The required side effect is to set an attribute "X.command" which is simply a reference to its first positional argument. It may optionally also have the side effect of sending an appropriate query preparation statement to its database engine. An optional third side effect is that it may also populate the "X.description" array (my anticipated implementation will not do that). If the first positional argument of a subsequent "X.execute()" statement also refers to the same query string, then the package may use the prepared statement to query the database. If the strings are different, it merely starts over as if no "X.prepare()" had been executed. In other words, the following three code snippets will have exactly the same effect (except for timing): crsr = some_connection.cursor() # prepared statement crsr.prepare("select * from SomeSQLtable") crsr.execute(crsr.command) # the way we do it now crsr.execute("select * from SomeSQLtable") # an otherwise harmless waste of time crsr.prepare("select * from ThisIsNotTheTableYouAreLookingForMoveAlong") crsr.execute("select * from SomeSQLtable") The only standard needed is: "If a .prepare() method is provided, it must define .command, and set .description to either None, or a valid result from the query." # this would be a compliant driver snippet class MySqlApi(object): def prepare(self, sql): self.command = sql self.description = None -- Vernon Cole On Mon, Apr 7, 2014 at 3:21 PM, Peter Eisentraut wrote: > On 3/24/14, 12:53 PM, Daniele Varrazzo wrote: > > - is there enough consensus - not only in the Python world - about how > > to implement a prepared statements interface on a db driver? > > In other languages, there is often a parameter on the connection handle > saying whether (the analogue of) a prepare+execute call should be only a > parameter substitution or a full prepared statement. I think this is > due to the historical confusion between these aspects and therefore not > a good idea for a new API. In Python, adding an explicit prepare > function and having that actually prepare in all cases sounds like a > decent idea to me. > > _______________________________________________ > DB-SIG maillist - DB-SIG at python.org > https://mail.python.org/mailman/listinfo/db-sig > -------------- next part -------------- An HTML attachment was scrubbed... URL: From info at egenix.com Tue Apr 8 09:18:24 2014 From: info at egenix.com (eGenix Team: M.-A. Lemburg) Date: Tue, 08 Apr 2014 09:18:24 +0200 Subject: [DB-SIG] ANN: eGenix mxODBC 3.3.0 - Python ODBC Database Interface Message-ID: <5343A2C0.4090600@egenix.com> ________________________________________________________________________ ANNOUNCING eGenix.com mxODBC Python ODBC Database Interface Version 3.3.0 mxODBC is our commercially supported Python extension providing ODBC database connectivity to Python applications on Windows, Mac OS X, Unix and BSD platforms This announcement is also available on our web-site for online reading: http://www.egenix.com/company/news/eGenix-mxODBC-3.3.0-GA.html ________________________________________________________________________ INTRODUCTION mxODBC provides an easy-to-use, high-performance, reliable and robust Python interface to ODBC compatible databases such as MS SQL Server, MS Access, Oracle Database, IBM DB2 and Informix , Sybase ASE and Sybase Anywhere, MySQL, PostgreSQL, SAP MaxDB and many more: http://www.egenix.com/products/python/mxODBC/ The "eGenix mxODBC - Python ODBC Database Interface" product is a commercial extension to our open-source eGenix mx Base Distribution: http://www.egenix.com/products/python/mxBase/ ________________________________________________________________________ NEWS The 3.3.0 release of our mxODBC is a new release of our popular Python ODBC Interface for Windows, Linux, Mac OS X and FreeBSD. New Features in 3.3 ------------------- Stored Procedures * mxODBC now has full support for input, output and input/output parameters in stored procedures and stored functions, allowing easy integration with existing databases systems. User Customizable Row Objects * Added support for user customizable row objects by adding cursor/connection .rowfactory and .row constructor attributes. When set, these are used to wrap the normal row tuples returned by the .fetch*() methods into dynamically created row objects. * Added new RowFactory classes to support cursor.rowfactory and cursor.row. These allow dynamically creating row classes that provide sequence as well as mapping and attribute access to row fields - similar to what namedtuples implement, but specific to result sets. Fast Cursor Types * Switched to forward-only cursor types for all database backends, since this provides a much better performance for MS SQL Server and IBM DB2 drivers. * Added a new .cursortype attribute to allow adjusting and inspecting the ODBC cursor type to be used for an mxODBC cursor object. Default is to use forward-only cursors, but mxODBC also support several other useful cursor types such as static cursors with full support for result set scrolling. More new Features * Custom errorhandlers are now also called very early during the connection process. This makes it possible to debug e.g. ODBC driver/manager setup problems from within Python, without having to resort to ODBC trace files. * Enhanced cursor.prepare() to allow querying cursor.description right after the prepare step and not only after calling a cursor.execute*() method. * Added iterator/generator support to .executemany(). The parameters list can now be an iterator/generator, if needed. * Added new connection.dbapi property to easily access module level symbols from the connection object. * Timestamp seconds fraction resolution is now determined from the scale of a datetime/timestamp SQL column, using the connection.timestampresolution as lower bound, when using SQL type binding. In Python type binding, the connection.timestampresolution determines the scale with which a variable is bound. This allows for greater flexibility when dealing with database backends that don't provide full nano-second second resolution, such as e.g. MS SQL Server. * mxODBC now accepts Unicode string values for date/time/datetime/timestamp column types in SQL type binding mode. Previous versions already did in Python type binding mode. * mxODBC now uses unicode(obj, encoding) semantics when binding Python objects to SQLWCHAR database parameters. Additionally, it ignores the encoding in case obj is a number, to avoid conversion errors. * Added new cursor.encoding and (read-only) cursor.converter attributes. Both inherit their default values from the connection the cursor was created on. * Added cursor.bindmethod which inherits from connection.bindmethod when creating the cursor. This allows adjusting the variable bind method on a per-cursor basis, rather than only on a per connection basis as in previous mxODBC versions. * mxODBC is now built against unixODBC 2.3.2. * The SQL lookup object now supports ODBC 3.8 symbols and values, including driver specific symbols used by the MS SQL Server Native Client and IBM DB2 ODBC drivers. * Updated the DataDirect binding to version 7.1.2 of the DataDirect ODBC manager. For the full set of features mxODBC has to offer, please see: http://www.egenix.com/products/python/mxODBC/#Features Driver Compatibility Enhancements --------------------------------- Oracle * Added work-around for Oracle Instant Client to be able to use integer output parameters. * Added a work-around for Oracle Instant Client to have it return output parameters based on the input placeholder Python parameter types. It would otherwise return all parameters as strings. * Disabled a test for Oracle Instant Client which tries to set a pre-connect connection option for timeouts, since the ODBC driver segfaults with this option. MS SQL Server * mxODBC now defaults to 100ns connection.timestampresolution for MS SQL Server 2008 and later, and 1ms resolution for MS SQL server 2005 and earlier. This simplifies interfacing to SQL Server timestamp columns by preventing occasional precision errors. * Tested mxODBC successfully with new MS SQL Server Native Client 11 for Linux. Unicode connection strings still don't work, but everything else does. * Added documentation on how to use Kerberos with mxODBC and SQL Server fo authentication on both Windows and Linux. * Added note about problems of the FreeTDS ODBC driver dealing with TIME and DATE columns to the documentation. Sybase ASE * Added work-around for the Sybase ASE ODBC driver, which doesn't always pass back NULL correctly to mxODBC on 64-bit Unix systems. * Changed the variable type binding mode default for the Sybase ASE ODBC driver from Python type binding to SQL type binding, which resolves issues with e.g. the Unicode support for that driver. * Added note about a segfault problem with the Sybase ASE 15.7 ODBC driver which is caused by the driver corrupting the heap. IBM DB2 * Added work-around for the IBM DB2 ODBC driver, which doesn't always pass back NULL correctly to mxODBC on 64-bit Unix systems. PostgreSQL * Added work-around to force Python type binding for the PostgreSQL ODBC drivers. More recent versions of the driver report supporting SQL type binding, but they don't implement it. * Added work-around to have PostgreSQL ODBC drivers properly work with binary data for BYTEA columns. MySQL * mxODBC now supports native Unicode with the recent MySQL ODBC drivers - provided you use the Unicode variants of the drivers. * Changed the default binding mode for MySQL ODBC drivers to Python type binding. This works around a problem with date/time values when talking to MySQL 5.6 servers. For the full set of changes please check the mxODBC change log: http://www.egenix.com/products/python/mxODBC/changelog.html The Future --------------- * Please note that this will be the last release of mxODBC for Python 2.4, 2.5 and 2.6. For the next release of mxODBC, we are focusing on making the code Python 2.7 and Python 3.x compatible, dropping support for earlier Python versions. * If you need long term support for these older Python versions, please contact sales at egenix.com. We can then arrange custom support contracts for you. mxODBC Editions --------------- mxODBC is available in these two editions: * The Professional Edition, which gives full access to all mxODBC features. * The Product Development Edition, which allows including mxODBC in applications you develop. For a complete overview of the new editions, please see the product page. http://www.egenix.com/products/python/mxODBC/#mxODBCEditions ________________________________________________________________________ DOWNLOADS The download archives and instructions for installing the package can be found at: http://www.egenix.com/products/python/mxODBC/ In order to use the eGenix mxODBC package you will first need to install the eGenix mx Base package: http://www.egenix.com/products/python/mxBase/ ________________________________________________________________________ UPGRADING Users are encouraged to upgrade to this latest mxODBC release to benefit from the new features and updated ODBC driver support. We have taken special care, not to introduce backwards incompatible changes, making the upgrade experience as smooth as possible. For upgrade purchases, we will give out 20% discount coupons going from mxODBC 2.x to 3.3 and 50% coupons for upgrades from mxODBC 3.x to 3.3. After upgrade, use of the original license from which you upgraded is no longer permitted. Please contact the eGenix.com Sales Team at sales at egenix.com with your existing license serials for details for an upgrade discount coupon. If you want to try the new release before purchace, you can request 30-day evaluation licenses by visiting our web-site http://www.egenix.com/products/python/mxODBC/#Evaluation or by writing to sales at egenix.com, stating your name (or the name of the company) and the number of eval licenses that you need. _______________________________________________________________________ SUPPORT Commercial support for this product is available from eGenix.com. Please see http://www.egenix.com/services/support/ for details about our support offerings. _______________________________________________________________________ INFORMATION About Python (http://www.python.org/): Python is an object-oriented Open Source programming language which runs on all modern platforms. By integrating ease-of-use, clarity in coding, enterprise application connectivity and rapid application design, Python establishes an ideal programming platform for today's IT challenges. About eGenix (http://www.egenix.com/): eGenix is a software project, consulting and product company focusing on expert services and professional quality products for companies, Python users and developers. PS: If you want to meet with eGenix at PyCon 2014, please send an email and we can arrange a meeting. Enjoy, -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Apr 08 2014) >>> Python Projects, Consulting and Support ... http://www.egenix.com/ >>> mxODBC.Zope/Plone.Database.Adapter ... http://zope.egenix.com/ >>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/ ________________________________________________________________________ 2014-04-09: PyCon 2014, Montreal, Canada ... tomorrow 2014-04-29: Python Meeting Duesseldorf ... 21 days to go ::::: Try our mxODBC.Connect Python Database Interface for free ! :::::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/ From songofacandy at gmail.com Wed Apr 9 04:49:33 2014 From: songofacandy at gmail.com (INADA Naoki) Date: Wed, 9 Apr 2014 11:49:33 +0900 Subject: [DB-SIG] Prepared statements in python drivers In-Reply-To: <534316F3.2080803@gmx.net> References: <534316F3.2080803@gmx.net> Message-ID: +1 on explicit separation between prepared statement and server-side placeholder. Prepared statement holds resource on server side. For example, following code is dangerous when combined with connection pool. def myexecute(params): cur = con.cursor() cur.prepare(MY_STMT) # allocate resource on server-side that is freed when connection is closed. return cur.execute(params) I think prepared statement should be bound to connection. Connection.prapare(name, stmt, skip_on_dup=False) Prepare stmt as name. If skip_on_dup is true and same name is prepared before, do nothing. Cursor.execute_prepared(name, params, stmt=None) Execute prepared statement named name. If stmt is not None, call Cursor.prepare(name, stmt, skip_on_dup=True) before execute. Example 1: def myexecute(params): cur = connection.cursor() return cur.execute_prepared("mystmt", params, MY_STMT) Example 2: def create_connection(opts): global _connection _connection = MyDB.connect(**opts) _connection.prepare("mystmt", MY_STMT) def myexecute(params): cur = _connection.cursor() cur.execute_prepared("mystmt", params) On Tue, Apr 8, 2014 at 6:21 AM, Peter Eisentraut wrote: > On 3/24/14, 12:53 PM, Daniele Varrazzo wrote: >> - is there enough consensus - not only in the Python world - about how >> to implement a prepared statements interface on a db driver? > > In other languages, there is often a parameter on the connection handle > saying whether (the analogue of) a prepare+execute call should be only a > parameter substitution or a full prepared statement. I think this is > due to the historical confusion between these aspects and therefore not > a good idea for a new API. In Python, adding an explicit prepare > function and having that actually prepare in all cases sounds like a > decent idea to me. > > _______________________________________________ > DB-SIG maillist - DB-SIG at python.org > https://mail.python.org/mailman/listinfo/db-sig -- INADA Naoki From fog at initd.org Wed Apr 9 11:24:22 2014 From: fog at initd.org (Federico Di Gregorio) Date: Wed, 09 Apr 2014 11:24:22 +0200 Subject: [DB-SIG] Prepared statements in python drivers In-Reply-To: References: <534316F3.2080803@gmx.net> Message-ID: <534511C6.5050103@initd.org> On 09/04/2014 04:49, INADA Naoki wrote: > Prepared statement holds resource on server side. > For example, following code is dangerous when combined with connection pool. > > def myexecute(params): > cur = con.cursor() > cur.prepare(MY_STMT) # allocate resource on server-side that is > freed when connection is closed. > return cur.execute(params) > > I think prepared statement should be bound to connection. > > Connection.prapare(name, stmt, skip_on_dup=False) > Prepare stmt as name. > If skip_on_dup is true and same name is prepared before, do nothing. > > Cursor.execute_prepared(name, params, stmt=None) > Execute prepared statement named name. > If stmt is not None, call Cursor.prepare(name, stmt, skip_on_dup=True) > before execute. This seems to complicate the code for no gain. The API previously proposed is much better IMO. federico -- Federico Di Gregorio federico.digregorio at dndg.it Di Nunzio & Di Gregorio srl http://dndg.it E tu usa il prefisso corretto Re: non R:, questa ? una ML seria. -- cosmos, su debian-italian From phd at phdru.name Sun Apr 13 14:29:13 2014 From: phd at phdru.name (Oleg Broytman) Date: Sun, 13 Apr 2014 14:29:13 +0200 Subject: [DB-SIG] SQLObject 1.5.2 Message-ID: <20140413122913.GA12301@phdru.name> Hello! I'm pleased to announce version 1.5.2, the second bugfix release of branch 1.5 of SQLObject. What's new in SQLObject ======================= * Adapt duplicate error message strings for SQLite 3.8. Contributor for this release is Neil Muller. For a more complete list, please see the news: http://sqlobject.org/News.html What is SQLObject ================= SQLObject is an object-relational mapper. Your database tables are described as classes, and rows are instances of those classes. SQLObject is meant to be easy to use and quick to get started with. SQLObject supports a number of backends: MySQL, PostgreSQL, SQLite, Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB). Where is SQLObject ================== Site: http://sqlobject.org Development: http://sqlobject.org/devel/ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Archives: http://news.gmane.org/gmane.comp.python.sqlobject Download: https://pypi.python.org/pypi/SQLObject/1.5.2 News and changes: http://sqlobject.org/News.html Oleg. -- Oleg Broytman http://phdru.name/ phd at phdru.name Programmers don't die, they just GOSUB without RETURN. From songofacandy at gmail.com Wed Apr 9 12:13:34 2014 From: songofacandy at gmail.com (INADA Naoki) Date: Wed, 9 Apr 2014 19:13:34 +0900 Subject: [DB-SIG] Prepared statements in python drivers In-Reply-To: <534511C6.5050103@initd.org> References: <534316F3.2080803@gmx.net> <534511C6.5050103@initd.org> Message-ID: >> I think prepared statement should be bound to connection. >> >> Connection.prapare(name, stmt, skip_on_dup=False) >> Prepare stmt as name. >> If skip_on_dup is true and same name is prepared before, do nothing. >> >> Cursor.execute_prepared(name, params, stmt=None) >> Execute prepared statement named name. >> If stmt is not None, call Cursor.prepare(name, stmt, skip_on_dup=True) >> before execute. > > This seems to complicate the code for no gain. The API previously > proposed is much better IMO. > > federico Previously proposed API may prepare multiple times. My propose make it easier to reuse same prepared statement over function call. Imagine about simple, high performance simple API server. One API call may execute one statement, but it called so often. -- INADA Naoki From vernondcole at gmail.com Fri Apr 18 19:18:28 2014 From: vernondcole at gmail.com (Vernon D. Cole) Date: Fri, 18 Apr 2014 11:18:28 -0600 Subject: [DB-SIG] stored procedure writing contest (not really, but please contribute) Message-ID: Dear Sig-ites: I am in the process of expanding the test coverage for adodbapi. I have working tests for stored procedure operation for MS SQL Server, but my feeble efforts to write working "sproc"s for PostgreSQL and MySQL were dismal failures. So... I am soliciting code... I have put my unit test class definition for SQL Server into a Gist at: https://gist.github.com/vernondcole/11053526 I two (or more) of you would be so kind, Please expand this test suite to include your favorite database engine. If this works the result could perhaps be included in a some future version of the general db-api compliance test. -------------- next part -------------- An HTML attachment was scrubbed... URL: From info at egenix.com Thu Apr 24 10:47:28 2014 From: info at egenix.com (eGenix Team: M.-A. Lemburg) Date: Thu, 24 Apr 2014 10:47:28 +0200 Subject: [DB-SIG] ANN: eGenix mxODBC Connect 2.0.5 - Python ODBC Database Interface Message-ID: <5358CFA0.50204@egenix.com> ________________________________________________________________________ ANNOUNCING eGenix.com mxODBC Connect Python ODBC Database Interface Version 2.0.5 mxODBC Connect is our commercially supported client-server product for connecting Python applications to relational databases in a truly platform independent way. This announcement is also available on our web-site for online reading: http://www.egenix.com/company/news/eGenix-mxODBC-Connect-2.0.5-GA.html ________________________________________________________________________ INTRODUCTION The mxODBC Connect Database Interface for Python allows users to easily connect Python applications to all major databases on the market today in a highly portable, convenient and secure way. Python Database Connectivity the Easy Way ----------------------------------------- Unlike our mxODBC Python extension, mxODBC Connect is designed as client-server application, so you no longer need to find production quality ODBC drivers for all the platforms you target with your Python application. Instead you use an easy to install royalty-free Python client library which connects directly to the mxODBC Connect database server over the network. This makes mxODBC Connect a great basis for writing cross-platform multi-tier database applications and utilities in Python, especially if you run applications that need to communicate with databases such as MS SQL Server and MS Access, Oracle Database, IBM DB2 and Informix, Sybase ASE and Sybase Anywhere, MySQL, PostgreSQL, SAP MaxDB and many more, that run on Windows or Linux machines. Ideal for Database Driven Client Applications --------------------------------------------- By removing the need to install and configure ODBC drivers on the client side and dealing with complicated network setups for each set of drivers, mxODBC Connect greatly simplifies deployment of database driven client applications, while at the same time making the network communication between client and database server more efficient and more secure. For more information, please have a look at the mxODBC Connect product page, in particular, the full list of available features. For more information, please see the product page: http://www.egenix.com/products/python/mxODBCConnect/ ________________________________________________________________________ NEWS The 2.0.5 release of mxODBC Connect includes the following enhancements and fixes: Security Enhancements --------------------- * Upgraded client and server to the most recent eGenix pyOpenSSL Distribution 0.13.3.1.0.1.7 (see http://egenix.com/go54 for details) to address the recently found Heartbleed Bug in OpenSSL 1.0.1 - 1.0.1f: - CVE-2014-0160 ("Heartbleed Bug"): A missing bounds check in the handling of the TLS heartbeat extension can be used to reveal up to 64kB of memory to a connected client or server. This issue did not affect versions of OpenSSL prior to 1.0.1. For information, also have a look at the Heartbleed Bug website: http://heartbleed.com/ For the full set of changes, please check the mxODBC Connect change log: http://www.egenix.com/products/python/mxODBCConnect/changelog.html mxODBC Connect 2.0 Highlights ----------------------------- mxODBC Connect 2.0 was released on 2012-08-20. These are the most important highlights: * mxODBC Connect Server now uses mxODBC 3.2 internally and makes its API available in the mxODBC Connect Client. This is a major step forward from the mxODBC 3.0 version used in mxODBC Connect Server 1.0. * We've added native Windows x64 builds. * mxODBC Connect Client now integrates directly with gevent, allowing client applications to run asynchronous tasks while performing remote database queries. Please see the release announcement for full details: http://www.egenix.com/company/news/eGenix-mxODBC-Connect-2.0.0-GA.html ________________________________________________________________________ UPGRADING You are encouraged to upgrade to this latest mxODBC Connect release. When upgrading, please always upgrade both the server and the client installations to the same version - even for patch level releases. Customers who have purchased mxODBC Connect 2.0 licenses can continue to use their licenses with this patch level release. Customers who have purchased mxODBC Connect 1.x licenses can request 20% discount coupons for upgrade purchases. Please contact the eGenix.com Sales Team (sales at egenix.com) with your existing license serials for details. Users of our stand-alone mxODBC product will have to purchase new licenses from our online shop in order to use mxODBC Connect. You can request 30-day evaluation licenses by visiting our web-site or writing to sales at egenix.com, stating your name (or the name of the company) and the number of eval licenses that you need. http://www.egenix.com/products/python/mxODBCConnect/#Evaluation ________________________________________________________________________ DOWNLOADS The download archives as well as instructions for installation and configuration of the product can be found on the product page: http://www.egenix.com/products/python/mxODBCConnect/ If you want to try the package, jump straight to the download instructions: https://cms.egenix.com/products/python/mxODBCConnect/#Download Fully functional evaluation licenses for the mxODBC Connect Server are available free of charge: http://www.egenix.com/products/python/mxODBCConnect/#Evaluation mxODBC Connect Client is always free of charge. _______________________________________________________________________ SUPPORT Commercial support for this product is available from eGenix.com. Please see http://www.egenix.com/services/support/ for details about our support offerings. _______________________________________________________________________ INFORMATION About Python (http://www.python.org/): Python is an object-oriented Open Source programming language which runs on all modern platforms. By integrating ease-of-use, clarity in coding, enterprise application connectivity and rapid application design, Python establishes an ideal programming platform for today's IT challenges. About eGenix (http://www.egenix.com/): eGenix is a software project, consulting and product company focusing on expert project services and professional quality products for companies, Python users and developers. Enjoy, -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source >>> Python/Zope Consulting and Support ... http://www.egenix.com/ >>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/ >>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/ ________________________________________________________________________ ::: Try our new mxODBC.Connect Python Database Interface for free ! :::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/