Commit eafb6364 authored by Bruce Momjian's avatar Bruce Momjian

Update to PyGreSQL 3.1:

Fix some quoting functions. In particular handle NULLs better.

Use a method to add primary key information rather than direct
manipulation of the class structures.

Break decimal out in _quote (in pg.py) and treat it as float.

Treat timestamp like date for quoting purposes.

Remove a redundant SELECT from the get method speeding it, and
insert since it calls get, up a little.

Add test for BOOL type in typecast method to pgdbTypeCache class.
(tv@beamnet.de)

Fix pgdb.py to send port as integer to lower level function
(dildog@l0pht.com)

Change pg.py to speed up some operations

Allow updates on tables with no primary keys.

D'Arcy J.M. Cain
parent 960c1861
Announce: Release of PyGreSQL version 3.0 Announce: Release of PyGreSQL version 3.1
=============================================== ===============================================
PyGreSQL v3.0 has been released. PyGreSQL v3.1 has been released.
It is available at: ftp://ftp.druid.net/pub/distrib/PyGreSQL.tgz. If It is available at: ftp://ftp.druid.net/pub/distrib/PyGreSQL.tgz. If
you are running NetBSD, look in the packages directory under databases. you are running NetBSD, look in the packages directory under databases.
There is also a package in the FreeBSD ports collection. There is also a package in the FreeBSD ports collection.
...@@ -25,16 +25,11 @@ PyGreSQL is a python module that interfaces to a PostgreSQL database. It ...@@ -25,16 +25,11 @@ PyGreSQL is a python module that interfaces to a PostgreSQL database. It
embeds the PostgreSQL query library to allow easy use of the powerful embeds the PostgreSQL query library to allow easy use of the powerful
PostgreSQL features from a Python script. PostgreSQL features from a Python script.
This release of PyGreSQL is the first DB-SIG API. That's why we have This release fixes a few bugs, adds a few minor features and makes a
a bump in the major number. There is also a potential problem in few speedups in the code.
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.
Due to the fact that the DB-API is brand new, it is expected that there The next release (unless serious bugs are found) will be to match PyGreSQL
will be a 3.1 release shortly with corrections once many people have to version 2.0 of Python.
had a chance to test it.
See the other changes below or in the Changelog file. See the other changes below or in the Changelog file.
...@@ -44,7 +39,22 @@ andre@chimay.via.ecp.fr. I changed the version to 2.0 and updated the ...@@ -44,7 +39,22 @@ 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 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 the code to use full ANSI style prototypes and changed the order of
arguments to connect. Later versions are fixes and enhancements to that. 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. The latest version of PyGreSQL works with Python 1.5.2 and PostgreSQL 7.0.x
Important changes from PyGreSQL 3.0 to PyGreSQL 3.1
- Fix some quoting functions. In particular handle NULLs better.
- Use a method to add primary key information rather than direct
manipulation of the class structures.
- Break decimal out in _quote (in pg.py) and treat it as float.
- Treat timestamp like date for quoting purposes.
- Remove a redundant SELECT from the get method speeding it, and insert
since it calls get, up a little.
- Add test for BOOL type in typecast method to pgdbTypeCache class.
(tv@beamnet.de)
- Fix pgdb.py to send port as integer to lower level function
(dildog@l0pht.com)
- Change pg.py to speed up some operations
- Allow updates on tables with no primary keys.
Important changes from PyGreSQL 2.4 to PyGreSQL 3.0: Important changes from PyGreSQL 2.4 to PyGreSQL 3.0:
- Remove strlen() call from pglarge_write() and get size from object. - Remove strlen() call from pglarge_write() and get size from object.
......
...@@ -5,6 +5,21 @@ This software is copyright (c) 1995, Pascal Andre (andre@via.ecp.fr) ...@@ -5,6 +5,21 @@ 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) Further copyright 1997, 1998 and 1999 by D'Arcy J.M. Cain (darcy@druid.net)
See file README for copyright information. See file README for copyright information.
Version 3.1
- Fix some quoting functions. In particular handle NULLs better.
- Use a method to add primary key information rather than direct
manipulation of the class structures.
- Break decimal out in _quote (in pg.py) and treat it as float.
- Treat timestamp like date for quoting purposes.
- Remove a redundant SELECT from the get method speeding it, and insert
since it calls get, up a little.
- Add test for BOOL type in typecast method to pgdbTypeCache class.
(tv@beamnet.de)
- Fix pgdb.py to send port as integer to lower level function
(dildog@l0pht.com)
- Change pg.py to speed up some operations
- Allow updates on tables with no primary keys.
Version 3.0 Version 3.0
- Remove strlen() call from pglarge_write() and get size from object. - Remove strlen() call from pglarge_write() and get size from object.
(Richard@Bouska.cz) (Richard@Bouska.cz)
......
...@@ -89,6 +89,9 @@ version of PyGreSQL works with PostgreSQL 6.5 and Python 1.5.2. ...@@ -89,6 +89,9 @@ version of PyGreSQL works with PostgreSQL 6.5 and Python 1.5.2.
that uses RPMs, then you can pick up an RPM at that uses RPMs, then you can pick up an RPM at
ftp://ftp.druid.net/pub/distrib/pygresql.i386.rpm ftp://ftp.druid.net/pub/distrib/pygresql.i386.rpm
* Note that if you are using the DB-API module you must also install
mxDateTime from http://starship.python.net/~lemburg/mxDateTime.html.
* Also, check out setup.py for an alternate method of installing the package. * 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 You have two options. You can compile PyGreSQL as a stand-alone module
...@@ -114,7 +117,7 @@ GENERAL ...@@ -114,7 +117,7 @@ GENERAL
STAND-ALONE STAND-ALONE
* In the directory containing pgmodule.c, run the following command * 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 cc -fpic -shared -o _pg.so -I[pyInc] -I[pgInc] -L[pgLib] -lpq pgmodule.c
where: where:
[pyInc] = path of the Python include (usually Python.h) [pyInc] = path of the Python include (usually Python.h)
[pgInc] = path of the PostgreSQL include (usually postgres.h) [pgInc] = path of the PostgreSQL include (usually postgres.h)
...@@ -126,6 +129,9 @@ STAND-ALONE ...@@ -126,6 +129,9 @@ STAND-ALONE
-DNO_SNPRINTF - if running a system with no snprintf call -DNO_SNPRINTF - if running a system with no snprintf call
-DNO_PQSOCKET - if running an older PostgreSQL -DNO_PQSOCKET - if running an older PostgreSQL
On some systems you may need to include -lcrypt in the list of libraries
to make it compile.
Define NO_PQSOCKET if you are using a version of PostgreSQL before 6.4 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 that does not have the PQsocket function. The other options will be
described in the next sections. described in the next sections.
...@@ -1050,6 +1056,8 @@ The C module needs to be cleaned up and redundant code merged. ...@@ -1050,6 +1056,8 @@ The C module needs to be cleaned up and redundant code merged.
The DB-API module needs to be documented. The DB-API module needs to be documented.
The fetch method should use real cursers.
6. Future directions 6. Future directions
==================== ====================
......
Thanks to thilo@eevolute.com for this README and the RPM Thanks to thilo@eevolute.com and others for this README and the RPM
Note: The precompiled RPM package is not available at www.eevolute.com. Note: The precompiled RPM package is not available at www.eevolute.com.
You may use the spec file provided with PyGreSQL to build your You may use the spec file provided with PyGreSQL to build your
...@@ -36,3 +36,11 @@ bash# cp _pg.so /usr/lib/python1.5/lib-dynload ...@@ -36,3 +36,11 @@ bash# cp _pg.so /usr/lib/python1.5/lib-dynload
done! done!
Oliver White (ojw@muzak.iinet.net.au) sent me the following information
about installing on Debian.
Hi, I thought you might want to upgrade your documentation for PyGreSQL
to let people know they can get it by simply typing 'apt-get install
python-pygresql', on debian (duh). This would have saved me a lot of
trouble.
...@@ -13,21 +13,30 @@ def _quote(d, t): ...@@ -13,21 +13,30 @@ def _quote(d, t):
if d == None: if d == None:
return "NULL" return "NULL"
if t in ['int', 'decimal', 'seq']: if t in ['int', 'seq']:
if d == "": return 0 if d == "": return "NULL"
return "%d" % int(d) return "%d" % int(d)
if t == 'decimal':
if d == "": return "NULL"
return "%f" % float(d)
if t == 'money': if t == 'money':
if d == "": return '0.00' if d == "": return "NULL"
return "'%.2f'" % float(d) return "'%.2f'" % float(d)
if t == 'bool': if t == 'bool':
if string.upper(d) in ['T', 'TRUE', 'Y', 'YES', 1, '1', 'ON']: # Can't run upper() on these
if d in (0, 1): return ('f', 't')[d]
if string.upper(d) in ['T', 'TRUE', 'Y', 'YES', '1', 'ON']:
return "'t'" return "'t'"
else: else:
return "'f'" return "'f'"
if d == "": return "null" if t == 'date' and d == '': return "NULL"
if t in ('inet', 'cidr') and d == '': return "NULL"
return "'%s'" % string.strip(re.sub("'", "''", \ return "'%s'" % string.strip(re.sub("'", "''", \
re.sub("\\\\", "\\\\\\\\", "%s" %d))) re.sub("\\\\", "\\\\\\\\", "%s" %d)))
...@@ -68,7 +77,11 @@ class DB: ...@@ -68,7 +77,11 @@ class DB:
print self.debug % qstr print self.debug % qstr
return self.db.query(qstr) return self.db.query(qstr)
def pkey(self, cl): # If third arg supplied set primary key to it
def pkey(self, cl, newpkey = None):
if newpkey:
self.__pkeys__[cl] = newpkey
# will raise an exception if primary key doesn't exist # will raise an exception if primary key doesn't exist
return self.__pkeys__[cl] return self.__pkeys__[cl]
...@@ -115,6 +128,8 @@ class DB: ...@@ -115,6 +128,8 @@ class DB:
l[attname] = 'date' l[attname] = 'date'
elif re.match("^date", typname): elif re.match("^date", typname):
l[attname] = 'date' l[attname] = 'date'
elif re.match("^timestamp", typname):
l[attname] = 'date'
elif re.match("^bool", typname): elif re.match("^bool", typname):
l[attname] = 'bool' l[attname] = 'bool'
elif re.match("^float", typname): elif re.match("^float", typname):
...@@ -129,15 +144,20 @@ class DB: ...@@ -129,15 +144,20 @@ class DB:
# return a tuple from a database # return a tuple from a database
def get(self, cl, arg, keyname = None, view = 0): def get(self, cl, arg, keyname = None, view = 0):
if cl[-1] == '*': # need parent table name
xcl = cl[:-1]
else:
xcl = cl
if keyname == None: # use the primary key by default if keyname == None: # use the primary key by default
keyname = self.__pkeys__[cl] keyname = self.__pkeys__[xcl]
fnames = self.get_attnames(cl) fnames = self.get_attnames(xcl)
if type(arg) == type({}): if type(arg) == type({}):
# To allow users to work with multiple tables we munge the # To allow users to work with multiple tables we munge the
# name when the key is "oid" # name when the key is "oid"
if keyname == 'oid': k = arg['oid_%s' % cl] if keyname == 'oid': k = arg['oid_%s' % xcl]
else: k = arg[keyname] else: k = arg[keyname]
else: else:
k = arg k = arg
...@@ -151,7 +171,7 @@ class DB: ...@@ -151,7 +171,7 @@ class DB:
(cl, keyname, _quote(k, fnames[keyname])) (cl, keyname, _quote(k, fnames[keyname]))
else: else:
q = "SELECT oid AS oid_%s, %s FROM %s WHERE %s = %s" % \ q = "SELECT oid AS oid_%s, %s FROM %s WHERE %s = %s" % \
(cl, string.join(fnames.keys(), ','),\ (xcl, string.join(fnames.keys(), ','),\
cl, keyname, _quote(k, fnames[keyname])) cl, keyname, _quote(k, fnames[keyname]))
if self.debug != None: print self.debug % q if self.debug != None: print self.debug % q
...@@ -175,8 +195,7 @@ class DB: ...@@ -175,8 +195,7 @@ class DB:
n = [] n = []
for f in fnames.keys(): for f in fnames.keys():
if a.has_key(f): if a.has_key(f):
if a[f] == "": l.append("null") l.append(_quote(a[f], fnames[f]))
else: l.append(_quote(a[f], fnames[f]))
n.append(f) n.append(f)
try: try:
...@@ -197,44 +216,37 @@ class DB: ...@@ -197,44 +216,37 @@ class DB:
# otherwise use the primary key. Fail if neither. # otherwise use the primary key. Fail if neither.
def update(self, cl, a): def update(self, cl, a):
foid = 'oid_%s' % cl foid = 'oid_%s' % cl
pk = self.__pkeys__[cl]
if a.has_key(foid): if a.has_key(foid):
where = "oid = %s" % a[foid] where = "oid = %s" % a[foid]
elif a.has_key(pk): elif self.__pkeys__.has_key(cl) and a.has_key(self.__pkeys__[cl]):
where = "%s = '%s'" % (pk, a[pk]) where = "%s = '%s'" % (self.__pkeys__[cl], a[self.__pkeys__[cl]])
else: else:
raise error, "Update needs key (%s) or oid as %s" % (pk, foid) raise error, "Update needs primary key or oid as %s" % foid
q = "SELECT oid FROM %s WHERE %s" % (cl, where)
if self.debug != None: print self.debug % q
res = self.db.query(q).getresult()
if len(res) < 1:
raise error, "No record in %s where %s (%s)" % \
(cl, where, sys.exc_value)
else: a[foid] = res[0][0]
v = [] v = []
k = 0 k = 0
fnames = self.get_attnames(cl) fnames = self.get_attnames(cl)
for ff in fnames.keys(): for ff in fnames.keys():
if a.has_key(ff) and a[ff] != res[0][k]: if a.has_key(ff):
v.append("%s = %s" % (ff, _quote(a[ff], fnames[ff]))) v.append("%s = %s" % (ff, _quote(a[ff], fnames[ff])))
if v == []: if v == []:
return None return None
try: try:
q = "UPDATE %s SET %s WHERE oid = %s" % \ q = "UPDATE %s SET %s WHERE %s" % \
(cl, string.join(v, ','), a[foid]) (cl, string.join(v, ','), where)
if self.debug != None: print self.debug % q if self.debug != None: print self.debug % q
self.db.query(q) self.db.query(q)
except: except:
raise error, "Can't update %s: %s" % (cl, sys.exc_value) raise error, "Can't update %s: %s" % (cl, sys.exc_value)
# reload the dictionary to catch things modified by engine # reload the dictionary to catch things modified by engine
return self.get(cl, a, 'oid') if a.has_key(foid):
return self.get(cl, a, 'oid')
else:
return self.get(cl, a)
# At some point we will need a way to get defaults from a table # At some point we will need a way to get defaults from a table
def clear(self, cl, a = {}): def clear(self, cl, a = {}):
......
...@@ -120,6 +120,8 @@ class pgdbTypeCache: ...@@ -120,6 +120,8 @@ class pgdbTypeCache:
pass pass
elif typ == BINARY: elif typ == BINARY:
pass pass
elif typ == BOOL:
value = (value[:1] in ['t','T'])
elif typ == INTEGER: elif typ == INTEGER:
value = int(value) value = int(value)
elif typ == LONG: elif typ == LONG:
...@@ -322,7 +324,7 @@ def connect(dsn = None, user = None, password = None, host = None, database = No ...@@ -322,7 +324,7 @@ def connect(dsn = None, user = None, password = None, host = None, database = No
try: try:
params = string.split(host, ":") params = string.split(host, ":")
dbhost = params[0] dbhost = params[0]
dbport = params[1] dbport = int(params[1])
except: except:
pass pass
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#define CASHOID 790 #define CASHOID 790
static PyObject *PGError; static PyObject *PGError;
static const char *PyPgVersion = "3.0"; static const char *PyPgVersion = "3.1";
/* taken from fileobject.c */ /* taken from fileobject.c */
#define BUF(v) PyString_AS_STRING((PyStringObject *)(v)) #define BUF(v) PyString_AS_STRING((PyStringObject *)(v))
...@@ -1502,7 +1502,7 @@ pgconnect(pgobject *self, PyObject *args, PyObject *dict) ...@@ -1502,7 +1502,7 @@ pgconnect(pgobject *self, PyObject *args, PyObject *dict)
if (pgport != -1) if (pgport != -1)
{ {
bzero(port_buffer, sizeof(port_buffer)); memset(port_buffer, 0, sizeof(port_buffer));
sprintf(port_buffer, "%d", pgport); sprintf(port_buffer, "%d", pgport);
npgobj->cnx = PQsetdbLogin(pghost, port_buffer, pgopt, pgtty, pgdbname, npgobj->cnx = PQsetdbLogin(pghost, port_buffer, pgopt, pgtty, pgdbname,
pguser, pgpasswd); pguser, pgpasswd);
...@@ -2976,8 +2976,7 @@ pgsetdefpasswd(PyObject * self, PyObject *args) ...@@ -2976,8 +2976,7 @@ pgsetdefpasswd(PyObject * self, PyObject *args)
if (!PyArg_ParseTuple(args, "z", &temp)) if (!PyArg_ParseTuple(args, "z", &temp))
{ {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"set_defpasswd(password), with password (string/ "set_defpasswd(password), with password (string/None).");
None).");
return NULL; return NULL;
} }
......
...@@ -24,7 +24,7 @@ optional_libs=['pq'] ...@@ -24,7 +24,7 @@ optional_libs=['pq']
from distutils.core import setup from distutils.core import setup
setup (name = "PyGreSQL", setup (name = "PyGreSQL",
version = "3.0", version = "3.1",
description = "Python PostgreSQL Interfaces", description = "Python PostgreSQL Interfaces",
author = "D'Arcy J. M. Cain", author = "D'Arcy J. M. Cain",
author_email = "darcy@druid.net", author_email = "darcy@druid.net",
......
...@@ -10,7 +10,7 @@ MODULE BASICS.PY : BASIC POSTGRES SQL COMMANDS TUTORIAL ...@@ -10,7 +10,7 @@ MODULE BASICS.PY : BASIC POSTGRES SQL COMMANDS TUTORIAL
This module is designed for being imported from python prompt This module is designed for being imported from python prompt
In order to run the samples included here, first create a connection In order to run the samples included here, first create a connection
using : cnx = advanced.DB(...) using : cnx = basics.DB(...)
The "..." should be replaced with whatever arguments you need to open an The "..." should be replaced with whatever arguments you need to open an
existing database. Usually all you need is the name of the database and, existing database. Usually all you need is the name of the database and,
......
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