Commit f36e7ff0 authored by Bruce Momjian's avatar Bruce Momjian

Update for PyGreSQL 3.0, from D'Arcy J.M. Cain

parent 0bd84442
......@@ -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)
......
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
......
%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}
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.
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:
[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 the PostgreSQL include
[pgLib] = path of the PostgreSQL libraries
[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.
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
==============================================
......
#! /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] = ""
......
""" 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])
......@@ -26,9 +26,9 @@
*
*/
#include "Python.h"
#include "libpq-fe.h"
#include "libpq/libpq-fs.h"
#include <Python.h>
#include <libpq-fe.h>
#include <libpq/libpq-fs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
......@@ -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 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; i<self->num_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", &param))
{
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", &param))
{
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 CONNECTION OBJECT IMPLEMENTATION */
/* 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)
{
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;
pgconnect(pgobject *self, PyObject *args, PyObject *dict)
{
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("<pg query result>");
}
/* 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("<unknown user>")); */
/* return PyString_FromString(fe_getauthname("<unknown user>")); */
/* 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())
......
# 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 )
#!/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
}
)]
)
#! /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)
#! /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)
# 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)
#! /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()
# 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment