mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-17 19:30:00 +08:00
Update for PyGreSQL 3.0, from D'Arcy J.M. Cain
This commit is contained in:
parent
0bd84442f5
commit
f36e7ff092
2
doc/TODO
2
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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
57
src/interfaces/python/PyGreSQL.spec
Normal file
57
src/interfaces/python/PyGreSQL.spec
Normal file
@ -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 <hartmut@goebel.noris.de>
|
||||
Vendor: D'Arcy J.M. Cain <darcy@druid.net>
|
||||
URL: http://www.druid.net/pygresql/
|
||||
|
||||
%changelog
|
||||
#* Tue Oct 06 1998 Fabio Coatti <cova@felix.unife.it>
|
||||
#- 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}
|
@ -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<BR>
|
||||
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.
|
||||
|
||||
|
||||
|
@ -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 <hartmut@goebel.noris.de>
|
||||
|
||||
|
||||
INSTALLING PyGreSQL on Redhat Linux 5.1 or 5.2
|
||||
==============================================
|
||||
|
@ -1,4 +1,4 @@
|
||||
#! /usr/local/bin/python
|
||||
#! /usr/bin/env python
|
||||
|
||||
import string
|
||||
|
||||
|
@ -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<BR>"
|
||||
@ -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] = ""
|
||||
|
||||
|
401
src/interfaces/python/pgdb.py
Normal file
401
src/interfaces/python/pgdb.py
Normal file
@ -0,0 +1,401 @@
|
||||
""" pgdb - DB-SIG compliant module for PygreSQL.
|
||||
|
||||
(c) 1999, Pascal Andre <andre@via.ecp.fr>.
|
||||
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])
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 )
|
||||
|
43
src/interfaces/python/setup.py
Executable file
43
src/interfaces/python/setup.py
Executable file
@ -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 <mwa@gate.net>
|
||||
# tweaked 2000/05 Jeremy Hylton <jeremy@cnri.reston.va.us>
|
||||
|
||||
# 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
|
||||
}
|
||||
)]
|
||||
)
|
||||
|
@ -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)
|
@ -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)
|
@ -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)
|
@ -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 <enter>"
|
||||
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()
|
@ -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
|
Loading…
Reference in New Issue
Block a user