From: Bruce Momjian Date: Fri, 10 Nov 2000 22:29:21 +0000 (+0000) Subject: Update to PyGreSQL 3.1: X-Git-Tag: REL7_1_BETA~205 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eafb63643538000b3523478c3b2e51bd4611abbe;p=postgresql 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 --- diff --git a/src/interfaces/python/Announce b/src/interfaces/python/Announce index b02f83670b..20a4bb2668 100644 --- a/src/interfaces/python/Announce +++ b/src/interfaces/python/Announce @@ -1,8 +1,8 @@ -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 you are running NetBSD, look in the packages directory under databases. 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 embeds the PostgreSQL query library to allow easy use of the powerful PostgreSQL features from a Python script. -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. +This release fixes a few bugs, adds a few minor features and makes a +few speedups in the code. -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. +The next release (unless serious bugs are found) will be to match PyGreSQL +to version 2.0 of Python. 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 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. +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: - Remove strlen() call from pglarge_write() and get size from object. diff --git a/src/interfaces/python/ChangeLog b/src/interfaces/python/ChangeLog index 84f3fb78b1..ac4770bbf9 100644 --- a/src/interfaces/python/ChangeLog +++ b/src/interfaces/python/ChangeLog @@ -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) 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 - Remove strlen() call from pglarge_write() and get size from object. (Richard@Bouska.cz) diff --git a/src/interfaces/python/README b/src/interfaces/python/README index c53a22b5cd..0637d8827c 100644 --- a/src/interfaces/python/README +++ b/src/interfaces/python/README @@ -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 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. You have two options. You can compile PyGreSQL as a stand-alone module @@ -114,7 +117,7 @@ GENERAL 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 + cc -fpic -shared -o _pg.so -I[pyInc] -I[pgInc] -L[pgLib] -lpq pgmodule.c where: [pyInc] = path of the Python include (usually Python.h) [pgInc] = path of the PostgreSQL include (usually postgres.h) @@ -126,6 +129,9 @@ STAND-ALONE -DNO_SNPRINTF - if running a system with no snprintf call -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 that does not have the PQsocket function. The other options will be described in the next sections. @@ -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 fetch method should use real cursers. + 6. Future directions ==================== diff --git a/src/interfaces/python/README.linux b/src/interfaces/python/README.linux index 3b98077089..66b0346c82 100644 --- a/src/interfaces/python/README.linux +++ b/src/interfaces/python/README.linux @@ -1,4 +1,4 @@ -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. 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 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. + diff --git a/src/interfaces/python/pg.py b/src/interfaces/python/pg.py index d840c64a7b..a3e0bfc9b0 100644 --- a/src/interfaces/python/pg.py +++ b/src/interfaces/python/pg.py @@ -13,21 +13,30 @@ def _quote(d, t): if d == None: return "NULL" - if t in ['int', 'decimal', 'seq']: - if d == "": return 0 + if t in ['int', 'seq']: + if d == "": return "NULL" return "%d" % int(d) + if t == 'decimal': + if d == "": return "NULL" + return "%f" % float(d) + if t == 'money': - if d == "": return '0.00' + if d == "": return "NULL" return "'%.2f'" % float(d) 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'" else: 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("'", "''", \ re.sub("\\\\", "\\\\\\\\", "%s" %d))) @@ -68,7 +77,11 @@ class DB: print self.debug % 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 return self.__pkeys__[cl] @@ -115,6 +128,8 @@ class DB: l[attname] = 'date' elif re.match("^date", typname): l[attname] = 'date' + elif re.match("^timestamp", typname): + l[attname] = 'date' elif re.match("^bool", typname): l[attname] = 'bool' elif re.match("^float", typname): @@ -129,15 +144,20 @@ class DB: # return a tuple from a database 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 - keyname = self.__pkeys__[cl] + keyname = self.__pkeys__[xcl] - fnames = self.get_attnames(cl) + fnames = self.get_attnames(xcl) if type(arg) == type({}): # To allow users to work with multiple tables we munge the # 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 @@ -151,7 +171,7 @@ class DB: (cl, keyname, _quote(k, fnames[keyname])) else: 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])) if self.debug != None: print self.debug % q @@ -175,8 +195,7 @@ class DB: n = [] for f in fnames.keys(): if a.has_key(f): - if a[f] == "": l.append("null") - else: l.append(_quote(a[f], fnames[f])) + l.append(_quote(a[f], fnames[f])) n.append(f) try: @@ -197,44 +216,37 @@ class DB: # otherwise use the primary key. Fail if neither. def update(self, cl, a): foid = 'oid_%s' % cl - pk = self.__pkeys__[cl] if a.has_key(foid): where = "oid = %s" % a[foid] - elif a.has_key(pk): - where = "%s = '%s'" % (pk, a[pk]) + elif self.__pkeys__.has_key(cl) and a.has_key(self.__pkeys__[cl]): + where = "%s = '%s'" % (self.__pkeys__[cl], a[self.__pkeys__[cl]]) else: - raise error, "Update needs key (%s) or oid as %s" % (pk, 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] + raise error, "Update needs primary key or oid as %s" % foid v = [] k = 0 fnames = self.get_attnames(cl) 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]))) if v == []: return None try: - q = "UPDATE %s SET %s WHERE oid = %s" % \ - (cl, string.join(v, ','), a[foid]) + q = "UPDATE %s SET %s WHERE %s" % \ + (cl, string.join(v, ','), where) if self.debug != None: print self.debug % q self.db.query(q) except: raise error, "Can't update %s: %s" % (cl, sys.exc_value) # 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 def clear(self, cl, a = {}): diff --git a/src/interfaces/python/pgdb.py b/src/interfaces/python/pgdb.py index f5859713f0..28eab3d4ad 100644 --- a/src/interfaces/python/pgdb.py +++ b/src/interfaces/python/pgdb.py @@ -120,6 +120,8 @@ class pgdbTypeCache: pass elif typ == BINARY: pass + elif typ == BOOL: + value = (value[:1] in ['t','T']) elif typ == INTEGER: value = int(value) elif typ == LONG: @@ -322,7 +324,7 @@ def connect(dsn = None, user = None, password = None, host = None, database = No try: params = string.split(host, ":") dbhost = params[0] - dbport = params[1] + dbport = int(params[1]) except: pass diff --git a/src/interfaces/python/pgmodule.c b/src/interfaces/python/pgmodule.c index 09e94b8361..d51f8c7b04 100644 --- a/src/interfaces/python/pgmodule.c +++ b/src/interfaces/python/pgmodule.c @@ -44,7 +44,7 @@ #define CASHOID 790 static PyObject *PGError; -static const char *PyPgVersion = "3.0"; +static const char *PyPgVersion = "3.1"; /* taken from fileobject.c */ #define BUF(v) PyString_AS_STRING((PyStringObject *)(v)) @@ -1502,7 +1502,7 @@ pgconnect(pgobject *self, PyObject *args, PyObject *dict) if (pgport != -1) { - bzero(port_buffer, sizeof(port_buffer)); + memset(port_buffer, 0, sizeof(port_buffer)); sprintf(port_buffer, "%d", pgport); npgobj->cnx = PQsetdbLogin(pghost, port_buffer, pgopt, pgtty, pgdbname, pguser, pgpasswd); @@ -2976,8 +2976,7 @@ pgsetdefpasswd(PyObject * self, PyObject *args) 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; } diff --git a/src/interfaces/python/setup.py b/src/interfaces/python/setup.py index c128e6e799..76c6cd1101 100755 --- a/src/interfaces/python/setup.py +++ b/src/interfaces/python/setup.py @@ -24,7 +24,7 @@ optional_libs=['pq'] from distutils.core import setup setup (name = "PyGreSQL", - version = "3.0", + version = "3.1", description = "Python PostgreSQL Interfaces", author = "D'Arcy J. M. Cain", author_email = "darcy@druid.net", diff --git a/src/interfaces/python/tutorial/basics.py b/src/interfaces/python/tutorial/basics.py index 313258ba24..98a7f86a90 100755 --- a/src/interfaces/python/tutorial/basics.py +++ b/src/interfaces/python/tutorial/basics.py @@ -10,7 +10,7 @@ MODULE BASICS.PY : BASIC POSTGRES SQL COMMANDS TUTORIAL This module is designed for being imported from python prompt 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 existing database. Usually all you need is the name of the database and,