Update to PyGreSQL 3.1:
authorBruce Momjian
Fri, 10 Nov 2000 22:29:21 +0000 (22:29 +0000)
committerBruce Momjian
Fri, 10 Nov 2000 22:29:21 +0000 (22:29 +0000)
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.
([email protected])

Fix pgdb.py to send port as integer to lower level function
([email protected])

Change pg.py to speed up some operations

Allow updates on tables with no primary keys.

D'Arcy J.M. Cain

src/interfaces/python/Announce
src/interfaces/python/ChangeLog
src/interfaces/python/README
src/interfaces/python/README.linux
src/interfaces/python/pg.py
src/interfaces/python/pgdb.py
src/interfaces/python/pgmodule.c
src/interfaces/python/setup.py
src/interfaces/python/tutorial/basics.py

index b02f83670bf9545ad4d0c341b770c0531485af22..20a4bb2668a69854e0410c91112a8d63b9053886 100644 (file)
@@ -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 @@ [email protected].  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.
+  - Fix pgdb.py to send port as integer to lower level function
+  - 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.
index 84f3fb78b11561cc0b4bc3ba9a26b6d8f5e2a001..ac4770bbf93d7079c39591020ac3e0b3d63314a2 100644 (file)
@@ -5,6 +5,21 @@ This software is copyright (c) 1995, Pascal Andre ([email protected])
 Further copyright 1997, 1998 and 1999 by D'Arcy J.M. Cain ([email protected])
 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.
+  - Fix pgdb.py to send port as integer to lower level function
+  - 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.
     ([email protected])
index c53a22b5cda5ba400ef5fd2c6a927b0c6cb39c31..0637d8827cdb34166f34f0bfabcf4acbe7a8018f 100644 (file)
@@ -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
 ====================
index 3b98077089f6a82fda2c965d92fc0f75506a8ec9..66b0346c8266990eebb6255298304d84e5ae71c4 100644 (file)
@@ -1,4 +1,4 @@
-Thanks to [email protected] for this README and the RPM
+Thanks to [email protected] 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 ([email protected]) 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.
+
index d840c64a7b2d22057587f5e42c0c8ebdfe75c1f1..a3e0bfc9b02e8fc37c9e2ae8b4dfb7d85e61a55d 100644 (file)
@@ -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 = {}):
index f5859713f032d3a3a39882ba606f703f6498f090..28eab3d4ada8466bab56ff78a3e77a6f35f21034 100644 (file)
@@ -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
 
index 09e94b836196e2fc67f74318d5b5e0a26f87add6..d51f8c7b040ca8263c90b2b0fcb3adcfc90929ac 100644 (file)
@@ -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;
    }
 
index c128e6e7997ef91369d1a9947260d00f9720113a..76c6cd1101f4f3ebe51e6f4d4b276ccc4be2fdde 100755 (executable)
@@ -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 = "[email protected]",
index 313258ba24e3a13c044bf3b2cc790ef1ef364b29..98a7f86a90be91bfe04f9117d91b8090adcc5f70 100755 (executable)
@@ -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,