From f36e7ff0927bdae6ea477cb64be9088307e5bddd Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Mon, 2 Oct 2000 03:27:33 +0000 Subject: [PATCH] Update for PyGreSQL 3.0, from D'Arcy J.M. Cain --- doc/TODO | 2 +- src/interfaces/python/Announce | 58 +- src/interfaces/python/ChangeLog | 25 +- src/interfaces/python/PyGreSQL.spec | 57 + src/interfaces/python/README | 143 +- src/interfaces/python/README.linux | 5 + src/interfaces/python/mkdefines | 2 +- src/interfaces/python/pg.py | 44 +- src/interfaces/python/pgdb.py | 401 +++++ src/interfaces/python/pgmodule.c | 1701 +++++++++++++++----- src/interfaces/python/pgsqldb.py | 46 - src/interfaces/python/setup.py | 43 + src/interfaces/python/tutorial/advanced.py | 171 -- src/interfaces/python/tutorial/basics.py | 284 ---- src/interfaces/python/tutorial/func.py | 193 --- src/interfaces/python/tutorial/pgtools.py | 48 - src/interfaces/python/tutorial/syscat.py | 133 -- 17 files changed, 1982 insertions(+), 1374 deletions(-) create mode 100644 src/interfaces/python/PyGreSQL.spec create mode 100644 src/interfaces/python/pgdb.py delete mode 100644 src/interfaces/python/pgsqldb.py create mode 100755 src/interfaces/python/setup.py delete mode 100755 src/interfaces/python/tutorial/advanced.py delete mode 100755 src/interfaces/python/tutorial/basics.py delete mode 100755 src/interfaces/python/tutorial/func.py delete mode 100755 src/interfaces/python/tutorial/pgtools.py delete mode 100755 src/interfaces/python/tutorial/syscat.py diff --git a/doc/TODO b/doc/TODO index 60102d7e50..49561e76de 100644 --- a/doc/TODO +++ b/doc/TODO @@ -250,7 +250,7 @@ MISC * allow configuration of maximum number of open files * Remove pg_listener index * Remove ANALYZE from VACUUM so it can be run separately without locks -* Gather more accurate statistics using indexes +* Gather more accurate disbursion statistics using indexes * Improve statistics storage in pg_class [performance] * Improve VACUUM speed with indexes [vacuum] * -BSD/OS does not support locale because there is no LC_MESSAGES (Bruce) diff --git a/src/interfaces/python/Announce b/src/interfaces/python/Announce index 38c8f4eda3..b02f83670b 100644 --- a/src/interfaces/python/Announce +++ b/src/interfaces/python/Announce @@ -1,14 +1,11 @@ -Announce: Release of PyGreSQL version 2.4 +Announce: Release of PyGreSQL version 3.0 =============================================== -PyGreSQL v2.4 has been released. +PyGreSQL v3.0 has been released. It is available at: ftp://ftp.druid.net/pub/distrib/PyGreSQL.tgz. If -you are on NetBSD, look in the packages directory under databases. If -it isn't there yet, it should be there shortly. You can also pick up the -package files from ftp://ftp.druid.net/pub/distrib/pygresql.pkg.tgz. -There is also a package in the FreeBSD ports collection but as I write -this it is at version 2.1. I will try to get that updated as well. +you are running NetBSD, look in the packages directory under databases. +There is also a package in the FreeBSD ports collection. PostgreSQL is a database system derived from Postgres4.2. It conforms to (most of) ANSI SQL and offers many interesting capabilities (C @@ -28,19 +25,49 @@ PyGreSQL is a python module that interfaces to a PostgreSQL database. It embeds the PostgreSQL query library to allow easy use of the powerful PostgreSQL features from a Python script. -I wanted to have DB-SIG API support in the next release but there are -enough fixes and improvements to make one more release before starting -on that. The next version will be 3.0 and have the DB-SIG API support. -Note that I said this for 2.4 but some required changes from others have -been slow in coming (I'm not complaining, people do have lives) and -there were enough fixes that I didn't want to keep them from a release. +This release of PyGreSQL is the first DB-SIG API. That's why we have +a bump in the major number. There is also a potential problem in +backwards compatibility. Previously when there was a NULL in a returned +field it was returned as a blank. Now it is more properly returned as +a Python None. Any scripts that expect NULLs to be blanks will have +problems with this. -PyGreSQL 2.3 was developed and tested on a NetBSD 1.3_BETA system. It +Due to the fact that the DB-API is brand new, it is expected that there +will be a 3.1 release shortly with corrections once many people have +had a chance to test it. + +See the other changes below or in the Changelog file. + +PyGreSQL 2.0 was developed and tested on a NetBSD 1.3_BETA system. It is based on the PyGres95 code written by Pascal Andre, andre@chimay.via.ecp.fr. I changed the version to 2.0 and updated the code for Python 1.5 and PostgreSQL 6.2.1. While I was at it I upgraded the code to use full ANSI style prototypes and changed the order of arguments to connect. Later versions are fixes and enhancements to that. +The latest version of PyGreSQL works with Python 1.5.2 and PostgreSQL 6.5. + +Important changes from PyGreSQL 2.4 to PyGreSQL 3.0: + - Remove strlen() call from pglarge_write() and get size from object. + (Richard@Bouska.cz) + - Add a little more error checking to the quote function in the wrapper + - Add extra checking in _quote function + - Wrap query in pg.py for debugging + - Add DB-API 2.0 support to pgmodule.c (andre@via.ecp.fr) + - Add DB-API 2.0 wrapper pgdb.py (andre@via.ecp.fr) + - Correct keyword clash (temp) in tutorial + - Clean up layout of tutorial + - Return NULL values as None (rlawrence@lastfoot.com) (WARNING: This + will cause backwards compatibility issues.) + - Change None to NULL in insert and update + - Change hash-bang lines to use /usr/bin/env + - Clearing date should be blank (NULL) not TODAY + - Quote backslashes in strings in _quote (brian@CSUA.Berkeley.EDU) + - Expanded and clarified build instructions (tbryan@starship.python.net) + - Make code thread safe (Jerome.Alet@unice.fr) + - Add README.distutils (mwa@gate.net & jeremy@cnri.reston.va.us) + - Many fixes and increased DB-API compliance by chifungfan@yahoo.com, + tony@printra.net, jeremy@alum.mit.edu and others to get the final + version ready to release. Important changes from PyGreSQL 2.3 to PyGreSQL 2.4: - Insert returns None if the user doesn't have select permissions @@ -48,10 +75,11 @@ Important changes from PyGreSQL 2.3 to PyGreSQL 2.4: not select permissions on a table. - Added ntuples() method to query object (brit@druid.net) - Corrected a bug related to getresult() and the money type - - Corrected a but related to negative money amounts + - Corrected a bug related to negative money amounts - Allow update based on primary key if munged oid not available and table has a primary key - Add many __doc__ strings. (andre@via.ecp.fr) + - Get method works with views if key specified Important changes from PyGreSQL 2.2 to PyGreSQL 2.3: - connect.host returns "localhost" when connected to Unix socket diff --git a/src/interfaces/python/ChangeLog b/src/interfaces/python/ChangeLog index 68d722bee6..84f3fb78b1 100644 --- a/src/interfaces/python/ChangeLog +++ b/src/interfaces/python/ChangeLog @@ -5,16 +5,39 @@ This software is copyright (c) 1995, Pascal Andre (andre@via.ecp.fr) Further copyright 1997, 1998 and 1999 by D'Arcy J.M. Cain (darcy@druid.net) See file README for copyright information. +Version 3.0 + - Remove strlen() call from pglarge_write() and get size from object. + (Richard@Bouska.cz) + - Add a little more error checking to the quote function in the wrapper + - Add extra checking in _quote function + - Wrap query in pg.py for debugging + - Add DB-API 2.0 support to pgmodule.c (andre@via.ecp.fr) + - Add DB-API 2.0 wrapper pgdb.py (andre@via.ecp.fr) + - Correct keyword clash (temp) in tutorial + - Clean up layout of tutorial + - Return NULL values as None (rlawrence@lastfoot.com) + - Change None to NULL in insert and update + - Change hash-bang lines to use /usr/bin/env + - Clearing date should be blank (NULL) not TODAY + - Quote backslashes in strings in _quote (brian@CSUA.Berkeley.EDU) + - Expanded and clarified build instructions (tbryan@starship.python.net) + - Make code thread safe (Jerome.Alet@unice.fr) + - Add README.distutils (mwa@gate.net & jeremy@cnri.reston.va.us) + - Many fixes and increased DB-API compliance by chifungfan@yahoo.com, + tony@printra.net, jeremy@alum.mit.edu and others to get the final + version ready to release. + Version 2.4 - Insert returns None if the user doesn't have select permissions on the table. It can (and does) happen that one has insert but not select permissions on a table. - Added ntuples() method to query object (brit@druid.net) - Corrected a bug related to getresult() and the money type - - Corrected a but related to negative money amounts + - Corrected a bug related to negative money amounts - Allow update based on primary key if munged oid not available and table has a primary key - Add many __doc__ strings. (andre@via.ecp.fr) + - Get method works with views if key specified Version 2.3 - connect.host returns "localhost" when connected to Unix socket diff --git a/src/interfaces/python/PyGreSQL.spec b/src/interfaces/python/PyGreSQL.spec new file mode 100644 index 0000000000..315dee3998 --- /dev/null +++ b/src/interfaces/python/PyGreSQL.spec @@ -0,0 +1,57 @@ +%define version 3.0 +%define release pre20000310 +%define name PyGreSQL +%define pythonversion 1.5 +Source: %{name}-%{version}-%{release}.tgz +Summary: A Python interface for PostgreSQL database. +Name: %{name} +Version: %{version} +Release: %{release} +#Patch: +Group: Applications/Databases +BuildRoot: /tmp/rpmbuild_%{name} +Copyright: GPL-like +Requires: python >= %{pythonversion}, postgresql +Packager: Hartmut Goebel +Vendor: D'Arcy J.M. Cain +URL: http://www.druid.net/pygresql/ + +%changelog +#* Tue Oct 06 1998 Fabio Coatti +#- fixed installation directory files list + +%description +PyGreSQL is a python module that interfaces to a PostgreSQL database. It +embeds the PostgreSQL query library to allow easy use of the powerful +PostgreSQL features from a Python script. + +Version 3.0 includes DB-API 2.0 support. + +%prep +rm -rf $RPM_BUILD_ROOT + +%setup -n %{name}-%{version}-%{release} +#%patch + +%build +mkdir -p $RPM_BUILD_ROOT/usr/lib/python%{pythonversion}/lib-dynload +cc -fpic -shared -o $RPM_BUILD_ROOT/usr/lib/python%{pythonversion}/lib-dynload/_pg.so -I/usr/include/pgsql/ -I/usr/include/python1.5 pgmodule.c -lpq +## import fails, since _pg is not yet installed +python -c 'import pg' || true +python -c 'import pgdb' || true + +%install +cp *.py *.pyc $RPM_BUILD_ROOT/usr/lib/python%{pythonversion}/ + +cd $RPM_BUILD_ROOT +find . -type f | sed 's,^\.,\%attr(-\,root\,root) ,' > $RPM_BUILD_DIR/file.list.%{name} +find . -type l | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.%{name} + +%files -f ../file.list.%{name} +%doc %attr(-,root,root) Announce ChangeLog README tutorial + + +%clean +rm -rf $RPM_BUILD_ROOT +cd $RPM_BUILD_DIR +rm -rf %{name}-%{version}-%{release} file.list.%{name} diff --git a/src/interfaces/python/README b/src/interfaces/python/README index 7ec961859e..c53a22b5cd 100644 --- a/src/interfaces/python/README +++ b/src/interfaces/python/README @@ -1,11 +1,11 @@ -PyGreSQL - v2.4: PostgreSQL module for Python +PyGreSQL - v2.5: PostgreSQL module for Python ============================================== 0. Copyright notice =================== - PyGreSQL, version 2.4 + PyGreSQL, version 2.5 A Python interface for PostgreSQL database. Written by D'Arcy J.M. Cain, darcy@druid.net
Based heavily on code written by Pascal Andre, andre@chimay.via.ecp.fr. @@ -57,7 +57,8 @@ PyGreSQL 2.0 was developed and tested on a NetBSD 1.3_BETA system. It is based on the PyGres95 code written by Pascal Andre, andre@chimay.via.ecp.fr. I changed the version to 2.0 and updated the code for Python 1.5 and PostgreSQL 6.2.1. While I was at it I upgraded the code to use full ANSI -style prototypes and changed the order of arguments to connect. +style prototypes and changed the order of arguments to connect. The latest +version of PyGreSQL works with PostgreSQL 6.5 and Python 1.5.2. 1.2. Distribution files @@ -78,25 +79,90 @@ style prototypes and changed the order of arguments to connect. 1.3. Installation ----------------- -* You first have to get and build Python and PostgreSQL. +* If you are on NetBSD, look in the packages directory under databases. If + it isn't there yet, it should be there shortly. You can also pick up the + package files from ftp://ftp.druid.net/pub/distrib/pygresql.pkg.tgz. + There is also a package in the FreeBSD ports collection but as I write + this it is at version 2.1. I will try to get that updated as well. + +* For Linux installation look at README.linux. If you're on an x86 system + that uses RPMs, then you can pick up an RPM at + ftp://ftp.druid.net/pub/distrib/pygresql.i386.rpm + +* Also, check out setup.py for an alternate method of installing the package. + +You have two options. You can compile PyGreSQL as a stand-alone module +or you can build it into the Python interpreter. + +GENERAL + +* You must first have installed Python and PostgreSQL on your system. + The header files and developer's libraries for both Python and PostgreSQL + must be installed on your system before you can build PyGreSQL. If you + built both Python and PostgreSQL from source, you should be fine. If your + system uses some package mechanism (such as RPMs or NetBSD packages), then + you probably need to install packages such as Python-devel in addition to + the Python package. * PyGreSQL is implemented as two parts, a C module labeled _pg and a Python wrapper called pg.py. This changed between 2.1 and 2.2. This should not affect any existing programs but the installation is slightly different. -* Find the directory where your 'Setup' file lives (usually ??/Modules) and - copy or symlink the 'pgmodule.c' file there. +* Download and unpack the PyGreSQL tarball if you haven't already done so. -* Add the following line to your Setup file - _pg pgmodule.c -I[pgInc] -L[pgLib] -lpq # -lcrypt # needed on some systems +STAND-ALONE + +* In the directory containing pgmodule.c, run the following command + cc -fpic -shared -o _pg.so -I[pyInc] -I[pgInc] -L[pgLib] -lpq # -lcrypt # needed on some systems where: - [pgInc] = path of the PostgreSQL include - [pgLib] = path of the PostgreSQL libraries + [pyInc] = path of the Python include (usually Python.h) + [pgInc] = path of the PostgreSQL include (usually postgres.h) + [pgLib] = path of the PostgreSQL libraries (usually libpq.so or libpq.a) Some options may be added to this line: -DNO_DEF_VAR - no default variables support -DNO_DIRECT - no direct access methods -DNO_LARGE - no large object support + -DNO_SNPRINTF - if running a system with no snprintf call + -DNO_PQSOCKET - if running an older PostgreSQL + + Define NO_PQSOCKET if you are using a version of PostgreSQL before 6.4 + that does not have the PQsocket function. The other options will be + described in the next sections. + +* Test the new module. Something like the following should work. + + $ python + + >>> import _pg + >>> db = _pg.connect('thilo','localhost') + >>> db.query("INSERT INTO test VALUES ('ping','pong')") + 18304 + >>> db.query("SELECT * FROM test") + eins|zwei + ----+---- + ping|pong + (1 row) + +* Finally, move the _pg.so, pg.py, and pgdb.py to a directory in your + PYTHONPATH. A good place would be /usr/lib/python1.5/site-python if + your Python modules are in /usr/lib/python1.5. + +BUILT-IN TO PYTHON INTERPRETER + +* Find the directory where your 'Setup' file lives (usually ??/Modules) in + the Python source hierarchy and copy or symlink the 'pgmodule.c' file there. + +* Add the following line to your Setup file + _pg pgmodule.c -I[pgInc] -L[pgLib] -lpq # -lcrypt # needed on some systems + where: + [pgInc] = path of PostgreSQL include (often /usr/local/include/python1.5) + [pgLib] = path of the PostgreSQL libraries (often /usr/local/lib/python1.5) + Some options may be added to this line: + -DNO_DEF_VAR - no default variables support + -DNO_DIRECT - no direct access methods + -DNO_LARGE - no large object support + -DNO_SNPRINTF - if running a system with no snprintf call -DNO_PQSOCKET - if running an older PostgreSQL Define NO_PQSOCKET if you are using a version of PostgreSQL before 6.4 @@ -108,21 +174,14 @@ style prototypes and changed the order of arguments to connect. your shared modules with "make sharedinstall but this no longer seems to be true." -* Copy pg.py to the lib directory where the rest of your modules are. For +* Copy pg.py to the lib directory where the rest of your modules are. For example, that's /usr/local/lib/Python on my system. -* Do 'make -f Makefile.pre.in boot' and do 'make && make install' +* Rebuild Python from the root directory of the Python source hierarchy by + running 'make -f Makefile.pre.in boot' and 'make && make install' * For more details read the documentation at the top of Makefile.pre.in -* If you are on NetBSD, look in the packages directory under databases. If - it isn't there yet, it should be there shortly. You can also pick up the - package files from ftp://ftp.druid.net/pub/distrib/pygresql.pkg.tgz. - There is also a package in the FreeBSD ports collection but as I write - this it is at version 2.1. I will try to get that updated as well. - -* For Linux installation look at README.linux - 1.4. Where to get ... ? ----------------------- @@ -133,9 +192,10 @@ The home sites of the different packages are: - PosgreSQL: http://www.PostgreSQL.org/ - PyGreSQL: http://www.druid.net/pygresql/ -A Linux RPM can be picked up from ftp://www.eevolute.com/pub/python/. -A NetBSD package thould be in the distribution soon and is available -at ftp://ftp.druid.net/pub/distrib/pygresql.pkg.tgz. +A Linux RPM can be picked up from +ftp://ftp.druid.net/pub/distrib/pygresql.i386.rpm. A NetBSD package thould +be in the distribution soon and is available at +ftp://ftp.druid.net/pub/distrib/pygresql.pkg.tgz. 1.5. Information and support ---------------------------- @@ -394,7 +454,7 @@ methods are specified by the tag [LO]. inserted row. If it is otherwise a query that does not return a result (ie. is not a some kind of SELECT statement), it returns None. Otherwise, it returns a pgqueryobject that can be accessed via the - getresult method or printed. + getresult or dictresult method or simply printed. pgqueryobject methods --------------------- @@ -411,8 +471,8 @@ methods are specified by the tag [LO]. pg.error - invalid previous result Description: This method returns the list of the values returned by the query. - More information about this result may be get using listfields, - fieldname and fiednum methods. + More information about this result may be accessed using listfields, + fieldname and fieldnum methods. 2.2.1.2. dictresult - like getresult but returns list of dictionaries --------------------------------------------------------------------- @@ -839,8 +899,8 @@ has a class called DB. The above functions are also included in the name space so it isn't necessary to import both modules. The preferred way to use this module is as follows. -from pg import DB -db = DB(...) # See description of the initialization method below. +import pg +db = pg.DB(...) # See description of the initialization method below. The following describes the methods and variables of this class. @@ -973,11 +1033,30 @@ The following describes the methods and variables of this class. as munged as described above. -4. Future directions -==================== +4. DB-API reference +=================== + + This section needs to be written. + + +5. Todo +======= The large object and direct access functions need much more attention. -I want to add a DB-SIG API wrapper around the underlying module. This -will be in 3.0. +An update query should return the number of rows affected. + +The C module needs to be cleaned up and redundant code merged. + +The DB-API module needs to be documented. + + +6. Future directions +==================== + +Users should be able to register their own types with _pg. + +I would like a new method that returns a dictionary of dictionaries from +a SELECT. + diff --git a/src/interfaces/python/README.linux b/src/interfaces/python/README.linux index 8fd75f252f..3b98077089 100644 --- a/src/interfaces/python/README.linux +++ b/src/interfaces/python/README.linux @@ -1,5 +1,10 @@ Thanks to thilo@eevolute.com for this README and the RPM +Note: The precompiled RPM package is not available at www.eevolute.com. + You may use the spec file provided with PyGreSQL to build your + own package. + Hartmut Goebel + INSTALLING PyGreSQL on Redhat Linux 5.1 or 5.2 ============================================== diff --git a/src/interfaces/python/mkdefines b/src/interfaces/python/mkdefines index fd5eb6f4cd..f023b3c748 100755 --- a/src/interfaces/python/mkdefines +++ b/src/interfaces/python/mkdefines @@ -1,4 +1,4 @@ -#! /usr/local/bin/python +#! /usr/bin/env python import string diff --git a/src/interfaces/python/pg.py b/src/interfaces/python/pg.py index a3644dd451..d840c64a7b 100644 --- a/src/interfaces/python/pg.py +++ b/src/interfaces/python/pg.py @@ -10,13 +10,16 @@ import string, re, sys # utility function # We expect int, seq, decimal, text or date (more later) def _quote(d, t): + if d == None: + return "NULL" + if t in ['int', 'decimal', 'seq']: if d == "": return 0 - return "%s" % d + return "%d" % int(d) if t == 'money': if d == "": return '0.00' - return "'%.2f'" % d + return "'%.2f'" % float(d) if t == 'bool': if string.upper(d) in ['T', 'TRUE', 'Y', 'YES', 1, '1', 'ON']: @@ -25,7 +28,8 @@ def _quote(d, t): return "'f'" if d == "": return "null" - return "'%s'" % string.strip(re.sub("'", "''", "%s" % d)) + return "'%s'" % string.strip(re.sub("'", "''", \ + re.sub("\\\\", "\\\\\\\\", "%s" %d))) class DB: """This class wraps the pg connection type""" @@ -42,8 +46,8 @@ class DB: if not hasattr(self,e) and hasattr(self.db,e): exec 'self.%s = self.db.%s' % ( e, e ) - self.attnames = {} - self.pkeys = {} + self.__attnames__ = {} + self.__pkeys__ = {} self.debug = None # For debugging scripts, set to output format # that takes a single string arg. For example # in a CGI set to "%s
" @@ -56,11 +60,17 @@ class DB: pg_class.oid = pg_index.indrelid AND pg_index.indkey[0] = pg_attribute.attnum AND pg_index.indisprimary = 't'""").getresult(): - self.pkeys[rel] = att + self.__pkeys__[rel] = att + + # wrap query for debugging + def query(self, qstr): + if self.debug != None: + print self.debug % qstr + return self.db.query(qstr) def pkey(self, cl): # will raise an exception if primary key doesn't exist - return self.pkeys[cl] + return self.__pkeys__[cl] def get_databases(self): l = [] @@ -79,8 +89,8 @@ class DB: def get_attnames(self, cl): # May as well cache them - if self.attnames.has_key(cl): - return self.attnames[cl] + if self.__attnames__.has_key(cl): + return self.__attnames__[cl] query = """SELECT pg_attribute.attname, pg_type.typname FROM pg_class, pg_attribute, pg_type @@ -114,13 +124,13 @@ class DB: else: l[attname] = 'text' - self.attnames[cl] = l - return self.attnames[cl] + self.__attnames__[cl] = l + return self.__attnames__[cl] # return a tuple from a database - def get(self, cl, arg, keyname = None): + def get(self, cl, arg, keyname = None, view = 0): if keyname == None: # use the primary key by default - keyname = self.pkeys[cl] + keyname = self.__pkeys__[cl] fnames = self.get_attnames(cl) @@ -136,6 +146,9 @@ class DB: # We want the oid for later updates if that isn't the key if keyname == 'oid': q = "SELECT * FROM %s WHERE oid = %s" % (cl, k) + elif view: + q = "SELECT * FROM %s WHERE %s = %s" % \ + (cl, keyname, _quote(k, fnames[keyname])) else: q = "SELECT oid AS oid_%s, %s FROM %s WHERE %s = %s" % \ (cl, string.join(fnames.keys(), ','),\ @@ -155,6 +168,7 @@ class DB: return arg # Inserts a new tuple into a table + # We currently don't support insert into views although PostgreSQL does def insert(self, cl, a): fnames = self.get_attnames(cl) l = [] @@ -183,7 +197,7 @@ class DB: # otherwise use the primary key. Fail if neither. def update(self, cl, a): foid = 'oid_%s' % cl - pk = self.pkeys[cl] + pk = self.__pkeys__[cl] if a.has_key(foid): where = "oid = %s" % a[foid] elif a.has_key(pk): @@ -228,8 +242,6 @@ class DB: for ff in fnames.keys(): if fnames[ff] in ['int', 'decimal', 'seq', 'money']: a[ff] = 0 - elif fnames[ff] == 'date': - a[ff] = 'TODAY' else: a[ff] = "" diff --git a/src/interfaces/python/pgdb.py b/src/interfaces/python/pgdb.py new file mode 100644 index 0000000000..f5859713f0 --- /dev/null +++ b/src/interfaces/python/pgdb.py @@ -0,0 +1,401 @@ +""" pgdb - DB-SIG compliant module for PygreSQL. + + (c) 1999, Pascal Andre . + See package documentation for further information on copyright. + + Even though this file is distributed with a release version of + PyGreSQL, this is beta software. Inline documentation is sparse. + See DB-SIG 2.0 specification for usage information. + + basic usage: + + pgdb.connect(connect_string) -> connection + connect_string = 'host:database:user:password:opt:tty' + All parts are optional. You may also pass host through + password as keyword arguments. To pass a port, pass it in + the host keyword parameter: + pgdb.connect(host='localhost:5432') + + connection.cursor() -> cursor + + connection.commit() + + connection.close() + + connection.rollback() + + cursor.execute(query[, params]) + execute a query, binding params (a dictionary) if it is + passed. The binding syntax is the same as the % operator + for dictionaries, and no quoting is done. + + cursor.executemany(query, list of params) + execute a query many times, binding each param dictionary + from the list. + + cursor.fetchone() -> [value, value, ...] + + cursor.fetchall() -> [[value, value, ...], ...] + + cursor.fetchmany([size]) -> [[value, value, ...], ...] + returns size or cursor.arraysize number of rows from result + set. Default cursor.arraysize is 1. + + cursor.description -> [(column_name, type_name, display_size, + internal_size, precision, scale, null_ok), ...] + + Note that precision, scale and null_ok are not implemented. + + cursor.rowcount + number of rows available in the result set. Available after + a call to execute. + + cursor.close() + +""" + +import _pg +import string +import exceptions +import types +import DateTime +import time + +### module constants + +# compliant with DB SIG 2.0 +apilevel = '2.0' + +# module may be shared, but not connections +threadsafety = 1 + +# this module use extended python format codes +paramstyle = 'pyformat' + +### exception hierarchy + +class Warning(StandardError): + pass + +class Error(StandardError): + pass + +class InterfaceError(Error): + pass + +class DatabaseError(Error): + pass + +class DataError(DatabaseError): + pass + +class OperationalError(DatabaseError): + pass + +class IntegrityError(DatabaseError): + pass + +class InternalError(DatabaseError): + pass + +class ProgrammingError(DatabaseError): + pass + +class NotSupportedError(DatabaseError): + pass + +### internal type handling class +class pgdbTypeCache: + + def __init__(self, cnx): + self.__source = cnx.source() + self.__type_cache = {} + + def typecast(self, typ, value): + # for NULL values, no typecast is necessary + if value == None: + return value + + if typ == STRING: + pass + elif typ == BINARY: + pass + elif typ == INTEGER: + value = int(value) + elif typ == LONG: + value = long(value) + elif typ == FLOAT: + value = float(value) + elif typ == MONEY: + value = string.replace(value, "$", "") + value = string.replace(value, ",", "") + value = float(value) + elif typ == DATETIME: + # format may differ ... we'll give string + pass + elif typ == ROWID: + value = long(value) + return value + + def getdescr(self, oid): + try: + return self.__type_cache[oid] + except: + self.__source.execute( + "SELECT typname, typprtlen, typlen " + "FROM pg_type WHERE oid = %s" % oid + ) + res = self.__source.fetch(1)[0] + # column name is omitted from the return value. It will + # have to be prepended by the caller. + res = ( + res[0], + string.atoi(res[1]), string.atoi(res[2]), + None, None, None + ) + self.__type_cache[oid] = res + return res + +### cursor object + +class pgdbCursor: + + def __init__(self, src, cache): + self.__cache = cache + self.__source = src + self.description = None + self.rowcount = -1 + self.arraysize = 5 + + def close(self): + self.__source.close() + self.description = None + self.rowcount = -1 + + def execute(self, operation, params = None): + if type(params) == types.TupleType or type(params) == types.ListType: + self.executemany(operation, params) + else: + self.executemany(operation, (params,)) + + def executemany(self, operation, param_seq): + self.description = None + self.rowcount = -1 + + # first try to execute all queries + totrows = 0 + sql = "INIT" + try: + for params in param_seq: + if params != None: + sql = operation % params + else: + sql = operation + rows = self.__source.execute(sql) + if rows != None: # true is __source is NOT a DQL + totrows = totrows + rows + except _pg.error, msg: + raise DatabaseError, "error '%s' in '%s'" % ( msg, sql ) + except: + raise OperationalError, "internal error in '%s'" % sql + + # then initialize result raw count and description + if self.__source.resulttype == _pg.RESULT_DQL: + self.rowcount = self.__source.ntuples + d = [] + for typ in self.__source.listinfo(): + # listinfo is a sequence of + # (index, column_name, type_oid) + # getdescr returns all items needed for a + # description tuple except the column_name. + desc = typ[1:2]+self.__cache.getdescr(typ[2]) + d.append(desc) + self.description = d + else: + self.rowcount = totrows + self.description = None + + def fetchone(self): + res = self.fetchmany(1, 0) + try: + return res[0] + except: + return None + + def fetchall(self): + return self.fetchmany(-1, 0) + + def fetchmany(self, size = None, keep = 1): + if size == None: + size = self.arraysize + if keep == 1: + self.arraysize = size + res = self.__source.fetch(size) + result = [] + for r in res: + row = [] + for i in range(len(r)): + row.append(self.__cache.typecast( + self.description[i][1], + r[i] + ) + ) + result.append(row) + return result + + def setinputsizes(self, sizes): + pass + + def setoutputsize(self, size, col = 0): + pass + +### connection object + +class pgdbCnx: + + def __init__(self, cnx): + self.__cnx = cnx + self.__cache = pgdbTypeCache(cnx) + try: + src = self.__cnx.source() + src.execute("BEGIN") + except: + raise OperationalError, "invalid connection." + + def close(self): + self.__cnx.close() + + def commit(self): + try: + src = self.__cnx.source() + src.execute("COMMIT") + src.execute("BEGIN") + except: + raise OperationalError, "can't commit." + + def rollback(self): + try: + src = self.__cnx.source() + src.execute("ROLLBACK") + src.execute("BEGIN") + except: + raise OperationalError, "can't rollback." + + def cursor(self): + try: + src = self.__cnx.source() + return pgdbCursor(src, self.__cache) + except: + raise pgOperationalError, "invalid connection." + +### module interface + +# connects to a database +def connect(dsn = None, user = None, password = None, host = None, database = None): + # first get params from DSN + dbport = -1 + dbhost = "" + dbbase = "" + dbuser = "" + dbpasswd = "" + dbopt = "" + dbtty = "" + try: + params = string.split(dsn, ":") + dbhost = params[0] + dbbase = params[1] + dbuser = params[2] + dbpasswd = params[3] + dbopt = params[4] + dbtty = params[5] + except: + pass + + # override if necessary + if user != None: + dbuser = user + if password != None: + dbpasswd = password + if database != None: + dbbase = database + if host != None: + try: + params = string.split(host, ":") + dbhost = params[0] + dbport = params[1] + except: + pass + + # empty host is localhost + if dbhost == "": + dbhost = None + if dbuser == "": + dbuser = None + + # open the connection + cnx = _pg.connect(host = dbhost, dbname = dbbase, port = dbport, + opt = dbopt, tty = dbtty, + user = dbuser, passwd = dbpasswd) + return pgdbCnx(cnx) + +### types handling + +# PostgreSQL is object-oriented: types are dynamic. We must thus use type names +# as internal type codes. + +class pgdbType: + + def __init__(self, *values): + self.values= values + + def __cmp__(self, other): + if other in self.values: + return 0 + if other < self.values: + return 1 + else: + return -1 + +STRING = pgdbType( + 'char', 'name', 'text', 'varchar' +) + +# BLOB support is pg specific +BINARY = pgdbType() +INTEGER = pgdbType('int2', 'int4', 'serial') +LONG = pgdbType('int8') +FLOAT = pgdbType('float4', 'float8', 'numeric') +BOOL = pgdbType('bool') +MONEY = pgdbType('money') + +# this may be problematic as type are quite different ... I hope it won't hurt +DATETIME = pgdbType( + 'abstime', 'reltime', 'tinterval', 'date', 'time', 'timespan', 'timestamp' +) + +# OIDs are used for everything (types, tables, BLOBs, rows, ...). This may cause +# confusion, but we are unable to find out what exactly is behind the OID (at +# least not easily enough). Should this be undefined as BLOBs ? +ROWID = pgdbType( + 'oid', 'oid8' +) + +# mandatory type helpers +def Date(year, month, day): + return DateTime.DateTime(year, month, day) + +def Time(hour, minute, second): + return DateTime.TimeDelta(hour, minute, second) + +def Timestamp(year, month, day, hour, minute, second): + return DateTime.DateTime(year, month, day, hour, minute, second) + +def DateFromTicks(ticks): + return apply(Date, time.localtime(ticks)[:3]) + +def TimeFromTicks(ticks): + return apply(Time, time.localtime(ticks)[3:6]) + +def TimestampFromTicks(ticks): + return apply(Timestamp, time.localtime(ticks)[:6]) + diff --git a/src/interfaces/python/pgmodule.c b/src/interfaces/python/pgmodule.c index 967ac53600..09e94b8361 100644 --- a/src/interfaces/python/pgmodule.c +++ b/src/interfaces/python/pgmodule.c @@ -26,9 +26,9 @@ * */ -#include "Python.h" -#include "libpq-fe.h" -#include "libpq/libpq-fs.h" +#include +#include +#include #include #include #include @@ -36,22 +36,22 @@ /* really bad stuff here - I'm so naughty */ /* If you need to you can run mkdefines to get */ /* current defines but it should not have changed */ -#define INT2OID 21 -#define INT4OID 23 -#define OIDOID 26 -#define FLOAT4OID 700 -#define FLOAT8OID 701 -#define CASHOID 790 +#define INT2OID 21 +#define INT4OID 23 +#define OIDOID 26 +#define FLOAT4OID 700 +#define FLOAT8OID 701 +#define CASHOID 790 -static PyObject *PGError; -static const char *PyPgVersion = "2.4"; +static PyObject *PGError; +static const char *PyPgVersion = "3.0"; /* taken from fileobject.c */ #define BUF(v) PyString_AS_STRING((PyStringObject *)(v)) /* default values */ -#define MODULE_NAME "pgsql" -#define ARRAYSIZE 1 +#define MODULE_NAME "pgsql" +#define ARRAYSIZE 1 /* flags for object validity checks */ #define CHECK_OPEN 1 @@ -60,19 +60,35 @@ static const char *PyPgVersion = "2.4"; #define CHECK_RESULT 8 #define CHECK_DQL 16 -#define MAX_BUFFER_SIZE 8192 /* maximum transaction size */ +/* query result types */ +#define RESULT_EMPTY 1 +#define RESULT_DML 2 +#define RESULT_DDL 3 +#define RESULT_DQL 4 + +/* flags for move methods */ +#define QUERY_MOVEFIRST 1 +#define QUERY_MOVELAST 2 +#define QUERY_MOVENEXT 3 +#define QUERY_MOVEPREV 4 + +/* moves names for errors */ +const char *__movename[5] = + { "", "movefirst", "movelast", "movenext", "moveprev" }; + +#define MAX_BUFFER_SIZE 8192 /* maximum transaction size */ #ifndef NO_DIRECT -#define DIRECT_ACCESS 1 /* enables direct access functions */ -#endif /* NO_DIRECT */ +#define DIRECT_ACCESS 1 /* enables direct access functions */ +#endif /* NO_DIRECT */ #ifndef NO_LARGE -#define LARGE_OBJECTS 1 /* enables large objects support */ -#endif /* NO_LARGE */ +#define LARGE_OBJECTS 1 /* enables large objects support */ +#endif /* NO_LARGE */ #ifndef NO_DEF_VAR -#define DEFAULT_VARS 1 /* enables default variables use */ -#endif /* NO_DEF_VAR */ +#define DEFAULT_VARS 1 /* enables default variables use */ +#endif /* NO_DEF_VAR */ /* --------------------------------------------------------------------- */ @@ -80,15 +96,15 @@ static const char *PyPgVersion = "2.4"; #ifdef DEFAULT_VARS -static PyObject *pg_default_host; /* default database host */ -static PyObject *pg_default_base; /* default database name */ -static PyObject *pg_default_opt;/* default connection options */ -static PyObject *pg_default_tty;/* default debug tty */ -static PyObject *pg_default_port; /* default connection port */ -static PyObject *pg_default_user; /* default username */ -static PyObject *pg_default_passwd; /* default password */ +static PyObject *pg_default_host; /* default database host */ +static PyObject *pg_default_base; /* default database name */ +static PyObject *pg_default_opt; /* default connection options */ +static PyObject *pg_default_tty; /* default debug tty */ +static PyObject *pg_default_port; /* default connection port */ +static PyObject *pg_default_user; /* default username */ +static PyObject *pg_default_passwd; /* default password */ -#endif /* DEFAULT_VARS */ +#endif /* DEFAULT_VARS */ /* --------------------------------------------------------------------- */ /* OBJECTS DECLARATION */ @@ -99,40 +115,78 @@ typedef struct { PyObject_HEAD int valid; /* validity flag */ - PGconn *cnx; /* PostGres connection handle */ -} pgobject; + PGconn *cnx; /* PostGres connection handle */ + PGresult *last_result; /* last result content */ +} pgobject; staticforward PyTypeObject PgType; #define is_pgobject(v) ((v)->ob_type == &PgType) +static PyObject * +pgobject_New(void) +{ + pgobject *pgobj; + + if ((pgobj = PyObject_NEW(pgobject, &PgType)) == NULL) + return NULL; + + pgobj->valid = 1; + pgobj->last_result = NULL; + pgobj->cnx = NULL; + return (PyObject*)pgobj; +} + /* pg query object */ typedef struct { PyObject_HEAD - PGresult *last_result; /* last result content */ -} pgqueryobject; + PGresult *last_result; /* last result content */ + int result_type; /* type of previous result */ + long current_pos; /* current position in last result */ + long num_rows; /* number of (affected) rows */ +} pgqueryobject; staticforward PyTypeObject PgQueryType; #define is_pgqueryobject(v) ((v)->ob_type == &PgQueryType) +/* pg source object */ + +typedef struct +{ + PyObject_HEAD + int valid; /* validity flag */ + pgobject *pgcnx; /* parent connection object */ + PGresult *last_result; /* last result content */ + int result_type; /* result type (DDL/DML/DQL) */ + long arraysize; /* array size for fetch method */ + int current_row; /* current selected row */ + int max_row; /* number of rows in the result */ + int num_fields; /* number of fields in each row */ +} pgsourceobject; + +staticforward PyTypeObject PgSourceType; + +#define is_pgsourceobject(v) ((v)->ob_type == &PgSourceType) + + #ifdef LARGE_OBJECTS /* pg large object */ typedef struct { PyObject_HEAD - pgobject * pgcnx; /* parent connection object */ - Oid lo_oid; /* large object oid */ - int lo_fd; /* large object fd */ -} pglargeobject; + pgobject *pgcnx; /* parent connection object */ + Oid lo_oid; /* large object oid */ + int lo_fd; /* large object fd */ +} pglargeobject; staticforward PyTypeObject PglargeType; #define is_pglargeobject(v) ((v)->ob_type == &PglargeType) -#endif /* LARGE_OBJECTS */ +#endif /* LARGE_OBJECTS */ /* --------------------------------------------------------------------- */ /* INTERNAL FUNCTIONS */ @@ -141,8 +195,7 @@ staticforward PyTypeObject PglargeType; static int check_cnx_obj(pgobject * self) { - if (!self->valid) - { + if (!self->valid) { PyErr_SetString(PGError, "connection has been closed"); return 0; } @@ -184,10 +237,725 @@ check_lo_obj(pglargeobject * self, int level) return 1; } -#endif /* LARGE_OBJECTS */ +#endif /* LARGE_OBJECTS */ + +/* checks source object validity */ +static int +check_source_obj(pgsourceobject * self, int level) +{ + if (!self->valid) + { + PyErr_SetString(PGError, "object has been closed"); + return 0; + } + + if ((level & CHECK_RESULT) && self->last_result == NULL) + { + PyErr_SetString(PGError, "no result."); + return 0; + } + + if ((level & CHECK_DQL) && self->result_type != RESULT_DQL) + { + PyErr_SetString(PGError, "last query did not return tuples."); + return 0; + } + + if ((level & CHECK_CNX) && !check_cnx_obj(self->pgcnx)) + return 0; + + return 1; +} + +/* shared functions for converting PG types to Python types */ +int * +get_type_array(PGresult *result, int nfields) +{ + int *typ; + int j; + + if ((typ = malloc(sizeof(int) * nfields)) == NULL) + { + PyErr_SetString(PyExc_SyntaxError, "memory error in getresult()."); + return NULL; + } + + for (j = 0; j < nfields; j++) + { + switch (PQftype(result, j)) + { + case INT2OID: + case INT4OID: + case OIDOID: + typ[j] = 1; + break; + + case FLOAT4OID: + case FLOAT8OID: + typ[j] = 2; + break; + + case CASHOID: + typ[j] = 3; + break; + + default: + typ[j] = 4; + break; + } + } + + return typ; +} + + +/* prototypes for constructors */ +static pgsourceobject * pgsource_new(pgobject * pgcnx); /* --------------------------------------------------------------------- */ -/* PG CONNECTION OBJECT IMPLEMENTATION */ +/* PG SOURCE OBJECT IMPLEMENTATION */ + +/* constructor (internal use only) */ +static pgsourceobject * +pgsource_new(pgobject * pgcnx) +{ + pgsourceobject * npgobj; + + /* allocates new query object */ + if ((npgobj = PyObject_NEW(pgsourceobject, &PgSourceType)) == NULL) + return NULL; + + /* initializes internal parameters */ + Py_XINCREF(pgcnx); + npgobj->pgcnx = pgcnx; + npgobj->last_result = NULL; + npgobj->valid = 1; + npgobj->arraysize = ARRAYSIZE; + + return npgobj; +} + +/* destructor */ +static void +pgsource_dealloc(pgsourceobject * self) +{ + if (self->last_result) + PQclear(self->last_result); + + Py_XDECREF(self->pgcnx); + PyMem_DEL(self); +} + +/* closes object */ +static char pgsource_close__doc__[] = +"close() -- close query object without deleting it. " +"All instances of the query object can no longer be used after this call."; + +static PyObject * +pgsource_close(pgsourceobject * self, PyObject * args) +{ + /* checks args */ + if (!PyArg_ParseTuple(args, "")) + { + PyErr_SetString(PyExc_TypeError, "method close() takes no parameter."); + return NULL; + } + + /* frees result if necessary and invalidates object */ + if (self->last_result) + { + PQclear(self->last_result); + self->result_type = RESULT_EMPTY; + self->last_result = NULL; + } + + self->valid = 0; + + /* return None */ + Py_INCREF(Py_None); + return Py_None; +} + +/* database query */ +static char pgsource_execute__doc__[] = +"execute(sql) -- execute a SQL statement (string).\n " +"On success, this call returns the number of affected rows, " +"or None for DQL (SELECT, ...) statements.\n" +"The fetch (fetch(), fetchone() and fetchall()) methods can be used " +"to get result rows."; + +static PyObject * +pgsource_execute(pgsourceobject * self, PyObject * args) +{ + char *query; + const char *temp; + long num_rows; + + /* checks validity */ + if (!check_source_obj(self, CHECK_CNX)) + return NULL; + + /* get query args */ + if (!PyArg_ParseTuple(args, "s", &query)) + { + PyErr_SetString(PyExc_TypeError, "execute(sql), with sql (string)."); + return NULL; + } + + /* frees previous result */ + if (self->last_result) + { + PQclear(self->last_result); + self->last_result = NULL; + } + self->max_row = 0; + self->current_row = 0; + self->num_fields = 0; + + /* gets result */ + Py_BEGIN_ALLOW_THREADS + self->last_result = PQexec(self->pgcnx->cnx, query); + Py_END_ALLOW_THREADS + + /* checks result validity */ + if (!self->last_result) + { + PyErr_SetString(PyExc_ValueError, PQerrorMessage(self->pgcnx->cnx)); + return NULL; + } + + /* checks result status */ + switch (PQresultStatus(self->last_result)) + { + + /* query succeeded */ + case PGRES_TUPLES_OK: /* DQL: returns None (DB-SIG compliant) */ + self->result_type = RESULT_DQL; + self->max_row = PQntuples(self->last_result); + self->num_fields = PQnfields(self->last_result); + Py_INCREF(Py_None); + return Py_None; + case PGRES_COMMAND_OK: /* other requests */ + case PGRES_COPY_OUT: + case PGRES_COPY_IN: + self->result_type = RESULT_DDL; + temp = PQcmdTuples(self->last_result); + num_rows = 1; + if (temp[0] != 0) { + self->result_type = RESULT_DML; + num_rows = atol(temp); + } + return PyInt_FromLong(num_rows); + + /* query failed */ + case PGRES_EMPTY_QUERY: + PyErr_SetString(PyExc_ValueError, "empty query."); + break; + case PGRES_BAD_RESPONSE: + case PGRES_FATAL_ERROR: + case PGRES_NONFATAL_ERROR: + PyErr_SetString(PGError, PQerrorMessage(self->pgcnx->cnx)); + break; + default: + PyErr_SetString(PGError, "internal error: " + "unknown result status."); + break; + } + + /* frees result and returns error */ + PQclear(self->last_result); + self->last_result = NULL; + self->result_type = RESULT_EMPTY; + return NULL; +} + +/* gets oid status for last query (valid for INSERTs, 0 for other) */ +static char pgsource_oidstatus__doc__[] = +"oidstatus() -- return oid of last inserted row (if available)."; + +static PyObject * +pgsource_oidstatus(pgsourceobject * self, PyObject * args) +{ + long oid; + const char *status; + + /* checks validity */ + if (!check_source_obj(self, CHECK_RESULT)) + return NULL; + + /* checks args */ + if ((args != NULL) && (!PyArg_ParseTuple(args, ""))) + { + PyErr_SetString(PyExc_SyntaxError, + "method oidstatus() takes no parameters."); + return NULL; + } + + /* retrieves oid status */ + oid = 0; + if ((status = PQoidStatus(self->last_result))) + oid = atol(status); + return PyInt_FromLong(oid); +} + +/* fetches rows from last result */ +static char pgsource_fetch__doc__[] = +"fetch(num) -- return the next num rows from the last result in a list. " +"If num parameter is omitted arraysize attribute value is used. " +"If size equals -1, all rows are fetched."; + +static PyObject * +pgsource_fetch(pgsourceobject * self, PyObject * args) +{ + PyObject *rowtuple, *reslist, *str; + int i, j; + long size; + + /* checks validity */ + if (!check_source_obj(self, CHECK_RESULT | CHECK_DQL)) + return NULL; + + /* checks args */ + size = self->arraysize; + if (!PyArg_ParseTuple(args, "|l", &size)) + { + PyErr_SetString(PyExc_SyntaxError, + "fetch(num), with num (integer, optional)."); + return NULL; + } + + /* seeks last line */ + /* limit size to be within the amount of data we actually have */ + if (size == -1 || (self->max_row - self->current_row) < size) + size = self->max_row - self->current_row; + + /* allocate list for result */ + if ((reslist = PyList_New(0)) == NULL) + return NULL; + + /* builds result */ + for (i = 0; i < size; ++i) + { + if ((rowtuple = PyTuple_New(self->num_fields)) == NULL) + { + Py_DECREF(reslist); + return NULL; + } + + for (j = 0; j < self->num_fields; j++) + { + if (PQgetisnull(self->last_result, i, j)) + { + Py_INCREF(Py_None); + str = Py_None; + } + else + str = PyString_FromString(PQgetvalue(self->last_result, i, j)); + + PyTuple_SET_ITEM(rowtuple, j, str); + } + + PyList_Append(reslist, rowtuple); + self->current_row++; + } + + return reslist; +} + +/* changes current row (internal wrapper for all "move" methods) */ +static PyObject * +pgsource_move(pgsourceobject * self, PyObject * args, int move) +{ + /* checks validity */ + if (!check_source_obj(self, CHECK_RESULT | CHECK_DQL)) + return NULL; + + /* checks args */ + if (!PyArg_ParseTuple(args, "")) + { + char errbuf[256]; + +#ifdef NO_SNPRINTF + sprintf(errbuf, "method %s() takes no parameter.", __movename[move]); +#else + snprintf(errbuf, sizeof(errbuf), + "method %s() takes no parameter.", __movename[move]); +#endif + + PyErr_SetString(PyExc_SyntaxError, errbuf); + return NULL; + } + + /* changes the current row */ + switch(move) { + case QUERY_MOVEFIRST: + self->current_row = 0; + break; + case QUERY_MOVELAST: + self->current_row = self->max_row - 1; + break; + case QUERY_MOVENEXT: + if (self->current_row != self->max_row) self->current_row++; + break; + case QUERY_MOVEPREV: + if (self->current_row > 0) self->current_row--; + break; + } + + Py_INCREF(Py_None); + return Py_None; +} + +/* move to first result row */ +static char pgsource_movefirst__doc__[] = +"movefirst() -- move to first result row."; + +static PyObject * +pgsource_movefirst(pgsourceobject * self, PyObject * args) +{ + return pgsource_move(self, args, QUERY_MOVEFIRST); +} + +/* move to last result row */ +static char pgsource_movelast__doc__[] = +"movelast() -- move to last valid result row."; + +static PyObject * +pgsource_movelast(pgsourceobject * self, PyObject * args) +{ + return pgsource_move(self, args, QUERY_MOVELAST); +} + +/* move to next result row */ +static char pgsource_movenext__doc__[] = +"movenext() -- move to next result row."; + +static PyObject * +pgsource_movenext(pgsourceobject * self, PyObject * args) +{ + return pgsource_move(self, args, QUERY_MOVENEXT); +} + +/* move to previous result row */ +static char pgsource_moveprev__doc__[] = +"moveprev() -- move to previous result row."; + +static PyObject * +pgsource_moveprev(pgsourceobject * self, PyObject * args) +{ + return pgsource_move(self, args, QUERY_MOVEPREV); +} + +/* finds field number from string/integer (internal use only) */ +static int +pgsource_fieldindex(pgsourceobject * self, PyObject * param, const char * usage) +{ + int num; + + /* checks validity */ + if (!check_source_obj(self, CHECK_RESULT | CHECK_DQL)) + return -1; + + /* gets field number */ + if (PyString_Check(param)) + { + num = PQfnumber(self->last_result, PyString_AsString(param)); + } + else if (PyInt_Check(param)) + { + num = PyInt_AsLong(param); + } + else + { + PyErr_SetString(PyExc_TypeError, usage); + return -1; + } + + /* checks field validity */ + if (num<0 || num>=self->num_fields) + { + PyErr_SetString(PyExc_ValueError, "Unknown field."); + return -1; + } + + return num; +} + +/* builds field information from position (internal use only) */ +static PyObject * +pgsource_buildinfo(pgsourceobject * self, int num) +{ + PyObject * result; + + /* allocates tuple */ + result = PyTuple_New(3); + if (!result) + return NULL; + + /* affects field information */ + PyTuple_SET_ITEM(result, 0, PyInt_FromLong(num)); + PyTuple_SET_ITEM(result, 1, + PyString_FromString(PQfname(self->last_result, num))); + PyTuple_SET_ITEM(result, 2, + PyInt_FromLong(PQftype(self->last_result, num))); + + return result; +} + +/* lists fields info */ +static char pgsource_listinfo__doc__[] = +"listinfo() -- return information for all fields " +"(position, name, type oid)."; + +static PyObject * +pgsource_listinfo(pgsourceobject * self, PyObject * args) +{ + int i; + PyObject * result, * info; + + /* checks validity */ + if (!check_source_obj(self, CHECK_RESULT | CHECK_DQL)) + return NULL; + + /* gets args */ + if (!PyArg_ParseTuple(args, "")) + { + PyErr_SetString(PyExc_TypeError, + "method listinfo() takes no parameter."); + return NULL; + } + + /* builds result */ + if ((result = PyTuple_New(self->num_fields)) == NULL) + return NULL; + + for (i=0; inum_fields; i++) + { + info = pgsource_buildinfo(self, i); + if (!info) + { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, i, info); + } + + /* returns result */ + return result; +}; + +/* list fields information for last result */ +static char pgsource_fieldinfo__doc__[] = +"fieldinfo(string|integer) -- return specified field information " +"(position, name, type oid)."; + +static PyObject * +pgsource_fieldinfo(pgsourceobject * self, PyObject * args) +{ + static const char short_usage[] = + "fieldinfo(desc), with desc (string|integer)."; + int num; + PyObject * param; + + /* gets args */ + if (!PyArg_ParseTuple(args, "O", ¶m)) + { + PyErr_SetString(PyExc_TypeError, short_usage); + return NULL; + } + + /* checks args and validity */ + if ((num = pgsource_fieldindex(self, param, short_usage)) == -1) + return NULL; + + /* returns result */ + return pgsource_buildinfo(self, num); +}; + +/* retrieve field value */ +static char pgsource_field__doc__[] = +"field(string|integer) -- return specified field value."; + +static PyObject * +pgsource_field(pgsourceobject * self, PyObject * args) +{ + static const char short_usage[] = + "field(desc), with desc (string|integer)."; + int num; + PyObject * param; + + /* gets args */ + if (!PyArg_ParseTuple(args, "O", ¶m)) + { + PyErr_SetString(PyExc_TypeError, short_usage); + return NULL; + } + + /* checks args and validity */ + if ((num = pgsource_fieldindex(self, param, short_usage)) == -1) + return NULL; + + return PyString_FromString(PQgetvalue(self->last_result, + self->current_row, num)); +} + +/* query object methods */ +static PyMethodDef pgsource_methods[] = { + { "close", (PyCFunction) pgsource_close, 1, + pgsource_close__doc__ }, + { "execute", (PyCFunction) pgsource_execute, 1, + pgsource_execute__doc__ }, + { "oidstatus", (PyCFunction) pgsource_oidstatus, 1, + pgsource_oidstatus__doc__ }, + { "fetch", (PyCFunction) pgsource_fetch, 1, + pgsource_fetch__doc__ }, + { "movefirst", (PyCFunction) pgsource_movefirst, 1, + pgsource_movefirst__doc__ }, + { "movelast", (PyCFunction) pgsource_movelast, 1, + pgsource_movelast__doc__ }, + { "movenext", (PyCFunction) pgsource_movenext, 1, + pgsource_movenext__doc__ }, + { "moveprev", (PyCFunction) pgsource_moveprev, 1, + pgsource_moveprev__doc__ }, + { "field", (PyCFunction) pgsource_field, 1, + pgsource_field__doc__ }, + { "fieldinfo", (PyCFunction) pgsource_fieldinfo, 1, + pgsource_fieldinfo__doc__ }, + { "listinfo", (PyCFunction) pgsource_listinfo, 1, + pgsource_listinfo__doc__ }, + { NULL, NULL } +}; + +/* gets query object attributes */ +static PyObject * +pgsource_getattr(pgsourceobject * self, char *name) +{ + /* pg connection object */ + if (!strcmp(name, "pgcnx")) + { + if (check_source_obj(self, 0)) + { + Py_INCREF(self->pgcnx); + return (PyObject *) (self->pgcnx); + } + Py_INCREF(Py_None); + return Py_None; + } + + /* arraysize */ + if (!strcmp(name, "arraysize")) + return PyInt_FromLong(self->arraysize); + + /* resulttype */ + if (!strcmp(name, "resulttype")) + return PyInt_FromLong(self->result_type); + + /* ntuples */ + if (!strcmp(name, "ntuples")) + return PyInt_FromLong(self->max_row); + + /* nfields */ + if (!strcmp(name, "nfields")) + return PyInt_FromLong(self->num_fields); + + /* attributes list */ + if (!strcmp(name, "__members__")) { + PyObject *list = PyList_New(5); + + PyList_SET_ITEM(list, 0, PyString_FromString("pgcnx")); + PyList_SET_ITEM(list, 1, PyString_FromString("arraysize")); + PyList_SET_ITEM(list, 2, PyString_FromString("resulttype")); + PyList_SET_ITEM(list, 3, PyString_FromString("ntuples")); + PyList_SET_ITEM(list, 4, PyString_FromString("nfields")); + + return list; + } + + /* module name */ + if (!strcmp(name, "__module__")) + return PyString_FromString(MODULE_NAME); + + /* class name */ + if (!strcmp(name, "__class__")) + return PyString_FromString("pgsource"); + + /* seeks name in methods (fallback) */ + return Py_FindMethod(pgsource_methods, (PyObject *) self, name); +} + +/* sets query object attributes */ +static int +pgsource_setattr(pgsourceobject * self, char * name, PyObject * v) +{ + /* arraysize */ + if (!strcmp(name, "arraysize")) + { + if (!PyInt_Check(v)) + { + PyErr_SetString(PyExc_TypeError, "arraysize must be integer."); + return -1; + } + + self->arraysize = PyInt_AsLong(v); + return 0; + } + + /* unknown attribute */ + PyErr_SetString(PyExc_TypeError, "not a writable attribute."); + return -1; +} + +/* prints query object in human readable format */ +static int +pgsource_print(pgsourceobject * self, FILE *fp, int flags) +{ + PQprintOpt op; + + switch (self->result_type) + { + case RESULT_DQL: + memset(&op, 0, sizeof(op)); + op.align = 1; + op.header = 1; + op.fieldSep = "|"; + op.pager = 1; + PQprint(fp, self->last_result, &op); + break; + case RESULT_DDL: + case RESULT_DML: + fputs(PQcmdStatus(self->last_result), fp); + break; + case RESULT_EMPTY: + default: + fputs("Empty PostgreSQL source object.", fp); + break; + } + + return 0; +} + +/* query type definition */ +staticforward PyTypeObject PgSourceType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "pgsourceobject", /* tp_name */ + sizeof(pgsourceobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor) pgsource_dealloc, /* tp_dealloc */ + (printfunc) pgsource_print, /* tp_print */ + (getattrfunc) pgsource_getattr, /* tp_getattr */ + (setattrfunc) pgsource_setattr, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ +}; + +/* --------------------------------------------------------------------- */ +/* PG "LARGE" OBJECT IMPLEMENTATION */ #ifdef LARGE_OBJECTS @@ -195,7 +963,7 @@ check_lo_obj(pglargeobject * self, int level) static pglargeobject * pglarge_new(pgobject * pgcnx, Oid oid) { - pglargeobject *npglo; + pglargeobject * npglo; if ((npglo = PyObject_NEW(pglargeobject, &PglargeType)) == NULL) return NULL; @@ -221,14 +989,13 @@ pglarge_dealloc(pglargeobject * self) /* opens large object */ static char pglarge_open__doc__[] = -"open(mode) -- open access to large object with specified mode " -"(INV_READ, INV_WRITE constants defined by module)."; + "open(mode) -- open access to large object with specified mode " + "(INV_READ, INV_WRITE constants defined by module)."; static PyObject * pglarge_open(pglargeobject * self, PyObject * args) { - int mode, - fd; + int mode, fd; /* check validity */ if (!check_lo_obj(self, CHECK_CLOSE)) @@ -256,7 +1023,7 @@ pglarge_open(pglargeobject * self, PyObject * args) /* close large object */ static char pglarge_close__doc__[] = -"close() -- close access to large object data."; + "close() -- close access to large object data."; static PyObject * pglarge_close(pglargeobject * self, PyObject * args) @@ -265,7 +1032,7 @@ pglarge_close(pglargeobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method close() takes no parameters."); + "method close() takes no parameters."); return NULL; } @@ -288,14 +1055,14 @@ pglarge_close(pglargeobject * self, PyObject * args) /* reads from large object */ static char pglarge_read__doc__[] = -"read(integer) -- read from large object to sized string. " -"Object must be opened in read mode before calling this method."; + "read(integer) -- read from large object to sized string. " + "Object must be opened in read mode before calling this method."; static PyObject * pglarge_read(pglargeobject * self, PyObject * args) { int size; - PyObject *buffer; + PyObject *buffer; /* checks validity */ if (!check_lo_obj(self, CHECK_OPEN)) @@ -331,30 +1098,30 @@ pglarge_read(pglargeobject * self, PyObject * args) /* write to large object */ static char pglarge_write__doc__[] = -"write(string) -- write sized string to large object. " -"Object must be opened in read mode before calling this method."; + "write(string) -- write sized string to large object. " + "Object must be opened in read mode before calling this method."; static PyObject * pglarge_write(pglargeobject * self, PyObject * args) { - char *buffer; - int size; + char *buffer; + int size, bufsize; /* checks validity */ if (!check_lo_obj(self, CHECK_OPEN)) return NULL; /* gets arguments */ - if (!PyArg_ParseTuple(args, "s", &buffer)) + if (!PyArg_ParseTuple(args, "s#", &buffer, &bufsize)) { PyErr_SetString(PyExc_TypeError, - "write(buffer), with buffer (sized string)."); + "write(buffer), with buffer (sized string)."); return NULL; } /* sends query */ if ((size = lo_write(self->pgcnx->cnx, self->lo_fd, buffer, - strlen(buffer))) < strlen(buffer)) + bufsize)) < bufsize) { PyErr_SetString(PyExc_IOError, "buffer truncated during write."); return NULL; @@ -367,17 +1134,15 @@ pglarge_write(pglargeobject * self, PyObject * args) /* go to position in large object */ static char pglarge_seek__doc__[] = -"seek(off, whence) -- move to specified position. Object must be opened " -"before calling this method. whence can be SEEK_SET, SEEK_CUR or SEEK_END, " -"constants defined by module."; + "seek(off, whence) -- move to specified position. Object must be opened " + "before calling this method. whence can be SEEK_SET, SEEK_CUR or SEEK_END, " + "constants defined by module."; static PyObject * pglarge_lseek(pglargeobject * self, PyObject * args) { /* offset and whence are initialized to keep compiler happy */ - int ret, - offset = 0, - whence = 0; + int ret, offset = 0, whence = 0; /* checks validity */ if (!check_lo_obj(self, CHECK_OPEN)) @@ -387,7 +1152,7 @@ pglarge_lseek(pglargeobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "ii", &offset, &whence)) { PyErr_SetString(PyExc_TypeError, - "lseek(offset, whence), with offset and whence (integers)."); + "lseek(offset, whence), with offset and whence (integers)."); return NULL; } @@ -404,20 +1169,19 @@ pglarge_lseek(pglargeobject * self, PyObject * args) /* gets large object size */ static char pglarge_size__doc__[] = -"size() -- return large object size. " -"Object must be opened before calling this method."; + "size() -- return large object size. " + "Object must be opened before calling this method."; static PyObject * pglarge_size(pglargeobject * self, PyObject * args) { - int start, - end; + int start, end; /* checks args */ if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method size() takes no parameters."); + "method size() takes no parameters."); return NULL; } @@ -440,10 +1204,10 @@ pglarge_size(pglargeobject * self, PyObject * args) } /* move back to start position */ - if ((start = lo_lseek(self->pgcnx->cnx, self->lo_fd, start, SEEK_SET)) == -1) + if ((start = lo_lseek(self->pgcnx->cnx,self->lo_fd,start,SEEK_SET)) == -1) { PyErr_SetString(PyExc_IOError, - "error while moving back to first position."); + "error while moving back to first position."); return NULL; } @@ -453,19 +1217,19 @@ pglarge_size(pglargeobject * self, PyObject * args) /* gets large object cursor position */ static char pglarge_tell__doc__[] = -"tell() -- give current position in large object. " -"Object must be opened before calling this method."; + "tell() -- give current position in large object. " + "Object must be opened before calling this method."; static PyObject * pglarge_tell(pglargeobject * self, PyObject * args) { - int start; + int start; /* checks args */ if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method tell() takes no parameters."); + "method tell() takes no parameters."); return NULL; } @@ -486,13 +1250,13 @@ pglarge_tell(pglargeobject * self, PyObject * args) /* exports large object as unix file */ static char pglarge_export__doc__[] = -"export(string) -- export large object data to specified file. " -"Object must be closed when calling this method."; + "export(string) -- export large object data to specified file. " + "Object must be closed when calling this method."; static PyObject * pglarge_export(pglargeobject * self, PyObject * args) { - char *name; + char *name; /* checks validity */ if (!check_lo_obj(self, CHECK_CLOSE)) @@ -502,7 +1266,7 @@ pglarge_export(pglargeobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "s", &name)) { PyErr_SetString(PyExc_TypeError, - "export(filename), with filename (string)."); + "export(filename), with filename (string)."); return NULL; } @@ -519,8 +1283,8 @@ pglarge_export(pglargeobject * self, PyObject * args) /* deletes a large object */ static char pglarge_unlink__doc__[] = -"unlink() -- destroy large object. " -"Object must be closed when calling this method."; + "unlink() -- destroy large object. " + "Object must be closed when calling this method."; static PyObject * pglarge_unlink(pglargeobject * self, PyObject * args) @@ -529,7 +1293,7 @@ pglarge_unlink(pglargeobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method unlink() takes no parameters."); + "method unlink() takes no parameters."); return NULL; } @@ -551,15 +1315,15 @@ pglarge_unlink(pglargeobject * self, PyObject * args) /* large object methods */ static struct PyMethodDef pglarge_methods[] = { - {"open", (PyCFunction) pglarge_open, 1, pglarge_open__doc__}, - {"close", (PyCFunction) pglarge_close, 1, pglarge_close__doc__}, - {"read", (PyCFunction) pglarge_read, 1, pglarge_read__doc__}, - {"write", (PyCFunction) pglarge_write, 1, pglarge_write__doc__}, - {"seek", (PyCFunction) pglarge_lseek, 1, pglarge_seek__doc__}, - {"size", (PyCFunction) pglarge_size, 1, pglarge_size__doc__}, - {"tell", (PyCFunction) pglarge_tell, 1, pglarge_tell__doc__}, - {"export", (PyCFunction) pglarge_export, 1, pglarge_export__doc__}, - {"unlink", (PyCFunction) pglarge_unlink, 1, pglarge_unlink__doc__}, + {"open", (PyCFunction) pglarge_open, 1, pglarge_open__doc__ }, + {"close", (PyCFunction) pglarge_close, 1, pglarge_close__doc__ }, + {"read", (PyCFunction) pglarge_read, 1, pglarge_read__doc__ }, + {"write", (PyCFunction) pglarge_write, 1, pglarge_write__doc__ }, + {"seek", (PyCFunction) pglarge_lseek, 1, pglarge_seek__doc__ }, + {"size", (PyCFunction) pglarge_size, 1, pglarge_size__doc__ }, + {"tell", (PyCFunction) pglarge_tell, 1, pglarge_tell__doc__ }, + {"export", (PyCFunction) pglarge_export, 1, pglarge_export__doc__ }, + {"unlink", (PyCFunction) pglarge_unlink, 1, pglarge_unlink__doc__ }, {NULL, NULL} }; @@ -599,13 +1363,13 @@ pglarge_getattr(pglargeobject * self, char *name) /* attributes list */ if (!strcmp(name, "__members__")) { - PyObject *list = PyList_New(3); + PyObject *list = PyList_New(3); if (list) { - PyList_SetItem(list, 0, PyString_FromString("oid")); - PyList_SetItem(list, 1, PyString_FromString("pgcnx")); - PyList_SetItem(list, 2, PyString_FromString("error")); + PyList_SET_ITEM(list, 0, PyString_FromString("oid")); + PyList_SET_ITEM(list, 1, PyString_FromString("pgcnx")); + PyList_SET_ITEM(list, 2, PyString_FromString("error")); } return list; @@ -627,46 +1391,56 @@ pglarge_getattr(pglargeobject * self, char *name) static int pglarge_print(pglargeobject * self, FILE *fp, int flags) { - char print_buffer[128]; + char print_buffer[128]; if (self->lo_fd >= 0) { +#ifdef NO_SNPRINTF + sprintf(print_buffer, + "Opened large object, oid %ld", (long)self->lo_oid); +#else snprintf(print_buffer, sizeof(print_buffer), - "Opened large object, oid %ld", (long) self->lo_oid); + "Opened large object, oid %ld", (long)self->lo_oid); +#endif fputs(print_buffer, fp); } else { +#ifdef NO_SNPRINTF + sprintf(print_buffer, + "Closed large object, oid %ld", (long)self->lo_oid); +#else snprintf(print_buffer, sizeof(print_buffer), - "Closed large object, oid %ld", (long) self->lo_oid); + "Closed large object, oid %ld", (long)self->lo_oid); +#endif fputs(print_buffer, fp); } return 0; -}; +} /* object type definition */ staticforward PyTypeObject PglargeType = { PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "pglarge", /* tp_name */ - sizeof(pglargeobject), /* tp_basicsize */ - 0, /* tp_itemsize */ + 0, /* ob_size */ + "pglarge", /* tp_name */ + sizeof(pglargeobject), /* tp_basicsize */ + 0, /* tp_itemsize */ /* methods */ - (destructor) pglarge_dealloc, /* tp_dealloc */ - (printfunc) pglarge_print, /* tp_print */ - (getattrfunc) pglarge_getattr, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ + (destructor) pglarge_dealloc, /* tp_dealloc */ + (printfunc) pglarge_print, /* tp_print */ + (getattrfunc) pglarge_getattr, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ }; -#endif /* LARGE_OBJECTS */ +#endif /* LARGE_OBJECTS */ /* --------------------------------------------------------------------- */ @@ -674,35 +1448,29 @@ staticforward PyTypeObject PglargeType = { /* connects to a database */ static char connect__doc__[] = -"connect(dbname, host, port, opt, tty) -- connect to a PostgreSQL database " -"using specified parameters (optionals, keywords aware)."; + "connect(dbname, host, port, opt, tty) -- connect to a PostgreSQL database " + "using specified parameters (optionals, keywords aware)."; static PyObject * -pgconnect(pgobject * self, PyObject * args, PyObject * dict) +pgconnect(pgobject *self, PyObject *args, PyObject *dict) { - static char *kwlist[] = {"dbname", "host", "port", "opt", - "tty", "user", "passwd", NULL}; - char *pghost, - *pgopt, - *pgtty, - *pgdbname, - *pguser, - *pgpasswd; - int pgport; - char port_buffer[20]; - pgobject *npgobj; + static const char *kwlist[] = { "dbname", "host", "port", "opt", + "tty", "user", "passwd" , NULL }; + char *pghost, *pgopt, *pgtty, *pgdbname, *pguser, *pgpasswd; + int pgport; + char port_buffer[20]; + pgobject *npgobj; pghost = pgopt = pgtty = pgdbname = pguser = pgpasswd = NULL; pgport = -1; - /* - * parses standard arguments With the right compiler warnings, this - * will issue a diagnostic. There is really no way around it. If I - * don't declare kwlist as const char *kwlist[] then it complains when - * I try to assign all those constant strings to it. - */ - if (!PyArg_ParseTupleAndKeywords(args, dict, "|zzlzzzz", kwlist, - &pgdbname, &pghost, &pgport, &pgopt, &pgtty, &pguser, &pgpasswd)) + /* parses standard arguments + * With the right compiler warnings, this will issue a diagnostic. + * There is really no way around it. If I don't declare kwlist as + * const char *kwlist[] then it complains when I try to assign all + * those constant strings to it. */ + if (!PyArg_ParseTupleAndKeywords(args, dict, "|zzlzzzz", (char **) kwlist, + &pgdbname, &pghost, &pgport, &pgopt, &pgtty, &pguser, &pgpasswd)) return NULL; #ifdef DEFAULT_VARS @@ -727,9 +1495,9 @@ pgconnect(pgobject * self, PyObject * args, PyObject * dict) if ((!pgpasswd) && (pg_default_passwd != Py_None)) pgpasswd = PyString_AsString(pg_default_passwd); -#endif /* DEFAULT_VARS */ +#endif /* DEFAULT_VARS */ - if ((npgobj = PyObject_NEW(pgobject, &PgType)) == NULL) + if ((npgobj = (pgobject*)pgobject_New()) == NULL) return NULL; if (pgport != -1) @@ -737,11 +1505,11 @@ pgconnect(pgobject * self, PyObject * args, PyObject * dict) bzero(port_buffer, sizeof(port_buffer)); sprintf(port_buffer, "%d", pgport); npgobj->cnx = PQsetdbLogin(pghost, port_buffer, pgopt, pgtty, pgdbname, - pguser, pgpasswd); + pguser, pgpasswd); } else npgobj->cnx = PQsetdbLogin(pghost, NULL, pgopt, pgtty, pgdbname, - pguser, pgpasswd); + pguser, pgpasswd); if (PQstatus(npgobj->cnx) == CONNECTION_BAD) { @@ -767,12 +1535,12 @@ pg_dealloc(pgobject * self) /* close without deleting */ static char pg_close__doc__[] = -"close() -- close connection. All instances of the connection object and " -"derived objects (queries and large objects) can no longer be used after " -"this call."; + "close() -- close connection. All instances of the connection object and " + "derived objects (queries and large objects) can no longer be used after " + "this call."; static PyObject * -pg_close(pgobject * self, PyObject * args) +pg_close(pgobject *self, PyObject *args) { /* gets args */ if (!PyArg_ParseTuple(args, "")) @@ -800,9 +1568,9 @@ pgquery_dealloc(pgqueryobject * self) /* resets connection */ static char pg_reset__doc__[] = -"reset() -- reset connection with current parameters. All derived queries " -"and large objects derived from this connection will not be usable after " -"this call."; + "reset() -- reset connection with current parameters. All derived queries " + "and large objects derived from this connection will not be usable after " + "this call."; static PyObject * pg_reset(pgobject * self, PyObject * args) @@ -817,7 +1585,7 @@ pg_reset(pgobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method reset() takes no parameters."); + "method reset() takes no parameters."); return NULL; } @@ -829,7 +1597,7 @@ pg_reset(pgobject * self, PyObject * args) /* get connection socket */ static char pg_fileno__doc__[] = -"fileno() -- return database connection socket file handle."; + "fileno() -- return database connection socket file handle."; static PyObject * pg_fileno(pgobject * self, PyObject * args) @@ -844,7 +1612,7 @@ pg_fileno(pgobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method fileno() takes no parameters."); + "method fileno() takes no parameters."); return NULL; } @@ -857,7 +1625,7 @@ pg_fileno(pgobject * self, PyObject * args) /* get number of rows */ static char pgquery_ntuples__doc__[] = -"ntuples() -- returns number of tuples returned by query."; + "ntuples() -- returns number of tuples returned by query."; static PyObject * pgquery_ntuples(pgqueryobject * self, PyObject * args) @@ -866,7 +1634,7 @@ pgquery_ntuples(pgqueryobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method ntuples() takes no parameters."); + "method ntuples() takes no parameters."); return NULL; } @@ -875,22 +1643,20 @@ pgquery_ntuples(pgqueryobject * self, PyObject * args) /* list fields names from query result */ static char pgquery_listfields__doc__[] = -"listfields() -- Lists field names from result."; + "listfields() -- Lists field names from result."; static PyObject * pgquery_listfields(pgqueryobject * self, PyObject * args) { - int i, - n; - char *name; - PyObject *fieldstuple, - *str; + int i, n; + char *name; + PyObject *fieldstuple, *str; /* checks args */ if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method listfields() takes no parameters."); + "method listfields() takes no parameters."); return NULL; } @@ -902,7 +1668,7 @@ pgquery_listfields(pgqueryobject * self, PyObject * args) { name = PQfname(self->last_result, i); str = PyString_FromString(name); - PyTuple_SetItem(fieldstuple, i, str); + PyTuple_SET_ITEM(fieldstuple, i, str); } return fieldstuple; @@ -910,19 +1676,19 @@ pgquery_listfields(pgqueryobject * self, PyObject * args) /* get field name from last result */ static char pgquery_fieldname__doc__[] = -"fieldname() -- returns name of field from result from its position."; + "fieldname() -- returns name of field from result from its position."; static PyObject * pgquery_fieldname(pgqueryobject * self, PyObject * args) { - int i; - char *name; + int i; + char *name; /* gets args */ if (!PyArg_ParseTuple(args, "i", &i)) { PyErr_SetString(PyExc_TypeError, - "fieldname(number), with number(integer)."); + "fieldname(number), with number(integer)."); return NULL; } @@ -940,13 +1706,13 @@ pgquery_fieldname(pgqueryobject * self, PyObject * args) /* gets fields number from name in last result */ static char pgquery_fieldnum__doc__[] = -"fieldnum() -- returns position in query for field from its name."; + "fieldnum() -- returns position in query for field from its name."; static PyObject * pgquery_fieldnum(pgqueryobject * self, PyObject * args) { - char *name; - int num; + char *name; + int num; /* gets args */ if (!PyArg_ParseTuple(args, "s", &name)) @@ -967,34 +1733,28 @@ pgquery_fieldnum(pgqueryobject * self, PyObject * args) /* retrieves last result */ static char pgquery_getresult__doc__[] = -"getresult() -- Gets the result of a query. The result is returned " -"as a list of rows, each one a list of fields in the order returned " -"by the server."; + "getresult() -- Gets the result of a query. The result is returned " + "as a list of rows, each one a list of fields in the order returned " + "by the server."; static PyObject * pgquery_getresult(pgqueryobject * self, PyObject * args) { - PyObject *rowtuple, - *reslist, - *val; - int i, - j, - m, - n, - *typ; + PyObject *rowtuple, *reslist, *val; + int i, j, m, n, *typ; /* checks args (args == NULL for an internal call) */ if ((args != NULL) && (!PyArg_ParseTuple(args, ""))) { PyErr_SetString(PyExc_SyntaxError, - "method getresult() takes no parameters."); + "method getresult() takes no parameters."); return NULL; } /* stores result in tuple */ - reslist = PyList_New(0); m = PQntuples(self->last_result); n = PQnfields(self->last_result); + reslist = PyList_New(m); if ((typ = malloc(sizeof(int) * n)) == NULL) { @@ -1029,14 +1789,25 @@ pgquery_getresult(pgqueryobject * self, PyObject * args) for (i = 0; i < m; i++) { - rowtuple = PyTuple_New(n); + if ((rowtuple = PyTuple_New(n)) == NULL) + { + Py_DECREF(reslist); + reslist = NULL; + goto exit; + } + for (j = 0; j < n; j++) { - int k; - char *s = PQgetvalue(self->last_result, i, j); - char cashbuf[64]; + int k; + char *s = PQgetvalue(self->last_result, i, j); + char cashbuf[64]; - switch (typ[j]) + if (PQgetisnull(self->last_result, i, j)) + { + Py_INCREF(Py_None); + val = Py_None; + } + else switch (typ[j]) { case 1: val = PyInt_FromLong(strtol(s, NULL, 10)); @@ -1046,9 +1817,8 @@ pgquery_getresult(pgqueryobject * self, PyObject * args) val = PyFloat_FromDouble(strtod(s, NULL)); break; - case 3: /* get rid of the '$' and commas */ - if (*s == '$') /* there's talk of getting rid of - * it */ + case 3: /* get rid of the '$' and commas */ + if (*s == '$') /* there's talk of getting rid of it */ s++; if ((s[0] == '-' || s[0] == '(') && s[1] == '$') @@ -1067,13 +1837,21 @@ pgquery_getresult(pgqueryobject * self, PyObject * args) break; } - PyTuple_SetItem(rowtuple, j, val); + if (val == NULL) + { + Py_DECREF(reslist); + Py_DECREF(rowtuple); + reslist = NULL; + goto exit; + } + + PyTuple_SET_ITEM(rowtuple, j, val); } - PyList_Append(reslist, rowtuple); - Py_XDECREF(rowtuple); + PyList_SET_ITEM(reslist, i, rowtuple); } +exit: free(typ); /* returns list */ @@ -1082,34 +1860,28 @@ pgquery_getresult(pgqueryobject * self, PyObject * args) /* retrieves last result as a list of dictionaries*/ static char pgquery_dictresult__doc__[] = -"dictresult() -- Gets the result of a query. The result is returned " -"as a list of rows, each one a dictionary with the field names used " -"as the labels."; + "dictresult() -- Gets the result of a query. The result is returned " + "as a list of rows, each one a dictionary with the field names used " + "as the labels."; static PyObject * pgquery_dictresult(pgqueryobject * self, PyObject * args) { - PyObject *dict, - *reslist, - *val; - int i, - j, - m, - n, - *typ; + PyObject *dict, *reslist, *val; + int i, j, m, n, *typ; /* checks args (args == NULL for an internal call) */ if ((args != NULL) && (!PyArg_ParseTuple(args, ""))) { PyErr_SetString(PyExc_SyntaxError, - "method getresult() takes no parameters."); + "method getresult() takes no parameters."); return NULL; } /* stores result in list */ - reslist = PyList_New(0); m = PQntuples(self->last_result); n = PQnfields(self->last_result); + reslist = PyList_New(m); if ((typ = malloc(sizeof(int) * n)) == NULL) { @@ -1144,14 +1916,25 @@ pgquery_dictresult(pgqueryobject * self, PyObject * args) for (i = 0; i < m; i++) { - dict = PyDict_New(); + if ((dict = PyDict_New()) == NULL) + { + Py_DECREF(reslist); + reslist = NULL; + goto exit; + } + for (j = 0; j < n; j++) { - int k; - char *s = PQgetvalue(self->last_result, i, j); - char cashbuf[64]; + int k; + char *s = PQgetvalue(self->last_result, i, j); + char cashbuf[64]; - switch (typ[j]) + if (PQgetisnull(self->last_result, i, j)) + { + Py_INCREF(Py_None); + val = Py_None; + } + else switch (typ[j]) { case 1: val = PyInt_FromLong(strtol(s, NULL, 10)); @@ -1161,9 +1944,8 @@ pgquery_dictresult(pgqueryobject * self, PyObject * args) val = PyFloat_FromDouble(strtod(s, NULL)); break; - case 3: /* get rid of the '$' and commas */ - if (*s == '$') /* there's talk of getting rid of - * it */ + case 3: /* get rid of the '$' and commas */ + if (*s == '$') /* there's talk of getting rid of it */ s++; if ((s[0] == '-' || s[0] == '(') && s[1] == '$') @@ -1182,14 +1964,22 @@ pgquery_dictresult(pgqueryobject * self, PyObject * args) break; } + if (val == NULL) + { + Py_DECREF(dict); + Py_DECREF(reslist); + reslist = NULL; + goto exit; + } + PyDict_SetItemString(dict, PQfname(self->last_result, j), val); - Py_XDECREF(val); + Py_DECREF(val); } - PyList_Append(reslist, dict); - Py_XDECREF(dict); + PyList_SET_ITEM(reslist, i, dict); } +exit: free(typ); /* returns list */ @@ -1198,15 +1988,14 @@ pgquery_dictresult(pgqueryobject * self, PyObject * args) /* gets asynchronous notify */ static char pg_getnotify__doc__[] = -"getnotify() -- get database notify for this connection."; + "getnotify() -- get database notify for this connection."; static PyObject * pg_getnotify(pgobject * self, PyObject * args) { - PGnotify *notify; - PGresult *result; - PyObject *notify_result, - *temp; + PGnotify *notify; + PGresult *result; + PyObject *notify_result, *temp; if (!self->cnx) { @@ -1218,25 +2007,40 @@ pg_getnotify(pgobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method getnotify() takes no parameters."); + "method getnotify() takes no parameters."); return NULL; } /* gets notify and builds result */ - - /* - * notifies only come back as result of a query, so I send an empty - * query - */ + /* notifies only come back as result of a query, so I send an empty query */ + Py_BEGIN_ALLOW_THREADS result = PQexec(self->cnx, " "); + Py_END_ALLOW_THREADS if ((notify = PQnotifies(self->cnx)) != NULL) { - notify_result = PyTuple_New(2); - temp = PyString_FromString(notify->relname); - PyTuple_SetItem(notify_result, 0, temp); - temp = PyInt_FromLong(notify->be_pid); - PyTuple_SetItem(notify_result, 1, temp); + if ((notify_result = PyTuple_New(2)) == NULL) + { + PQclear(result); + return NULL; + } + + if ((temp = PyString_FromString(notify->relname)) == NULL) + { + PQclear(result); + return NULL; + } + + PyTuple_SET_ITEM(notify_result, 0, temp); + + if ((temp = PyInt_FromLong(notify->be_pid)) == NULL) + { + PQclear(result); + Py_DECREF(notify_result); + return NULL; + } + + PyTuple_SET_ITEM(notify_result, 1, temp); free(notify); } else @@ -1251,17 +2055,40 @@ pg_getnotify(pgobject * self, PyObject * args) return notify_result; } +/* source creation */ +static char pg_source__doc__[] = + "source() -- creates a new source object for this connection"; + +static PyObject * +pg_source(pgobject * self, PyObject * args) +{ + /* checks validity */ + if (!check_cnx_obj(self)) + return NULL; + + /* checks args */ + if (!PyArg_ParseTuple(args, "")) + { + PyErr_SetString(PyExc_TypeError, "method source() takes no parameter."); + return NULL; + } + + /* allocate new pg query object */ + return (PyObject *)pgsource_new(self); +} + /* database query */ static char pg_query__doc__[] = -"query() -- creates a new query object for this connection."; + "query(sql) -- creates a new query object for this connection," + " using sql (string) request."; static PyObject * pg_query(pgobject * self, PyObject * args) { - char *query; - PGresult *result; - pgqueryobject *npgobj; - int status; + char *query; + PGresult *result; + pgqueryobject *npgobj; + int status; if (!self->cnx) { @@ -1276,8 +2103,17 @@ pg_query(pgobject * self, PyObject * args) return NULL; } + /* frees previous result */ + if (self->last_result) + { + PQclear(self->last_result); + self->last_result = NULL; + } + /* gets result */ + Py_BEGIN_ALLOW_THREADS result = PQexec(self->cnx, query); + Py_END_ALLOW_THREADS /* checks result validity */ if (!result) @@ -1303,7 +2139,7 @@ pg_query(pgobject * self, PyObject * args) case PGRES_NONFATAL_ERROR: PyErr_SetString(PGError, PQerrorMessage(self->cnx)); break; - case PGRES_COMMAND_OK: /* could be an INSERT */ + case PGRES_COMMAND_OK: /* could be an INSERT */ if (*(str = PQoidStatus(result)) == 0) /* nope */ { Py_INCREF(Py_None); @@ -1313,13 +2149,13 @@ pg_query(pgobject * self, PyObject * args) /* otherwise, return the oid */ return PyInt_FromLong(strtol(str, NULL, 10)); - case PGRES_COPY_OUT: /* no data will be received */ + case PGRES_COPY_OUT: /* no data will be received */ case PGRES_COPY_IN: Py_INCREF(Py_None); return Py_None; default: PyErr_SetString(PGError, "internal error: " - "unknown result status."); + "unknown result status."); break; } @@ -1336,13 +2172,13 @@ pg_query(pgobject * self, PyObject * args) #ifdef DIRECT_ACCESS static char pg_putline__doc__[] = -"putline() -- sends a line directly to the backend"; + "putline() -- sends a line directly to the backend"; /* direct acces function : putline */ static PyObject * pg_putline(pgobject * self, PyObject * args) { - char *line; + char *line; if (!self->cnx) { @@ -1365,14 +2201,13 @@ pg_putline(pgobject * self, PyObject * args) /* direct access function : getline */ static char pg_getline__doc__[] = -"getline() -- gets a line directly from the backend."; + "getline() -- gets a line directly from the backend."; static PyObject * pg_getline(pgobject * self, PyObject * args) { char line[MAX_BUFFER_SIZE]; - PyObject *str = NULL; /* GCC */ - int ret; + PyObject *str = NULL; /* GCC */ if (!self->cnx) { @@ -1384,7 +2219,7 @@ pg_getline(pgobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method getline() takes no parameters."); + "method getline() takes no parameters."); return NULL; } @@ -1409,7 +2244,7 @@ pg_getline(pgobject * self, PyObject * args) /* direct access function : end copy */ static char pg_endcopy__doc__[] = -"endcopy() -- synchronizes client and server"; + "endcopy() -- synchronizes client and server"; static PyObject * pg_endcopy(pgobject * self, PyObject * args) @@ -1424,7 +2259,7 @@ pg_endcopy(pgobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method endcopy() takes no parameters."); + "method endcopy() takes no parameters."); return NULL; } @@ -1433,14 +2268,13 @@ pg_endcopy(pgobject * self, PyObject * args) Py_INCREF(Py_None); return Py_None; } - -#endif /* DIRECT_ACCESS */ +#endif /* DIRECT_ACCESS */ static PyObject * -pgquery_print(pgqueryobject * self, FILE *fp, int flags) +pgquery_print(pgqueryobject *self, FILE *fp, int flags) { - PQprintOpt op; + PQprintOpt op; memset(&op, 0, sizeof(op)); op.align = 1; @@ -1451,26 +2285,27 @@ pgquery_print(pgqueryobject * self, FILE *fp, int flags) return 0; } +static PyObject * +pgquery_repr(pgqueryobject *self) +{ + return PyString_FromString(""); +} + /* insert table */ static char pg_inserttable__doc__[] = -"inserttable(string, list) -- insert list in table. The fields in the list " -"must be in the same order as in the table."; + "inserttable(string, list) -- insert list in table. The fields in the " + "list must be in the same order as in the table."; static PyObject * pg_inserttable(pgobject * self, PyObject * args) { - PGresult *result; - char *table, - *buffer, - *temp; + PGresult *result; + char *table, *buffer, *temp; char temp_buffer[256]; - PyObject *list, - *sublist, - *item; - PyObject *(*getitem) (PyObject *, int); - PyObject *(*getsubitem) (PyObject *, int); - int i, - j; + PyObject *list, *sublist, *item; + PyObject *(*getitem) (PyObject *, int); + PyObject *(*getsubitem) (PyObject *, int); + int i, j; if (!self->cnx) { @@ -1482,8 +2317,8 @@ pg_inserttable(pgobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "sO:filter", &table, &list)) { PyErr_SetString(PyExc_TypeError, - "tableinsert(table, content), with table (string) " - "and content (list)."); + "tableinsert(table, content), with table (string) " + "and content (list)."); return NULL; } @@ -1495,7 +2330,7 @@ pg_inserttable(pgobject * self, PyObject * args) else { PyErr_SetString(PyExc_TypeError, - "second arg must be some kind of array."); + "second arg must be some kind of array."); return NULL; } @@ -1505,7 +2340,7 @@ pg_inserttable(pgobject * self, PyObject * args) if (!PyTuple_Check(sublist) && !PyList_Check(sublist)) { PyErr_SetString(PyExc_TypeError, - "second arg must contain some kind of arrays."); + "second arg must contain some kind of arrays."); return NULL; } } @@ -1520,7 +2355,11 @@ pg_inserttable(pgobject * self, PyObject * args) /* starts query */ sprintf(buffer, "copy %s from stdin", table); - if (!(result = PQexec(self->cnx, buffer))) + Py_BEGIN_ALLOW_THREADS + result = PQexec(self->cnx, buffer); + Py_END_ALLOW_THREADS + + if (!result) { free(buffer); PyErr_SetString(PyExc_ValueError, PQerrorMessage(self->cnx)); @@ -1544,28 +2383,28 @@ pg_inserttable(pgobject * self, PyObject * args) { /* converts item to string */ if (PyString_Check(item)) - PyArg_ParseTuple(item, "s", &temp); + temp = PyString_AS_STRING(item); else if (PyInt_Check(item)) { - int k; + long k; - PyArg_ParseTuple(item, "i", &k); - sprintf(temp_buffer, "%d", k); + k = PyInt_AsLong(item); + sprintf(temp_buffer, "%ld", k); temp = temp_buffer; } else if (PyLong_Check(item)) { - long k; + long k; - PyArg_ParseTuple(item, "l", &k); + k = PyLong_AsLong(item); sprintf(temp_buffer, "%ld", k); temp = temp_buffer; } else if (PyFloat_Check(item)) { - double k; + double k; - PyArg_ParseTuple(item, "d", &k); + k = PyFloat_AS_DOUBLE(item); sprintf(temp_buffer, "%g", k); temp = temp_buffer; } @@ -1573,8 +2412,8 @@ pg_inserttable(pgobject * self, PyObject * args) { free(buffer); PyErr_SetString(PyExc_ValueError, - "items must be strings, integers, " - "longs or double (real)."); + "items must be strings, integers, " + "longs or double (real)."); return NULL; } @@ -1582,7 +2421,6 @@ pg_inserttable(pgobject * self, PyObject * args) if (strlen(buffer)) strncat(buffer, "\t", MAX_BUFFER_SIZE - strlen(buffer)); - fprintf(stderr, "Buffer: '%s', Temp: '%s'\n", buffer, temp); strncat(buffer, temp, MAX_BUFFER_SIZE - strlen(buffer)); } @@ -1593,7 +2431,7 @@ pg_inserttable(pgobject * self, PyObject * args) } /* ends query */ - PQputline(self->cnx, ".\n"); + PQputline(self->cnx, "\\.\n"); PQendcopy(self->cnx); free(buffer); @@ -1602,15 +2440,16 @@ pg_inserttable(pgobject * self, PyObject * args) return Py_None; } + /* creates large object */ static char pg_locreate__doc__[] = -"locreate() -- creates a new large object in the database."; + "locreate() -- creates a new large object in the database."; static PyObject * pg_locreate(pgobject * self, PyObject * args) { - int mode; - Oid lo_oid; + int mode; + Oid lo_oid; /* checks validity */ if (!check_cnx_obj(self)) @@ -1620,7 +2459,7 @@ pg_locreate(pgobject * self, PyObject * args) if (!PyArg_ParseTuple(args, "i", &mode)) { PyErr_SetString(PyExc_TypeError, - "locreate(mode), with mode (integer)."); + "locreate(mode), with mode (integer)."); return NULL; } @@ -1637,12 +2476,12 @@ pg_locreate(pgobject * self, PyObject * args) /* init from already known oid */ static char pg_getlo__doc__[] = -"getlo(long) -- create a large object instance for the specified oid."; + "getlo(long) -- create a large object instance for the specified oid."; static PyObject * pg_getlo(pgobject * self, PyObject * args) { - int lo_oid; + int lo_oid; /* checks validity */ if (!check_cnx_obj(self)) @@ -1651,7 +2490,7 @@ pg_getlo(pgobject * self, PyObject * args) /* gets arguments */ if (!PyArg_ParseTuple(args, "i", &lo_oid)) { - PyErr_SetString(PyExc_TypeError, "loopen(oid), with oid (integer)."); + PyErr_SetString(PyExc_TypeError, "getlo(oid), with oid (integer)."); return NULL; } @@ -1667,13 +2506,13 @@ pg_getlo(pgobject * self, PyObject * args) /* import unix file */ static char pg_loimport__doc__[] = -"loimport(string) -- create a new large object from specified file."; + "loimport(string) -- create a new large object from specified file."; static PyObject * pg_loimport(pgobject * self, PyObject * args) { - char *name; - Oid lo_oid; + char *name; + Oid lo_oid; /* checks validity */ if (!check_cnx_obj(self)) @@ -1700,24 +2539,25 @@ pg_loimport(pgobject * self, PyObject * args) /* connection object methods */ static struct PyMethodDef pgobj_methods[] = { - {"query", (PyCFunction) pg_query, 1, pg_query__doc__}, - {"reset", (PyCFunction) pg_reset, 1, pg_reset__doc__}, - {"close", (PyCFunction) pg_close, 1, pg_close__doc__}, - {"fileno", (PyCFunction) pg_fileno, 1, pg_fileno__doc__}, - {"getnotify", (PyCFunction) pg_getnotify, 1, pg_getnotify__doc__}, - {"inserttable", (PyCFunction) pg_inserttable, 1, pg_inserttable__doc__}, + {"source", (PyCFunction) pg_source, 1, pg_source__doc__ }, + {"query", (PyCFunction) pg_query, 1, pg_query__doc__ }, + {"reset", (PyCFunction) pg_reset, 1, pg_reset__doc__ }, + {"close", (PyCFunction) pg_close, 1, pg_close__doc__ }, + {"fileno", (PyCFunction) pg_fileno,1, pg_fileno__doc__ }, + {"getnotify", (PyCFunction) pg_getnotify, 1, pg_getnotify__doc__ }, + {"inserttable", (PyCFunction) pg_inserttable, 1, pg_inserttable__doc__ }, #ifdef DIRECT_ACCESS - {"putline", (PyCFunction) pg_putline, 1, pg_putline__doc__}, - {"getline", (PyCFunction) pg_getline, 1, pg_getline__doc__}, - {"endcopy", (PyCFunction) pg_endcopy, 1, pg_endcopy__doc__}, -#endif /* DIRECT_ACCESS */ + {"putline", (PyCFunction) pg_putline, 1, pg_putline__doc__ }, + {"getline", (PyCFunction) pg_getline, 1, pg_getline__doc__ }, + {"endcopy", (PyCFunction) pg_endcopy, 1, pg_endcopy__doc__ }, +#endif /* DIRECT_ACCESS */ #ifdef LARGE_OBJECTS - {"locreate", (PyCFunction) pg_locreate, 1, pg_locreate__doc__}, - {"getlo", (PyCFunction) pg_getlo, 1, pg_getlo__doc__}, - {"loimport", (PyCFunction) pg_loimport, 1, pg_loimport__doc__}, -#endif /* LARGE_OBJECTS */ + {"locreate", (PyCFunction) pg_locreate, 1, pg_locreate__doc__ }, + {"getlo", (PyCFunction) pg_getlo, 1, pg_getlo__doc__ }, + {"loimport", (PyCFunction) pg_loimport, 1, pg_loimport__doc__ }, +#endif /* LARGE_OBJECTS */ {NULL, NULL} /* sentinel */ }; @@ -1726,11 +2566,9 @@ static struct PyMethodDef pgobj_methods[] = { static PyObject * pg_getattr(pgobject * self, char *name) { - - /* - * Although we could check individually, there are only a few - * attributes that don't require a live connection and unless someone - * has an urgent need, this will have to do + /* Although we could check individually, there are only a few + * attributes that don't require a live connection and unless + * someone has an urgent need, this will have to do */ if (!self->cnx) { @@ -1743,8 +2581,7 @@ pg_getattr(pgobject * self, char *name) /* postmaster host */ if (!strcmp(name, "host")) { - char *r = PQhost(self->cnx); - + char *r = PQhost(self->cnx); return r ? PyString_FromString(r) : PyString_FromString("localhost"); } @@ -1775,23 +2612,23 @@ pg_getattr(pgobject * self, char *name) /* provided user name */ if (!strcmp(name, "user")) return PyString_FromString("Deprecated facility"); - /* return PyString_FromString(fe_getauthname("")); */ + /* return PyString_FromString(fe_getauthname("")); */ /* attributes list */ if (!strcmp(name, "__members__")) { - PyObject *list = PyList_New(8); + PyObject *list = PyList_New(8); if (list) { - PyList_SetItem(list, 0, PyString_FromString("host")); - PyList_SetItem(list, 1, PyString_FromString("port")); - PyList_SetItem(list, 2, PyString_FromString("db")); - PyList_SetItem(list, 3, PyString_FromString("options")); - PyList_SetItem(list, 4, PyString_FromString("tty")); - PyList_SetItem(list, 5, PyString_FromString("error")); - PyList_SetItem(list, 6, PyString_FromString("status")); - PyList_SetItem(list, 7, PyString_FromString("user")); + PyList_SET_ITEM(list, 0, PyString_FromString("host")); + PyList_SET_ITEM(list, 1, PyString_FromString("port")); + PyList_SET_ITEM(list, 2, PyString_FromString("db")); + PyList_SET_ITEM(list, 3, PyString_FromString("options")); + PyList_SET_ITEM(list, 4, PyString_FromString("tty")); + PyList_SET_ITEM(list, 5, PyString_FromString("error")); + PyList_SET_ITEM(list, 6, PyString_FromString("status")); + PyList_SET_ITEM(list, 7, PyString_FromString("user")); } return list; @@ -1823,12 +2660,12 @@ staticforward PyTypeObject PgType = { /* query object methods */ static struct PyMethodDef pgquery_methods[] = { - {"getresult", (PyCFunction) pgquery_getresult, 1, pgquery_getresult__doc__}, - {"dictresult", (PyCFunction) pgquery_dictresult, 1, pgquery_dictresult__doc__}, - {"fieldname", (PyCFunction) pgquery_fieldname, 1, pgquery_fieldname__doc__}, - {"fieldnum", (PyCFunction) pgquery_fieldnum, 1, pgquery_fieldnum__doc__}, - {"listfields", (PyCFunction) pgquery_listfields, 1, pgquery_listfields__doc__}, - {"ntuples", (PyCFunction) pgquery_ntuples, 1, pgquery_ntuples__doc__}, + {"getresult", (PyCFunction) pgquery_getresult, 1, pgquery_getresult__doc__}, + {"dictresult", (PyCFunction) pgquery_dictresult, 1, pgquery_dictresult__doc__}, + {"fieldname", (PyCFunction) pgquery_fieldname, 1, pgquery_fieldname__doc__}, + {"fieldnum", (PyCFunction) pgquery_fieldnum, 1, pgquery_fieldnum__doc__}, + {"listfields", (PyCFunction) pgquery_listfields, 1, pgquery_listfields__doc__}, + {"ntuples", (PyCFunction) pgquery_ntuples, 1, pgquery_ntuples__doc__}, {NULL, NULL} }; @@ -1843,21 +2680,21 @@ pgquery_getattr(pgqueryobject * self, char *name) /* query type definition */ staticforward PyTypeObject PgQueryType = { PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "pgqueryobject", /* tp_name */ - sizeof(pgqueryobject), /* tp_basicsize */ - 0, /* tp_itemsize */ + 0, /* ob_size */ + "pgqueryobject", /* tp_name */ + sizeof(pgqueryobject), /* tp_basicsize */ + 0, /* tp_itemsize */ /* methods */ - (destructor) pgquery_dealloc, /* tp_dealloc */ - (printfunc) pgquery_print, /* tp_print */ - (getattrfunc) pgquery_getattr, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ + (destructor) pgquery_dealloc, /* tp_dealloc */ + (printfunc) pgquery_print, /* tp_print */ + (getattrfunc) pgquery_getattr, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc) pgquery_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ }; @@ -1870,16 +2707,16 @@ staticforward PyTypeObject PgQueryType = { /* gets default host */ static char getdefhost__doc__[] = -"get_defhost() -- return default database host."; + "get_defhost() -- return default database host."; static PyObject * -pggetdefhost(PyObject * self, PyObject * args) +pggetdefhost(PyObject *self, PyObject *args) { /* checks args */ if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method get_defhost() takes no parameter."); + "method get_defhost() takes no parameter."); return NULL; } @@ -1889,19 +2726,19 @@ pggetdefhost(PyObject * self, PyObject * args) /* sets default host */ static char setdefhost__doc__[] = -"set_defhost(string) -- set default database host. Return previous value."; + "set_defhost(string) -- set default database host. Return previous value."; static PyObject * -pgsetdefhost(PyObject * self, PyObject * args) +pgsetdefhost(PyObject * self, PyObject *args) { - char *temp = NULL; - PyObject *old; + char *temp = NULL; + PyObject *old; /* gets arguments */ if (!PyArg_ParseTuple(args, "z", &temp)) { PyErr_SetString(PyExc_TypeError, - "set_defhost(name), with name (string/None)."); + "set_defhost(name), with name (string/None)."); return NULL; } @@ -1921,16 +2758,16 @@ pgsetdefhost(PyObject * self, PyObject * args) /* gets default base */ static char getdefbase__doc__[] = -"get_defbase() -- return default database name."; + "get_defbase() -- return default database name."; static PyObject * -pggetdefbase(PyObject * self, PyObject * args) +pggetdefbase(PyObject * self, PyObject *args) { /* checks args */ if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method get_defbase() takes no parameter."); + "method get_defbase() takes no parameter."); return NULL; } @@ -1940,19 +2777,19 @@ pggetdefbase(PyObject * self, PyObject * args) /* sets default base */ static char setdefbase__doc__[] = -"set_defbase(string) -- set default database name. Return previous value"; + "set_defbase(string) -- set default database name. Return previous value"; static PyObject * -pgsetdefbase(PyObject * self, PyObject * args) +pgsetdefbase(PyObject * self, PyObject *args) { - char *temp = NULL; - PyObject *old; + char *temp = NULL; + PyObject *old; /* gets arguments */ if (!PyArg_ParseTuple(args, "z", &temp)) { PyErr_SetString(PyExc_TypeError, - "set_defbase(name), with name (string/None)."); + "set_defbase(name), with name (string/None)."); return NULL; } @@ -1972,16 +2809,16 @@ pgsetdefbase(PyObject * self, PyObject * args) /* gets default options */ static char getdefopt__doc__[] = -"get_defopt() -- return default database options."; + "get_defopt() -- return default database options."; static PyObject * -pggetdefopt(PyObject * self, PyObject * args) +pggetdefopt(PyObject * self, PyObject *args) { /* checks args */ if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method get_defopt() takes no parameter."); + "method get_defopt() takes no parameter."); return NULL; } @@ -1991,19 +2828,19 @@ pggetdefopt(PyObject * self, PyObject * args) /* sets default opt */ static char setdefopt__doc__[] = -"set_defopt(string) -- set default database options. Return previous value."; + "set_defopt(string) -- set default database options. Return previous value."; static PyObject * -pgsetdefopt(PyObject * self, PyObject * args) +pgsetdefopt(PyObject * self, PyObject *args) { - char *temp = NULL; - PyObject *old; + char *temp = NULL; + PyObject *old; /* gets arguments */ if (!PyArg_ParseTuple(args, "z", &temp)) { PyErr_SetString(PyExc_TypeError, - "set_defopt(name), with name (string/None)."); + "set_defopt(name), with name (string/None)."); return NULL; } @@ -2023,16 +2860,16 @@ pgsetdefopt(PyObject * self, PyObject * args) /* gets default tty */ static char getdeftty__doc__[] = -"get_deftty() -- return default database debug terminal."; + "get_deftty() -- return default database debug terminal."; static PyObject * -pggetdeftty(PyObject * self, PyObject * args) +pggetdeftty(PyObject * self, PyObject *args) { /* checks args */ if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method get_deftty() takes no parameter."); + "method get_deftty() takes no parameter."); return NULL; } @@ -2042,20 +2879,20 @@ pggetdeftty(PyObject * self, PyObject * args) /* sets default tty */ static char setdeftty__doc__[] = -"set_deftty(string) -- set default database debug terminal. " -"Return previous value."; + "set_deftty(string) -- set default database debug terminal. " + "Return previous value."; static PyObject * -pgsetdeftty(PyObject * self, PyObject * args) +pgsetdeftty(PyObject * self, PyObject *args) { - char *temp = NULL; - PyObject *old; + char *temp = NULL; + PyObject *old; /* gets arguments */ if (!PyArg_ParseTuple(args, "z", &temp)) { PyErr_SetString(PyExc_TypeError, - "set_deftty(name), with name (string/None)."); + "set_deftty(name), with name (string/None)."); return NULL; } @@ -2075,16 +2912,16 @@ pgsetdeftty(PyObject * self, PyObject * args) /* gets default username */ static char getdefuser__doc__[] = -"get_defuser() -- return default database username."; + "get_defuser() -- return default database username."; static PyObject * -pggetdefuser(PyObject * self, PyObject * args) +pggetdefuser(PyObject * self, PyObject *args) { /* checks args */ if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method get_defuser() takes no parameter."); + "method get_defuser() takes no parameter."); return NULL; } @@ -2095,19 +2932,19 @@ pggetdefuser(PyObject * self, PyObject * args) /* sets default username */ static char setdefuser__doc__[] = -"set_defuser() -- set default database username. Return previous value."; + "set_defuser() -- set default database username. Return previous value."; static PyObject * -pgsetdefuser(PyObject * self, PyObject * args) +pgsetdefuser(PyObject * self, PyObject *args) { - char *temp = NULL; - PyObject *old; + char *temp = NULL; + PyObject *old; /* gets arguments */ if (!PyArg_ParseTuple(args, "z", &temp)) { PyErr_SetString(PyExc_TypeError, - "set_defuser(name), with name (string/None)."); + "set_defuser(name), with name (string/None)."); return NULL; } @@ -2127,19 +2964,20 @@ pgsetdefuser(PyObject * self, PyObject * args) /* sets default password */ static char setdefpasswd__doc__[] = -"set_defpasswd() -- set default database password."; + "set_defpasswd() -- set default database password."; static PyObject * -pgsetdefpasswd(PyObject * self, PyObject * args) +pgsetdefpasswd(PyObject * self, PyObject *args) { - char *temp = NULL; - PyObject *old; + char *temp = NULL; + PyObject *old; /* gets arguments */ if (!PyArg_ParseTuple(args, "z", &temp)) { PyErr_SetString(PyExc_TypeError, - "set_defpasswd(password), with password (string/None)."); + "set_defpasswd(password), with password (string/ +None)."); return NULL; } @@ -2160,16 +2998,16 @@ pgsetdefpasswd(PyObject * self, PyObject * args) /* gets default port */ static char getdefport__doc__[] = -"get_defport() -- return default database port."; + "get_defport() -- return default database port."; static PyObject * -pggetdefport(PyObject * self, PyObject * args) +pggetdefport(PyObject * self, PyObject *args) { /* checks args */ if (!PyArg_ParseTuple(args, "")) { PyErr_SetString(PyExc_SyntaxError, - "method get_defport() takes no parameter."); + "method get_defport() takes no parameter."); return NULL; } @@ -2179,19 +3017,19 @@ pggetdefport(PyObject * self, PyObject * args) /* sets default port */ static char setdefport__doc__[] = -"set_defport(integer) -- set default database port. Return previous value."; + "set_defport(integer) -- set default database port. Return previous value."; static PyObject * -pgsetdefport(PyObject * self, PyObject * args) +pgsetdefport(PyObject * self, PyObject *args) { long int port = -2; - PyObject *old; + PyObject *old; /* gets arguments */ if ((!PyArg_ParseTuple(args, "l", &port)) || (port < -1)) { PyErr_SetString(PyExc_TypeError, "set_defport(port), with port " - "(positive integer/-1)."); + "(positive integer/-1)."); return NULL; } @@ -2209,41 +3047,39 @@ pgsetdefport(PyObject * self, PyObject * args) return old; } -#endif /* DEFAULT_VARS */ +#endif /* DEFAULT_VARS */ /* List of functions defined in the module */ static struct PyMethodDef pg_methods[] = { - {"connect", (PyCFunction) pgconnect, 3, connect__doc__}, + {"connect", (PyCFunction) pgconnect, 3, connect__doc__ }, #ifdef DEFAULT_VARS - {"get_defhost", pggetdefhost, 1, getdefhost__doc__}, - {"set_defhost", pgsetdefhost, 1, setdefhost__doc__}, - {"get_defbase", pggetdefbase, 1, getdefbase__doc__}, - {"set_defbase", pgsetdefbase, 1, setdefbase__doc__}, - {"get_defopt", pggetdefopt, 1, getdefopt__doc__}, - {"set_defopt", pgsetdefopt, 1, setdefopt__doc__}, - {"get_deftty", pggetdeftty, 1, getdeftty__doc__}, - {"set_deftty", pgsetdeftty, 1, setdeftty__doc__}, - {"get_defport", pggetdefport, 1, getdefport__doc__}, - {"set_defport", pgsetdefport, 1, setdefport__doc__}, - {"get_defuser", pggetdefuser, 1, getdefuser__doc__}, - {"set_defuser", pgsetdefuser, 1, setdefuser__doc__}, - {"set_defpasswd", pgsetdefpasswd, 1, setdefpasswd__doc__}, -#endif /* DEFAULT_VARS */ + {"get_defhost", pggetdefhost, 1, getdefhost__doc__ }, + {"set_defhost", pgsetdefhost, 1, setdefhost__doc__ }, + {"get_defbase", pggetdefbase, 1, getdefbase__doc__ }, + {"set_defbase", pgsetdefbase, 1, setdefbase__doc__ }, + {"get_defopt", pggetdefopt, 1, getdefopt__doc__ }, + {"set_defopt", pgsetdefopt, 1, setdefopt__doc__ }, + {"get_deftty", pggetdeftty, 1, getdeftty__doc__ }, + {"set_deftty", pgsetdeftty, 1, setdeftty__doc__ }, + {"get_defport", pggetdefport, 1, getdefport__doc__ }, + {"set_defport", pgsetdefport, 1, setdefport__doc__ }, + {"get_defuser", pggetdefuser, 1, getdefuser__doc__ }, + {"set_defuser", pgsetdefuser, 1, setdefuser__doc__ }, + {"set_defpasswd", pgsetdefpasswd, 1, setdefpasswd__doc__ }, +#endif /* DEFAULT_VARS */ {NULL, NULL} /* sentinel */ }; static char pg__doc__[] = "Python interface to PostgreSQL DB"; /* Initialization function for the module */ -void init_pg(void); /* Python doesn't prototype this */ +void init_pg(void); /* Python doesn't prototype this */ void init_pg(void) { - PyObject *mod, - *dict, - *v; + PyObject *mod, *dict, *v; /* Initialize here because some WIN platforms get confused otherwise */ PglargeType.ob_type = PgType.ob_type = PgQueryType.ob_type = &PyType_Type; @@ -2253,7 +3089,7 @@ init_pg(void) dict = PyModule_GetDict(mod); /* Add some symbolic constants to the module */ - PGError = PyString_FromString("pg.error"); + PGError = PyString_FromString("_pg.error"); PyDict_SetItemString(dict, "error", PGError); /* Make the version available */ @@ -2262,6 +3098,12 @@ init_pg(void) PyDict_SetItemString(dict, "__version__", v); Py_DECREF(v); + /* results type for queries */ + PyDict_SetItemString(dict, "RESULT_EMPTY", PyInt_FromLong(RESULT_EMPTY)); + PyDict_SetItemString(dict, "RESULT_DML", PyInt_FromLong(RESULT_DML)); + PyDict_SetItemString(dict, "RESULT_DDL", PyInt_FromLong(RESULT_DDL)); + PyDict_SetItemString(dict, "RESULT_DQL", PyInt_FromLong(RESULT_DQL)); + #ifdef LARGE_OBJECTS /* create mode for large objects */ PyDict_SetItemString(dict, "INV_READ", PyInt_FromLong(INV_READ)); @@ -2271,25 +3113,18 @@ init_pg(void) PyDict_SetItemString(dict, "SEEK_SET", PyInt_FromLong(SEEK_SET)); PyDict_SetItemString(dict, "SEEK_CUR", PyInt_FromLong(SEEK_CUR)); PyDict_SetItemString(dict, "SEEK_END", PyInt_FromLong(SEEK_END)); -#endif /* LARGE_OBJECTS */ +#endif /* LARGE_OBJECTS */ #ifdef DEFAULT_VARS /* prepares default values */ - Py_INCREF(Py_None); - pg_default_host = Py_None; - Py_INCREF(Py_None); - pg_default_base = Py_None; - Py_INCREF(Py_None); - pg_default_opt = Py_None; - Py_INCREF(Py_None); - pg_default_port = Py_None; - Py_INCREF(Py_None); - pg_default_tty = Py_None; - Py_INCREF(Py_None); - pg_default_user = Py_None; - Py_INCREF(Py_None); - pg_default_passwd = Py_None; -#endif /* DEFAULT_VARS */ + Py_INCREF(Py_None); pg_default_host = Py_None; + Py_INCREF(Py_None); pg_default_base = Py_None; + Py_INCREF(Py_None); pg_default_opt = Py_None; + Py_INCREF(Py_None); pg_default_port = Py_None; + Py_INCREF(Py_None); pg_default_tty = Py_None; + Py_INCREF(Py_None); pg_default_user = Py_None; + Py_INCREF(Py_None); pg_default_passwd = Py_None; +#endif /* DEFAULT_VARS */ /* Check for errors */ if (PyErr_Occurred()) diff --git a/src/interfaces/python/pgsqldb.py b/src/interfaces/python/pgsqldb.py deleted file mode 100644 index df768b68b2..0000000000 --- a/src/interfaces/python/pgsqldb.py +++ /dev/null @@ -1,46 +0,0 @@ -# pgsqldb.py -# Written by D'Arcy J.M. Cain - -# This library implements the DB-SIG API -# It includes the pg module and builds on it - -from _pg import * - -import string - -class _cursor: - """For cursor object""" - - def __init__(self, conn): - self.conn = conn - self.cursor = None - self.arraysize = 1 - self.description = None - self.name = string.split(`self`)[3][:-1] - - def close(self): - if self.conn == None: raise self.conn.error, "Cursor has been closed" - if self.cursor == None: raise self.conn.error, "No cursor created" - self.conn.query('CLOSE %s' % self.name) - self.conn = None - - def __del__(self): - if self.cursor != None and self.conn != None: - self.conn.query('CLOSE %s' % self.name) - - -class pgsqldb: - """This class wraps the pg connection type in a DB-SIG API interface""" - - def __init__(self, *args, **kw): - self.db = apply(connect, args, kw) - - # Create convience methods, in a way that is still overridable. - for e in ('query', 'reset', 'close', 'getnotify', 'inserttable', - 'putline', 'getline', 'endcopy', - 'host', 'port', 'db', 'options', - 'tty', 'error', 'status', 'user', - 'locreate', 'getlo', 'loimport'): - if not hasattr(self,e) and hasattr(self.db,e): - exec 'self.%s = self.db.%s' % ( e, e ) - diff --git a/src/interfaces/python/setup.py b/src/interfaces/python/setup.py new file mode 100755 index 0000000000..c128e6e799 --- /dev/null +++ b/src/interfaces/python/setup.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +include_dirs=['/usr/include/pgsql'] +library_dirs=['usr/lib/pgsql'] +optional_libs=['pq'] + +# Setup script for the PyGreSQL version 3 +# created 2000/04 Mark Alexander +# tweaked 2000/05 Jeremy Hylton + +# requires distutils; standard in Python 1.6, otherwise download from +# http://www.python.org/sigs/distutils-sig/download.html + +# You may have to change the first 3 variables (include_dirs, +# library_dirs, optional_libs) to match your postgres distribution. + +# Now, you can: +# python setup.py build # to build the module +# python setup.py install # to install it + +# See http://www.python.org/sigs/distutils-sig/doc/ for more information +# on using distutils to install Python programs. + +from distutils.core import setup + +setup (name = "PyGreSQL", + version = "3.0", + description = "Python PostgreSQL Interfaces", + author = "D'Arcy J. M. Cain", + author_email = "darcy@druid.net", + url = "http://www.druid.net/pygresql/", + licence = "Python", + + py_modules = ['pg', 'pgdb'], + ext_modules = [ ('_pgmodule', { + 'sources': ['pgmodule.c'], + 'include_dirs': include_dirs, + 'library_dirs': library_dirs, + 'libraries': optional_libs + } + )] +) + diff --git a/src/interfaces/python/tutorial/advanced.py b/src/interfaces/python/tutorial/advanced.py deleted file mode 100755 index 4edf1e9294..0000000000 --- a/src/interfaces/python/tutorial/advanced.py +++ /dev/null @@ -1,171 +0,0 @@ -#! /usr/local/bin/python -# advanced.py - demo of advanced features of PostGres. Some may not be ANSI. -# inspired from the Postgres tutorial -# adapted to Python 1995 by Pascal Andre - -print "__________________________________________________________________" -print "MODULE ADVANCED.PY : ADVANCED POSTGRES SQL COMMANDS TUTORIAL" -print -print "This module is designed for being imported from python prompt" -print -print "In order to run the samples included here, first create a connection" -print "using : cnx = advanced.DB(...)" -print "then start the demo with: advanced.demo(cnx)" -print "__________________________________________________________________" - -from pgtools import * -from pg import DB - -# inheritance features -def inherit_demo(pgcnx): - print "-----------------------------" - print "-- Inheritance:" - print "-- a table can inherit from zero or more tables. A query" - print "-- can reference either all rows of a table or all rows " - print "-- of a table plus all of its descendants." - print "-----------------------------" - print - print "-- For example, the capitals table inherits from cities table." - print "-- (It inherits all data fields from cities.)" - print - print "CREATE TABLE cities (" - print " name text," - print " population float8," - print " altitude int" - print ")" - print - print "CREATE TABLE capitals (" - print " state varchar(2)" - print ") INHERITS (cities)" - pgcnx.query("CREATE TABLE cities (" \ - "name text," \ - "population float8," \ - "altitude int)") - pgcnx.query("CREATE TABLE capitals (" \ - "state varchar(2)) INHERITS (cities)") - wait_key() - print - print "-- now, let's populate the tables" - print - print "INSERT INTO cities VALUES ('San Francisco', 7.24E+5, 63)" - print "INSERT INTO cities VALUES ('Las Vegas', 2.583E+5, 2174)" - print "INSERT INTO cities VALUES ('Mariposa', 1200, 1953)" - print - print "INSERT INTO capitals VALUES ('Sacramento', 3.694E+5, 30, 'CA')" - print "INSERT INTO capitals VALUES ('Madison', 1.913E+5, 845, 'WI')" - print - pgcnx.query( - "INSERT INTO cities VALUES ('San Francisco', 7.24E+5, 63)") - pgcnx.query( - "INSERT INTO cities VALUES ('Las Vegas', 2.583E+5, 2174)") - pgcnx.query( - "INSERT INTO cities VALUES ('Mariposa', 1200, 1953)") - pgcnx.query("INSERT INTO capitals" \ - " VALUES ('Sacramento', 3.694E+5, 30, 'CA')") - pgcnx.query("INSERT INTO capitals" \ - " VALUES ('Madison', 1.913E+5, 845, 'WI')") - print - print "SELECT * FROM cities" - print pgcnx.query("SELECT * FROM cities") - print "SELECT * FROM capitals" - print pgcnx.query("SELECT * FROM capitals") - print - print "-- like before, a regular query references rows of the base" - print "-- table only" - print - print "SELECT name, altitude" - print "FROM cities" - print "WHERE altitude > 500;" - print pgcnx.query("SELECT name, altitude " \ - "FROM cities " \ - "WHERE altitude > 500") - print - print "-- on the other hand, you can find all cities, including " - print "-- capitals, that are located at an altitude of 500 'ft " - print "-- or higher by:" - print - print "SELECT c.name, c.altitude" - print "FROM cities* c" - print "WHERE c.altitude > 500" - print pgcnx.query("SELECT c.name, c.altitude " \ - "FROM cities* c " \ - "WHERE c.altitude > 500") - -# arrays attributes -def array_demo(pgcnx): - print "----------------------" - print "-- Arrays:" - print "-- attributes can be arrays of base types or user-defined " - print "-- types" - print "----------------------" - print - print "CREATE TABLE sal_emp (" - print " name text," - print " pay_by_quarter int4[]," - print " schedule text[][]" - print ")" - pgcnx.query("CREATE TABLE sal_emp (" \ - "name text," \ - "pay_by_quarter int4[]," \ - "schedule text[][])") - wait_key() - print - print "-- insert instances with array attributes. " - print " Note the use of braces" - print - print "INSERT INTO sal_emp VALUES (" - print " 'Bill'," - print " '{10000,10000,10000,10000}'," - print " '{{\"meeting\", \"lunch\"}, {}}')" - print - print "INSERT INTO sal_emp VALUES (" - print " 'Carol'," - print " '{20000,25000,25000,25000}'," - print " '{{\"talk\", \"consult\"}, {\"meeting\"}}')" - print - pgcnx.query("INSERT INTO sal_emp VALUES (" \ - "'Bill', '{10000,10000,10000,10000}'," \ - "'{{\"meeting\", \"lunch\"}, {}}')") - pgcnx.query("INSERT INTO sal_emp VALUES (" \ - "'Carol', '{20000,25000,25000,25000}'," \ - "'{{\"talk\", \"consult\"}, {\"meeting\"}}')") - wait_key() - print - print "----------------------" - print "-- queries on array attributes" - print "----------------------" - print - print "SELECT name FROM sal_emp WHERE" - print " sal_emp.pay_by_quarter[1] <> sal_emp.pay_by_quarter[2]" - print - print pgcnx.query("SELECT name FROM sal_emp WHERE " \ - "sal_emp.pay_by_quarter[1] <> sal_emp.pay_by_quarter[2]") - print - print "-- retrieve third quarter pay of all employees" - print - print "SELECT sal_emp.pay_by_quarter[3] FROM sal_emp" - print - print pgcnx.query("SELECT sal_emp.pay_by_quarter[3] FROM sal_emp") - print - print "-- select subarrays" - print - print "SELECT sal_emp.schedule[1:2][1:1] FROM sal_emp WHERE " - print " sal_emp.name = 'Bill'" - print pgcnx.query("SELECT sal_emp.schedule[1:2][1:1] FROM sal_emp WHERE " \ - "sal_emp.name = 'Bill'") - -# base cleanup -def demo_cleanup(pgcnx): - print "-- clean up (you must remove the children first)" - print "DROP TABLE sal_emp" - print "DROP TABLE capitals" - print "DROP TABLE cities;" - pgcnx.query("DROP TABLE sal_emp") - pgcnx.query("DROP TABLE capitals") - pgcnx.query("DROP TABLE cities") - -# main demo function -def demo(pgcnx): - inherit_demo(pgcnx) - array_demo(pgcnx) - demo_cleanup(pgcnx) diff --git a/src/interfaces/python/tutorial/basics.py b/src/interfaces/python/tutorial/basics.py deleted file mode 100755 index 418e86bca6..0000000000 --- a/src/interfaces/python/tutorial/basics.py +++ /dev/null @@ -1,284 +0,0 @@ -#! /usr/local/bin/python -# basics.py - basic SQL commands tutorial -# inspired from the Postgres95 tutorial -# adapted to Python 1995 by Pascal ANDRE - -print "__________________________________________________________________" -print "MODULE BASICS.PY : BASIC SQL COMMANDS TUTORIAL" -print -print "This module is designed for being imported from python prompt" -print -print "In order to run the samples included here, first create a connection" -print "using : cnx = basics.DB(...)" -print "then start the demo with: basics.demo(cnx)" -print "__________________________________________________________________" - -from pg import DB -from pgtools import * - -# table creation commands -def create_table(pgcnx): - print "-----------------------------" - print "-- Creating a table:" - print "-- a CREATE TABLE is used to create base tables. POSTGRES" - print "-- SQL has its own set of built-in types. (Note that" - print "-- keywords are case-insensitive but identifiers are " - print "-- case-sensitive.)" - print "-----------------------------" - print - print "Sending query :" - print "CREATE TABLE weather (" - print " city varchar(80)," - print " temp_lo int," - print " temp_hi int," - print " prcp float8," - print " date date" - print ")" - pgcnx.query("CREATE TABLE weather (city varchar(80), temp_lo int," \ - "temp_hi int, prcp float8, date date)") - print - print "Sending query :" - print "CREATE TABLE cities (" - print " name varchar(80)," - print " location point" - print ")" - pgcnx.query("CREATE TABLE cities (" \ - "name varchar(80)," \ - "location point)") - -# data insertion commands -def insert_data(pgcnx): - print "-----------------------------" - print "-- Inserting data:" - print "-- an INSERT statement is used to insert a new row into" - print "-- a table. There are several ways you can specify what" - print "-- columns the data should go to." - print "-----------------------------" - print - print "-- 1. the simplest case is when the list of value correspond to" - print "-- the order of the columns specified in CREATE TABLE." - print - print "Sending query :" - print "INSERT INTO weather " - print " VALUES ('San Francisco', 46, 50, 0.25, '11/27/1994')" - pgcnx.query("INSERT INTO weather " \ - "VALUES ('San Francisco', 46, 50, 0.25, '11/27/1994')") - print - print "Sending query :" - print "INSERT INTO cities " - print " VALUES ('San Francisco', '(-194.0, 53.0)')" - pgcnx.query("INSERT INTO cities " \ - "VALUES ('San Francisco', '(-194.0, 53.0)')") - print - wait_key() - print "-- 2. you can also specify what column the values correspond " - print " to. (The columns can be specified in any order. You may " - print " also omit any number of columns. eg. unknown precipitation" - print " below)" - print "Sending query :" - print "INSERT INTO weather (city, temp_lo, temp_hi, prcp, date)" - print " VALUES ('San Francisco', 43, 57, 0.0, '11/29/1994')" - pgcnx.query("INSERT INTO weather (date, city, temp_hi, temp_lo)" \ - "VALUES ('11/29/1994', 'Hayward', 54, 37)") - -# direct selection commands -def select_data1(pgcnx): - print "-----------------------------" - print "-- Retrieving data:" - print "-- a SELECT statement is used for retrieving data. The " - print "-- basic syntax is:" - print "-- SELECT columns FROM tables WHERE predicates" - print "-----------------------------" - print - print "-- a simple one would be the query:" - print "SELECT * FROM weather" - print - print "The result is :" - q = pgcnx.query("SELECT * FROM weather") - print q - print - print "-- you may also specify expressions in the target list (the " - print "-- 'AS column' specifies the column name of the result. It is " - print "-- optional.)" - print "The query :" - print " SELECT city, (temp_hi+temp_lo)/2 AS temp_avg, date " - print " FROM weather" - print "Gives :" - print pgcnx.query("SELECT city, (temp_hi+temp_lo)/2 " \ - "AS temp_avg, date FROM weather") - print - print "-- if you want to retrieve rows that satisfy certain condition" - print "-- (ie. a restriction), specify the condition in WHERE. The " - print "-- following retrieves the weather of San Francisco on rainy " - print "-- days." - print "SELECT *" - print "FROM weather" - print "WHERE city = 'San Francisco' " - print " and prcp > 0.0" - print pgcnx.query("SELECT * FROM weather WHERE city = 'San Francisco'" \ - " AND prcp > 0.0") - print - print "-- here is a more complicated one. Duplicates are removed when " - print "-- DISTINCT is specified. ORDER BY specifies the column to sort" - print "-- on. (Just to make sure the following won't confuse you, " - print "-- DISTINCT and ORDER BY can be used separately.)" - print "SELECT DISTINCT city" - print "FROM weather" - print "ORDER BY city;" - print pgcnx.query("SELECT DISTINCT city FROM weather ORDER BY city") - -# selection to a temporary table -def select_data2(pgcnx): - print "-----------------------------" - print "-- Retrieving data into other classes:" - print "-- a SELECT ... INTO statement can be used to retrieve " - print "-- data into another class." - print "-----------------------------" - print - print "The query :" - print "SELECT * INTO TABLE temp " - print "FROM weather" - print "WHERE city = 'San Francisco' " - print " and prcp > 0.0" - pgcnx.query("SELECT * INTO TABLE temp FROM weather " \ - "WHERE city = 'San Francisco' and prcp > 0.0") - print "Fills the table temp, that can be listed with :" - print "SELECT * from temp" - print pgcnx.query("SELECT * from temp") - -# aggregate creation commands -def create_aggregate(pgcnx): - print "-----------------------------" - print "-- Aggregates" - print "-----------------------------" - print - print "Let's consider the query :" - print "SELECT max(temp_lo)" - print "FROM weather;" - print pgcnx.query("SELECT max(temp_lo) FROM weather") - print - print "-- Aggregate with GROUP BY" - print "SELECT city, max(temp_lo)" - print "FROM weather " - print "GROUP BY city;" - print pgcnx.query( "SELECT city, max(temp_lo)" \ - "FROM weather GROUP BY city") - -# table join commands -def join_table(pgcnx): - print "-----------------------------" - print "-- Joining tables:" - print "-- queries can access multiple tables at once or access" - print "-- the same table in such a way that multiple instances" - print "-- of the table are being processed at the same time." - print "-----------------------------" - print - print "-- suppose we want to find all the records that are in the " - print "-- temperature range of other records. W1 and W2 are aliases " - print "--for weather." - print - print "SELECT W1.city, W1.temp_lo, W1.temp_hi, " - print " W2.city, W2.temp_lo, W2.temp_hi" - print "FROM weather W1, weather W2" - print "WHERE W1.temp_lo < W2.temp_lo " - print " and W1.temp_hi > W2.temp_hi" - print - print pgcnx.query("SELECT W1.city, W1.temp_lo, W1.temp_hi, " \ - "W2.city, W2.temp_lo, W2.temp_hi FROM weather W1, weather W2 "\ - "WHERE W1.temp_lo < W2.temp_lo and W1.temp_hi > W2.temp_hi") - print - print "-- let's join two tables. The following joins the weather table" - print "-- and the cities table." - print - print "SELECT city, location, prcp, date" - print "FROM weather, cities" - print "WHERE name = city" - print - print pgcnx.query("SELECT city, location, prcp, date FROM weather, cities"\ - " WHERE name = city") - print - print "-- since the column names are all different, we don't have to " - print "-- specify the table name. If you want to be clear, you can do " - print "-- the following. They give identical results, of course." - print - print "SELECT w.city, c.location, w.prcp, w.date" - print "FROM weather w, cities c" - print "WHERE c.name = w.city;" - print - print pgcnx.query("SELECT w.city, c.location, w.prcp, w.date " \ - "FROM weather w, cities c WHERE c.name = w.city") - -# data updating commands -def update_data(pgcnx): - print "-----------------------------" - print "-- Updating data:" - print "-- an UPDATE statement is used for updating data. " - print "-----------------------------" - print - print "-- suppose you discover the temperature readings are all off by" - print "-- 2 degrees as of Nov 28, you may update the data as follow:" - print - print "UPDATE weather" - print " SET temp_hi = temp_hi - 2, temp_lo = temp_lo - 2" - print " WHERE date > '11/28/1994'" - print - pgcnx.query("UPDATE weather " \ - "SET temp_hi = temp_hi - 2, temp_lo = temp_lo - 2" \ - "WHERE date > '11/28/1994'") - print - print "SELECT * from weather" - print pgcnx.query("SELECT * from weather") - -# data deletion commands -def delete_data(pgcnx): - print "-----------------------------" - print "-- Deleting data:" - print "-- a DELETE statement is used for deleting rows from a " - print "-- table." - print "-----------------------------" - print - print "-- suppose you are no longer interested in the weather of " - print "-- Hayward, you can do the following to delete those rows from" - print "-- the table" - print - print "DELETE FROM weather WHERE city = 'Hayward'" - pgcnx.query("DELETE FROM weather WHERE city = 'Hayward'") - print - print "SELECT * from weather" - print - print pgcnx.query("SELECT * from weather") - print - print "-- you can also delete all the rows in a table by doing the " - print "-- following. (This is different from DROP TABLE which removes " - print "-- the table in addition to the removing the rows.)" - print - print "DELETE FROM weather" - pgcnx.query("DELETE FROM weather") - print - print "SELECT * from weather" - print pgcnx.query("SELECT * from weather") - -# table removal commands -def remove_table(pgcnx): - print "-----------------------------" - print "-- Removing the tables:" - print "-- DROP TABLE is used to remove tables. After you have" - print "-- done this, you can no longer use those tables." - print "-----------------------------" - print - print "DROP TABLE weather, cities, temp" - pgcnx.query("DROP TABLE weather, cities, temp") - -# main demo function -def demo(pgcnx): - create_table(pgcnx) - wait_key() - insert_data(pgcnx) - wait_key() - select_data1(pgcnx) - select_data2(pgcnx) - create_aggregate(pgcnx) - join_table(pgcnx) - update_data(pgcnx) - delete_data(pgcnx) - remove_table(pgcnx) diff --git a/src/interfaces/python/tutorial/func.py b/src/interfaces/python/tutorial/func.py deleted file mode 100755 index d1412620c7..0000000000 --- a/src/interfaces/python/tutorial/func.py +++ /dev/null @@ -1,193 +0,0 @@ -# func.py - demonstrate the use of SQL functions -# inspired from the PostgreSQL tutorial -# adapted to Python 1995 by Pascal ANDRE - -print "__________________________________________________________________" -print "MODULE FUNC.PY : SQL FUNCTION DEFINITION TUTORIAL" -print -print "This module is designed for being imported from python prompt" -print -print "In order to run the samples included here, first create a connection" -print "using : cnx = func.DB(...)" -print "then start the demo with: func.demo(cnx)" -print "__________________________________________________________________" - -from pgtools import * -from pg import DB - -# basic functions declaration -def base_func(pgcnx): - print "-----------------------------" - print "-- Creating SQL Functions on Base Types" - print "-- a CREATE FUNCTION statement lets you create a new " - print "-- function that can be used in expressions (in SELECT, " - print "-- INSERT, etc.). We will start with functions that " - print "-- return values of base types." - print "-----------------------------" - print - print "--" - print "-- let's create a simple SQL function that takes no arguments" - print "-- and returns 1" - print - print "CREATE FUNCTION one() RETURNS int4" - print " AS 'SELECT 1 as ONE' LANGUAGE 'sql'" - pgcnx.query("CREATE FUNCTION one() RETURNS int4 " \ - "AS 'SELECT 1 as ONE' LANGUAGE 'sql'") - wait_key() - print - print "--" - print "-- functions can be used in any expressions (eg. in the target" - print "-- list or qualifications)" - print - print "SELECT one() AS answer" - print pgcnx.query("SELECT one() AS answer") - print - print "--" - print "-- here's how you create a function that takes arguments. The" - print "-- following function returns the sum of its two arguments:" - print - print "CREATE FUNCTION add_em(int4, int4) RETURNS int4" - print " AS 'SELECT $1 + $2' LANGUAGE 'sql'" - pgcnx.query("CREATE FUNCTION add_em(int4, int4) RETURNS int4 " \ - "AS 'SELECT $1 + $2' LANGUAGE 'sql'") - print - print "SELECT add_em(1, 2) AS answer" - print pgcnx.query("SELECT add_em(1, 2) AS answer") - -# functions on composite types -def comp_func(pgcnx): - print "-----------------------------" - print "-- Creating SQL Functions on Composite Types" - print "-- it is also possible to create functions that return" - print "-- values of composite types." - print "-----------------------------" - print - print "-- before we create more sophisticated functions, let's " - print "-- populate an EMP table" - print - print "CREATE TABLE EMP (" - print " name text," - print " salary int4," - print " age int4," - print " dept varchar(16)" - print ")" - pgcnx.query("CREATE TABLE EMP (" \ - "name text," \ - "salary int4," \ - "age int4," \ - "dept varchar(16))") - print - print "INSERT INTO EMP VALUES ('Sam', 1200, 16, 'toy')" - print "INSERT INTO EMP VALUES ('Claire', 5000, 32, 'shoe')" - print "INSERT INTO EMP VALUES ('Andy', -1000, 2, 'candy')" - print "INSERT INTO EMP VALUES ('Bill', 4200, 36, 'shoe')" - print "INSERT INTO EMP VALUES ('Ginger', 4800, 30, 'candy')" - pgcnx.query("INSERT INTO EMP VALUES ('Sam', 1200, 16, 'toy')") - pgcnx.query("INSERT INTO EMP VALUES ('Claire', 5000, 32, 'shoe')") - pgcnx.query("INSERT INTO EMP VALUES ('Andy', -1000, 2, 'candy')") - pgcnx.query("INSERT INTO EMP VALUES ('Bill', 4200, 36, 'shoe')") - pgcnx.query("INSERT INTO EMP VALUES ('Ginger', 4800, 30, 'candy')") - wait_key() - print - print "-- the argument of a function can also be a tuple. For " - print "-- instance, double_salary takes a tuple of the EMP table" - print - print "CREATE FUNCTION double_salary(EMP) RETURNS int4" - print " AS 'SELECT $1.salary * 2 AS salary' LANGUAGE 'sql'" - pgcnx.query("CREATE FUNCTION double_salary(EMP) RETURNS int4 " \ - "AS 'SELECT $1.salary * 2 AS salary' LANGUAGE 'sql'") - print - print "SELECT name, double_salary(EMP) AS dream" - print "FROM EMP" - print "WHERE EMP.dept = 'toy'" - print pgcnx.query("SELECT name, double_salary(EMP) AS dream " \ - "FROM EMP WHERE EMP.dept = 'toy'") - print - print "-- the return value of a function can also be a tuple. However," - print "-- make sure that the expressions in the target list is in the " - print "-- same order as the columns of EMP." - print - print "CREATE FUNCTION new_emp() RETURNS EMP" - print " AS 'SELECT \'None\'::text AS name," - print " 1000 AS salary," - print " 25 AS age," - print " \'none\'::varchar(16) AS dept'" - print " LANGUAGE 'sql'" - pgcnx.query("CREATE FUNCTION new_emp() RETURNS EMP " \ - "AS 'SELECT \\\'None\\\'::text AS name, " \ - "1000 AS salary, " \ - "25 AS age, " \ - "\\\'none\\\'::varchar(16) AS dept' " \ - "LANGUAGE 'sql'") - wait_key() - print - print "-- you can then project a column out of resulting the tuple by" - print "-- using the \"function notation\" for projection columns. " - print "-- (ie. bar(foo) is equivalent to foo.bar) Note that we don't" - print "-- support new_emp().name at this moment." - print - print "SELECT name(new_emp()) AS nobody" - print pgcnx.query("SELECT name(new_emp()) AS nobody") - print - print "-- let's try one more function that returns tuples" - print "CREATE FUNCTION high_pay() RETURNS setof EMP" - print " AS 'SELECT * FROM EMP where salary > 1500'" - print " LANGUAGE 'sql'" - pgcnx.query("CREATE FUNCTION high_pay() RETURNS setof EMP " \ - "AS 'SELECT * FROM EMP where salary > 1500' " \ - "LANGUAGE 'sql'") - print - print "SELECT name(high_pay()) AS overpaid" - print pgcnx.query("SELECT name(high_pay()) AS overpaid") - -# function with multiple SQL commands -def mult_func(pgcnx): - print "-----------------------------" - print "-- Creating SQL Functions with multiple SQL statements" - print "-- you can also create functions that do more than just a" - print "-- SELECT." - print "-----------------------------" - print - print "-- you may have noticed that Andy has a negative salary. We'll" - print "-- create a function that removes employees with negative " - print "-- salaries." - print - print "SELECT * FROM EMP" - print pgcnx.query("SELECT * FROM EMP") - print - print "CREATE FUNCTION clean_EMP () RETURNS int4" - print " AS 'DELETE FROM EMP WHERE EMP.salary <= 0" - print " SELECT 1 AS ignore_this'" - print " LANGUAGE 'sql'" - pgcnx.query("CREATE FUNCTION clean_EMP () RETURNS int4 AS 'DELETE FROM EMP WHERE EMP.salary <= 0; SELECT 1 AS ignore_this' LANGUAGE 'sql'") - print - print "SELECT clean_EMP()" - print pgcnx.query("SELECT clean_EMP()") - print - print "SELECT * FROM EMP" - print pgcnx.query("SELECT * FROM EMP") - -# base cleanup -def demo_cleanup(pgcnx): - print "-- remove functions that were created in this file" - print - print "DROP FUNCTION clean_EMP()" - print "DROP FUNCTION high_pay()" - print "DROP FUNCTION new_emp()" - print "DROP FUNCTION add_em(int4, int4)" - print "DROP FUNCTION one()" - print - print "DROP TABLE EMP" - pgcnx.query("DROP FUNCTION clean_EMP()") - pgcnx.query("DROP FUNCTION high_pay()") - pgcnx.query("DROP FUNCTION new_emp()") - pgcnx.query("DROP FUNCTION add_em(int4, int4)") - pgcnx.query("DROP FUNCTION one()") - pgcnx.query("DROP TABLE EMP") - -# main demo function -def demo(pgcnx): - base_func(pgcnx) - comp_func(pgcnx) - mult_func(pgcnx) - demo_cleanup(pgcnx) diff --git a/src/interfaces/python/tutorial/pgtools.py b/src/interfaces/python/tutorial/pgtools.py deleted file mode 100755 index 5355c584d7..0000000000 --- a/src/interfaces/python/tutorial/pgtools.py +++ /dev/null @@ -1,48 +0,0 @@ -#! /usr/local/bin/python -# pgtools.py - valuable functions for PostGreSQL tutorial -# written 1995 by Pascal ANDRE - -import sys - -# number of rows -scr_size = 24 - -# waits for a key -def wait_key(): - print "Press " - sys.stdin.read(1) - -# displays a table for a select query result -def display(fields, result): - print result - # gets cols width - fmt = [] - sep = '+' - head = '|' - for i in range(0, len(fields)): - max = len(fields[i]) - for j in range(0, len(result)): - if i < len(result[j]): - if len(result[j][i]) > max: - max = len(result[j][i]) - fmt.append(" %%%ds |" % max) - for j in range(0, max): - sep = sep + '-' - sep = sep + '--+' - for i in range(0, len(fields)): - head = head + fmt[i] % fields[i] - print sep + '\n' + head + '\n' + sep - pos = 6 - for i in range(0, len(result)): - str = '|' - for j in range(0, len(result[i])): - str = str + fmt[j] % result[i][j] - print str - pos = pos + 1 - if pos == scr_size: - print sep - wait_key() - print sep + '\n' + head + '\n' + sep - pos = 6 - print sep - wait_key() diff --git a/src/interfaces/python/tutorial/syscat.py b/src/interfaces/python/tutorial/syscat.py deleted file mode 100755 index 79b27ee77c..0000000000 --- a/src/interfaces/python/tutorial/syscat.py +++ /dev/null @@ -1,133 +0,0 @@ -# syscat.py - parses some system catalogs -# inspired from the PostgreSQL tutorial -# adapted to Python 1995 by Pascal ANDRE - -print "____________________________________________________________________" -print -print "MODULE SYSCAT.PY : PARSES SOME POSTGRESQL SYSTEM CATALOGS" -print -print "This module is designed for being imported from python prompt" -print -print "In order to run the samples included here, first create a connection" -print "using : cnx = syscat.DB(...)" -print "then start the demo with: syscat.demo(cnx)" -print -print "Some results may be empty, depending on your base status." -print -print "____________________________________________________________________" -print - -from pg import DB -from pgtools import * - -# lists all simple indices -def list_simple_ind(pgcnx): - result = pgcnx.query("select bc.relname " \ - "as class_name, ic.relname as index_name, a.attname " \ - "from pg_class bc, pg_class ic, pg_index i, pg_attribute a " \ - "where i.indrelid = bc.oid and i.indexrelid = bc.oid " \ - " and i.indkey[0] = a.attnum and a.attrelid = bc.oid " \ - " and i.indproc = '0'::oid " \ - "order by class_name, index_name, attname") - return result - -# list all user defined attributes and their type in user-defined classes -def list_all_attr(pgcnx): - result = pgcnx.query("select c.relname, a.attname, t.typname " \ - "from pg_class c, pg_attribute a, pg_type t " \ - "where c.relkind = 'r' and c.relname !~ '^pg_' " \ - " and c.relname !~ '^Inv' and a.attnum > 0 " \ - " and a.attrelid = c.oid and a.atttypid = t.oid " \ - "order by relname, attname") - return result - -# list all user defined base type -def list_user_base_type(pgcnx): - result = pgcnx.query("select u.usename, t.typname " \ - "from pg_type t, pg_user u " \ - "where u.usesysid = int2in(int4out(t.typowner)) " \ - " and t.typrelid = '0'::oid and t.typelem = '0'::oid " \ - " and u.usename <> 'postgres' order by usename, typname") - return result - -# list all right-unary operators -def list_right_unary_operator(pgcnx): - result = pgcnx.query("select o.oprname as right_unary, " \ - " lt.typname as operand, result.typname as return_type " \ - "from pg_operator o, pg_type lt, pg_type result " \ - "where o.oprkind='r' and o.oprleft = lt.oid " \ - " and o.oprresult = result.oid order by operand") - return result - -# list all left-unary operators -def list_left_unary_operator(pgcnx): - result = pgcnx.query("select o.oprname as left_unary, " \ - " rt.typname as operand, result.typname as return_type " \ - "from pg_operator o, pg_type rt, pg_type result " \ - "where o.oprkind='l' and o.oprright = rt.oid " \ - " and o.oprresult = result.oid order by operand") - return result - -# list all binary operators -def list_binary_operator(pgcnx): - result = pgcnx.query("select o.oprname as binary_op, " \ - " rt.typname as right_opr, lt.typname as left_opr, " \ - " result.typname as return_type " \ - "from pg_operator o, pg_type rt, pg_type lt, pg_type result " \ - "where o.oprkind = 'b' and o.oprright = rt.oid " \ - " and o.oprleft = lt.oid and o.oprresult = result.oid") - return result - -# returns the name, args and return type from all function of lang l -def list_lang_func(pgcnx, l): - result = pgcnx.query("select p.proname, p.pronargs, t.typname " \ - "from pg_proc p, pg_language l, pg_type t " \ - "where p.prolang = l.oid and p.prorettype = t.oid " \ - " and l.lanname = '%s' order by proname" % l) - return result - -# lists all the aggregate functions and the type to which they can be applied -def list_agg_func(pgcnx): - result = pgcnx.query("select a.aggname, t.typname " \ - "from pg_aggregate a, pg_type t " \ - "where a.aggbasetype = t.oid order by aggname, typname") - return result - -# lists all the operator classes that can be used with each access method as -# well as the operators that can be used with the respective operator classes -def list_op_class(pgcnx): - result = pgcnx.query("select am.amname, opc.opcname, opr.oprname " \ - "from pg_am am, pg_amop amop, pg_opclass opc, pg_operator opr " \ - "where amop.amopid = am.oid and amop.amopclaid = opc.oid " \ - " and amop.amopopr = opr.oid order by amname, opcname, oprname") - return result - -# demo function - runs all examples -def demo(pgcnx): - #import sys, os - #save_stdout = sys.stdout - #sys.stdout = os.popen("more", "w") - print "Listing simple indices ..." - print list_simple_ind(pgcnx) - print "Listing all attributes ..." - print list_all_attr(pgcnx) - print "Listing all user-defined base types ..." - print list_user_base_type(pgcnx) - print "Listing all left-unary operators defined ..." - print list_left_unary_operator(pgcnx) - print "Listing all right-unary operators defined ..." - print list_right_unary_operator(pgcnx) - print "Listing all binary operators ..." - print list_binary_operator(pgcnx) - print "Listing C external function linked ..." - print list_lang_func(pgcnx, 'C') - print "Listing C internal functions ..." - print list_lang_func(pgcnx, 'internal') - print "Listing SQL functions defined ..." - print list_lang_func(pgcnx, 'sql') - print "Listing 'aggregate functions' ..." - print list_agg_func(pgcnx) - print "Listing 'operator classes' ..." - print list_op_class(pgcnx) - #del sys.stdout - #sys.stdout = save_stdout