[Zope3-checkins] CVS: zopeproducts/pypgsqlda - INSTALL.txt:1.1.2.1 README.txt:1.1.2.1 TODO.txt:1.1.2.1 __init__.py:1.1.1.1.2.1 adapter.py:1.6.2.2 configure.zcml:1.1.1.1.2.1 TODO:NONE geometric.py:NONE

Christian 'Tiran' Heimes heimes@faho.rwth-aachen.de
Mon, 7 Apr 2003 12:17:32 -0400


Update of /cvs-repository/zopeproducts/pypgsqlda
In directory cvs.zope.org:/tmp/cvs-serv6268

Modified Files:
      Tag: tiran-pypgsql_types-branch
	__init__.py adapter.py configure.zcml 
Added Files:
      Tag: tiran-pypgsql_types-branch
	INSTALL.txt README.txt TODO.txt 
Removed Files:
      Tag: tiran-pypgsql_types-branch
	TODO geometric.py 
Log Message:
* changed directory structure
* changed converter to curry class
* added first release of geometric types
* added NULL type
* added some text files

=== Added File zopeproducts/pypgsqlda/INSTALL.txt ===
=========================
Installation of pyPgSQLDA
=========================

Requirements
------------

 * pypgsqlda 2.3 http://pypgsql.sourceforge.net
 * Postgres 7.x
 * Zope3
 
Conventions
-----------

'ZOPE_HOME'
  Your Zope3 root directory
  
'$ cmd'
  A command typed and executed in a shell (assuming bash on a linux box)
 
Installation of the package
---------------------------

1. checkout the newest version of pyPgSQLDA from the zope.org cvs repository
 
  * change into your local 'ZOPE_HOME' directory.
  * create a directory 'zopeproducts'.
  * change into 'zopeprocuts'.
  * create an empty '__init__.py' file. This will transform 'zopeproducts' to a python package
  * '$ cvs -d :pserver:anonymous@cvs.zope.org:/cvs-repository login' (empty password)
  * '$ cvs -z7 -d :pserver:anonymous@cvs.zope.org:/cvs-repository checkout zopeproducts/pypgsqlda'
  
  **Note:** You should use '$ cvs -q up -P -d' in the 
  'ZOPE_HOME/zopeproducts/pypgsqlda' directory to stick to the newest version
  if you already have pyPgSQLDA installed.
  
  Note: You can also check out the whole zopeproducts tree to 'ZOPE_HOME/zopeproducts'
  and stay tuned by simple cvs up in the 'ZOPE_HOME'

2. Add the following line to your 'ZOPE_HOME/products.zcml' configuration file::

    <include package='zopeproducts.pypgsqlda' /> 
    
3. Start Zope3

Adding a SQL connection to Zope 3
---------------------------------

To use an external rdb you must add a sql connection service and a database
adapter and a connection for each database you want to access.

 1. Browse to your zope3 webserver

 2. Click on 'Manage Local Services' in the upper right corner

 3. 'Visit default package'

 4. 'Add'

 5. Choose 'Service' and click on the 'Add' button

 6. Add a 'SQL Connection Service'. You can type a name in the textbox next
    to the addd button (e.g. SQLConnService).

 7. Make shure that 'Configure' and 'Activate' is checked and submit the form

 8. Now browse back to the default package and click on 'Add' again

 9. Add a 'pypgsql DA' database adapter. Again you can pick up a name, for
    example the database name.

10. Next you have to type a connection uri (also called a dsn). Currently you
    have to give a full uri with all option. In most cases it will look like::
    
    dbi://myuser:mypassword@localhost:5432/mydb
    
    **Note:** You must start the Postgres postmaster with the '-i' option to
    enable tcp conncetions. See postmaster(1) manual for more informations.
    
11. You can validate the connction by browsing to the database adapter and 
    clicking on 'Connect'. If the button changes to 'Disconnect' everything
    is just fine, if not consult the debug log of zope.
    
12. Now it's time to connect the database adapter and the sql connection
    service. Browse to the 'Configuration Manager' in the default package
     and click on 'Add'. 

13. Add a 'Connection'.

14. Type in a name (e.g. mydbConn), change the status to 'Active' and pick up
    the database adapter in the 'Component Path' dropdown field.

That's it. :)   
-= EOF =-

=== Added File zopeproducts/pypgsqlda/README.txt ===
deprecated types
-------------------

    'abstime'   : '',
    'money'     : 'numeric',
    'reltime'   : '',
    'tinverval' : 'interval',


                                       List of data types
            Name             |                            Description
-----------------------------+-------------------------------------------------------------------
 "SET"                       | set of tuples
 "char"                      | single character
 abstime                     | absolute, limited-range date and time (Unix system time)
 aclitem                     | access control list
 bigint                      | ~18 digit integer, 8-byte storage
 bit                         | fixed-length bit string
 bit varying                 | variable-length bit string
 boolean                     | boolean, 'true'/'false'
 box                         | geometric box '(lower left,upper right)'
 bytea                       | variable-length string, binary values escaped
 character                   | char(length), blank-padded string, fixed storage length
 character varying           | varchar(length), non-blank-padded string, variable storage length
 cid                         | command identifier type, sequence in transaction id
 cidr                        | network IP address/netmask, network address
 circle                      | geometric circle '(center,radius)'
 date                        | ANSI SQL date
 double precision            | double-precision floating point number, 8-byte storage
 inet                        | IP address/netmask, host address, netmask optional
 int2vector                  | array of 16 int2 integers, used in system tables
 integer                     | -2 billion to 2 billion integer, 4-byte storage
 interval                    | @ <number> <units>, time interval
 line                        | geometric line '(pt1,pt2)'
 lseg                        | geometric line segment '(pt1,pt2)'
 macaddr                     | XX:XX:XX:XX:XX:XX, MAC address
 money                       | $d,ddd.cc, money
 name                        | 31-character type for storing system identifiers
 numeric                     | numeric(precision, decimal), arbitrary precision number
 oid                         | object identifier(oid), maximum 4 billion
 oidvector                   | array of 16 oids, used in system tables
 path                        | geometric path '(pt1,...)'
 point                       | geometric point '(x, y)'
 polygon                     | geometric polygon '(pt1,...)'
 real                        | single-precision floating point number, 4-byte storage
 refcursor                   | reference cursor (portal name)
 regproc                     | registered procedure
 reltime                     | relative, limited-range time interval (Unix delta time)
 smallint                    | -32 thousand to 32 thousand, 2-byte storage
 smgr                        | storage manager
 text                        | variable-length string, no limit specified
 tid                         | (Block, offset), physical location of tuple
 time with time zone         | hh:mm:ss, ANSI SQL time
 time without time zone      | hh:mm:ss, ANSI SQL time
 timestamp with time zone    | date and time with time zone
 timestamp without time zone | date and time
 tinterval                   | (abstime,abstime), time interval
 unknown                     |
 xid                         | transaction id


=== Added File zopeproducts/pypgsqlda/TODO.txt ===
* support for postgres arrays
* testing, testing, testing
* documentation


Bugs in pypgsql
******************

no typechar for timetz
http://sourceforge.net/tracker/index.php?func=detail&aid=708013&group_id=16528&atid=316528

interval does not support intervals longer then a few days:
http://sourceforge.net/tracker/index.php?func=detail&aid=708002&group_id=16528&atid=116528

=== zopeproducts/pypgsqlda/__init__.py 1.1.1.1 => 1.1.1.1.2.1 ===
--- zopeproducts/pypgsqlda/__init__.py:1.1.1.1	Mon Mar 17 12:17:18 2003
+++ zopeproducts/pypgsqlda/__init__.py	Mon Apr  7 12:17:31 2003
@@ -1,2 +1,17 @@
-# make this a python package
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+"""PostgreSQL Database Adapter for Zope 3 using pyPgSQL >= 2.3
 
+$Id$
+"""


=== zopeproducts/pypgsqlda/adapter.py 1.6.2.1 => 1.6.2.2 ===
--- zopeproducts/pypgsqlda/adapter.py:1.6.2.1	Fri Mar 21 17:21:31 2003
+++ zopeproducts/pypgsqlda/adapter.py	Mon Apr  7 12:17:31 2003
@@ -16,16 +16,15 @@
 $Id$
 """
 
-from pyPgSQL import PgSQL
-
 from zope.app.rdb import ZopeDatabaseAdapter, parseDSN, identity
+from pyPgSQL import PgSQL
+from pyPgSQL.PgSQL import PgArray
 
-from geometric import Point2d
+import pgtypes
 
 import string
-
-import datetime
 from zope.app import datetimeutils
+import datetime
 
 
 class pypgsqlAdapter(ZopeDatabaseAdapter):
@@ -53,15 +52,42 @@
                             
     def getConverter(self, typechar):
         if converter_mapping.has_key(str(typechar)):
-            return converter_mapping[str(typechar)]
+            return Converter(converter_mapping[str(typechar)])
         else:
-            return identity
+            # XXX: I don't know how to handle this, so convert it to a
+            # unicode string or a (nested) list of unicode string if it's
+            # a PgArray
+            return Converter(convertUnicode)
 
 # helpers
 
-def _isPgArray(data):
-    """Check if data is a postgres array"""   
-    return isinstance(data, PgArray)
+NULL = pgtypes.Null()
+
+class Converter(object):
+    """
+    """
+    def __init__(self, cfun):
+        self.cfun = cfun
+        
+    def isPgArray(self, data):
+        """Check if data is a postgres array"""   
+        return isinstance(data, PgArray)
+
+    def convertArray(self, data):
+        """Converts postgres arrays
+        
+        FYI: postgres arrays are homogen and could be nested
+        """
+        return map(self.__class__(self.cfun), data)
+        
+    def __call__(self, data):
+        if not data: return NULL
+        if self.isPgArray(data): return self.convertArray(data)
+        retval = self.cfun(data)
+        #import pdb;
+        #pdb.set_trace()
+        return retval
+        
 
 def _sec2my(sec):
     """ Return second and mikro for a float second"""
@@ -72,141 +98,86 @@
 
 # Converters
 
-def convertINet(data):
-    """Converts inet and cidr to an nested tuple
-    
-    Return a nested tuple of the form (hostaddress, netmask) where
-    hostaddress itself is a tuple of ints and netmask is an int.
-    
-    FYI: cidr and inet can handle only ipv4 (12 bytes)
-    
-    XXX: make this a special type
-    """
-    addr = unicode(data).split('/')
-    if len(addr) == 2:
-        addr[1] = string.atoi(addr[1])
-    else:
-        addr.append(32)
-    return (tuple([string.atoi(a) for a in addr[0].split('.')]), addr[1])
+ 
+# *********************************
+# ***   byte and string types   ***
+# *********************************
  
 def convertBool(data):
-    """Returns a boolean as normal python boolean."""
-    return not not data
-
-def convertSmallInt(data):
-    """Converts a string containing a small int (int2) to int"""
-    return string.atoi(unicode(data))    
-
-
-class GeometricError(Exception): pass
-
-import re
-# matching an open path e.g. [(0,0),(1,1)]
-isOpenPath = re.compile(r"^\[\(.*\)\]$")
-
-# matching a closed path e.g. ((0,0),(1,1))
-isClosedPath = re.compile(r"^\(\(.*\)\)$")
-
-# group a circle e.g. <(1,1),0.5> into (1.0,1.0) as the middle point
-# and 0.5 as the radius
-groupCircle = re.compile(r"^<(\([\d.]+,[\d.]+\)),([\d.]+)>$")
-
-# group a single point e.g. (0,1) into 0 as the x value and 1 as the y value
-groupPoint = re.compile(r"^\(([\d.]+),([\d.]+)\)$")
-
-# group a path or a box e.g.((0,0),(1,1)) or [(0,0),(1,1)] into a 
-# list of points
-groupPointList = re.compile(r"(\([\d.]+,[\d.]+\))")
-
-def convertPoint(data):
-    """Returns tuple (x,y) coordinate of floats
+    """Returns a boolean as an ordenary python boolean.
     
-    XXX: make this a special type
+    XXX postgres NULL is neither True nor False ... how to handle this?
     """
-    point = groupPoint.match(unicode(data)).groups()
-    if len(point) != 2:
-        raise GeometricError, u"'%s' has wrong size" % data
-    return tuple([string.atof(p) for p in point])
+    return not not data
 
-def convertBox(data):
-    """Returns nested list upper right and lower left point
+def convertBlob(data):
+    """Convert a bytea or binary large object (BLOB) to a bytesafe string
     
-    XXX: make this a special type
+    XXX test, if blobs can be nested in PgArrays
+    XXX test, if str is ok
     """
-    box = groupPointList.findall(unicode(data))
-    if len(box) != 2:
-        raise GeometricError, u"'%s' has wrong size" % data
-    return tuple([convertPoint(p) for p in box])
+    return str(data)
 
-def convertCircle(data):
-    """Returns tuple ((x,y), radius) of floats
-    
-    XXX: make this a special type
+def convertBit(data):
     """
-    circle = groupCircle.match(unicode(data)).groups()
-    if len(circle) != 2:
-        raise GeometricError, u"'%s' has wrong size" % data
-    return (convertPoint(circle[0]), string.atof(circle[1]))
-
-def convertLine(data):
-    """Returns tuple of two points, which defines the infinite line
-    
-    XXX: make this a special type
     """
-    line = groupPointList.findall(unicode(data))
-    if len(line) != 2:
-        raise GeometricError, u"'%s' has wrong size" % data
-    return tuple([convertPoint(p) for p in line])
+    return str(data)
 
-def convertLSeg(data):
-    """Returns list of two points
-    
-    XXX: make this a special type
-    """
-    lseg = groupPointList.findall(unicode(data))
-    if len(lseg) != 2:
-        raise GeometricError, u"'%s' has wrong size" % data
-    return [convertPoint(p) for p in lseg]
+def convertUnicode(data):
+    """Return a unicode string"""
+    return unicode(data)
 
-def convertPath(data):
-    """Returns list or tuple of n points, tuple is used for a closed path
-    
-    XXX: make this a special type
-    """
-    if isOpenPath.match(unicode(data)):
-        return [convertPoint(p)
-            for p in groupPointList.findall(unicode(data))]
-    elif isClosedPath.match(unicode(data)):
-        return tuple([convertPoint(p)
-            for p in groupPointList.findall(unicode(data))])
-    else:
-        raise GeometricError, u"'%s' has wrong format" % data
 
-def convertPolygon(data):
-    """Returns tuple of n points
-    
-    XXX: make this a special type
-    """
-    return tuple([convertPoint(p) for p in groupPointList.findall(unicode(data))]) 
+# *********************************
+# ***         numbers           ***
+# *********************************
+
+def convertSmallInt(data):
+    """Converts a string containing a small int (int2) to int"""
+    return string.atoi(unicode(data))    
+
+def convertInt(data):
+    """Return an int"""
+    return int(data)
+
+def convertLong(data):
+    """Return a long"""
+    return long(data)
+
+def convertFloat(data):
+    """Return a float"""
+    return long(data)
+
+
+# *********************************
+# ***        time types         ***
+# *********************************
     
 def convertTime(data):
     """Converts a mxDateTime.time object to a datetime.time object"""
     # XXX: day?
-    if not data: return None
     d, h, min, sec = data.tuple()
     sec, my = _sec2my(sec)
     return datetime.time(h, min, sec, my)
 
+def convertTimeTZ(data):
+    """Converts a mxDateTime.time object to a datetime.time object with timezone"""
+    # XXX: day?
+    d, h, min, sec = data.tuple()
+    sec, my = _sec2my(sec)
+    tzoffset = data.gmtoffset().minutes
+    if tzoffset: tz = datetimeutils.tzinfo(tzoffset) 
+    else: tz = datetimeutils.tzinfo(0)
+    return datetime.time(h, min, sec, my, tz)
+
 def convertTimestamp(data):
     """Converts a mxDateTime.datetime object to a datetime.datetime object"""
-    if not data: return None
     y, m, d, h, min, sec, dayOfWeek, dayOfYear, dst = data.tuple()
     sec, my = _sec2my(sec)
     return datetime.datetime(y, m, d, h, min, sec, my)
 
 def convertTimestampTZ(data):
     """Converts a mxDateTime.time object to a datetime.time object with timezone"""
-    if not data: return None
     y, m, d, h, min, sec, dayOfWeek, dayOfYear, dst = data.tuple()
     sec, my = _sec2my(sec)
     # time zone offset in minutes
@@ -219,7 +190,7 @@
     """Converts a mxDateTime.DateTimeDelta object to a datetime.timedelta object
     
     XXX BUG BUG BUG
-    Warning: mxDateTime.DateTimeDelta returns wrong data for large intervals
+    Warning: pyPgSQL returns wrong data for large intervals
     for example 20 years are 20 days!
     XXX BUG BUG BUG
     """
@@ -227,6 +198,52 @@
     sec, my = _sec2my(sec)
     return datetime.timedelta(days=days, hours=hours, minutes=min,
                               seconds=sec, microseconds=my)
+                              
+def convertPoint(data):
+    return pgtypes.Point2d(data)
+
+def convertBox(data):
+    return pgtypes.Box2d(data)
+
+def convertCircle(data):
+    return pgtypes.Circle2d(data)
+
+def convertLSeg(data):
+    return pgtypes.ClosedPath(data)
+
+def convertLine(data):
+    return pgtypes.OpenPath(data)
+
+def convertPolygon(data):
+    return pgtypes.ClosedPath(data)
+
+def convertPath(data):
+    if pgtypes.isOpenPath(data):
+        return pgtypes.OpenPath(data)
+    if pgtypes.isClosedPath(data):
+        return pgtypes.ClosedPath(data)
+    raise TypeError
+
+def convertINet(data):
+    return convertUnicode(data)
+
+def convertAclitem(data):
+    """
+    unnested PgArray with string 'key=val'
+    """
+    retval = {}
+    for item in data:
+        key, val = unicode(item).split('=')
+        retval[key] = val
+    return retval
+
+def convertVector(data):
+    """
+    int int .... NOT PgArray
+    """
+    if not data: return None
+    return tuple([ int(item) for item in data.split(' ')])
+
 
 def debug(data):
     """XXX  used for debugging"""
@@ -238,53 +255,56 @@
 # http://www.cs.nott.ac.uk/TSG/manuals/databases/postgres/user/x774.htm#AEN1354
 # http://www.postgresql.org/docs/view.php?version=7.2&idoc=0&file=datatype.html
 # types from pypgsql/libpqmodule.c
+# or see postgres src include/catalog/pg_type.h, interfaces/ecpg/lib/pg_type.h
+
 converter_mapping = {
-    'abstime'   : unicode,           # PG_ABSTIME        XXXtime (obsolet)
-    'aclitem'   : unicode,          # PG_ACLITEM    S   unicode XXX PgArray
-    'blob'      : string,           # PG_BLOB           string
+    'abstime'   : convertUnicode,    # PG_ABSTIME        XXXtime (obsolet)
+    'aclitem'   : convertAclitem,   # PG_ACLITEM    S   
+    'blob'      : convertBlob,      # PG_BLOB           string
     'bool'      : convertBool,      # PG_BOOL           boolean
     'box'       : convertBox,       # PG_BOX            geometric.box
-    'char'      : identity,         # PG_BPCHAR         identity XXX ??
-    'bytea'     : string,           # PG_BYTEA          string
-    'money'     : float,            # PG_CASH           float XXX: special?
+    'char'      : convertUnicode,   # PG_BPCHAR         XXX
+    'bytea'     : convertBlob,      # PG_BYTEA          string
+    'money'     : convertFloat,      # PG_CASH           float XXX: special?
     'cid'       : debug,            # PG_CID        S   unicode XXX number?
                                     # need more information! could be connection id
     'cidr'      : convertINet,      # PG_CIDR           network XXX
     'circle'    : convertCircle,    # PG_CIRCLE         geometric.circle
     'date'      : convertTimestamp, # PG_DATE           datetime.date
-    'float4'    : identity,         # PG_FLOAT4         float
-    'float'     : identity,         # PG_FLOAT8         float
+    'float4'    : convertFloat,     # PG_FLOAT4         float
+    'float'     : convertFloat,     # PG_FLOAT8         float
     'inet'      : convertINet,      # PG_INET           network XXX 
     'int2'      : convertSmallInt,  # PG_INT2           integer
-    'int2vector' : unicode,         # PG_INT2VECTOR S   unicode XXX PgArray of int2
-    'integer'   : identity,         # PG_INT4           integer
-    'bigint'    : long,             # PG_INT8           longint
+    'int2vector' : convertVector,   # PG_INT2VECTOR S   
+    'integer'   : convertInt,       # PG_INT4           integer
+    'bigint'    : convertLong,      # PG_INT8           longint
     'interval'  : convertInterval,  # PG_INTERVAL       datetime.delta
     'line'      : convertLine,      # PG_LINE           geometric.line (XXX not implemented in pgsql 7.2)
     'lseg'      : convertLSeg,      # PG_LSEG           geometric.linesegment
-    'macaddr'   : unicode,          # PG_MACADDR        unicode
-    'name'      : identity,         # PG_NAME       S   identity == unicode
-    'numeric'   : float,            # PG_NUMERIC        float XXX: special?
+    'macaddr'   : convertUnicode,   # PG_MACADDR        unicode
+    'name'      : convertUnicode,   # PG_NAME       S   identity == unicode
+    'numeric'   : convertFloat,     # PG_NUMERIC        float XXX: special?
     'oid'       : debug,            # PG_OID        S   unicode XXX: what? is NOT oid in pgpPgAdmin, see rowid
-    'oidvector' : unicode,          # PG_OIDVECTOR  S   unicode XXX: PgArray
+    'oidvector' : convertVector,    # PG_OIDVECTOR  S   
     'path'      : convertPath,      # PG_PATH           geometric.path
     'point'     : convertPoint,     # PG_POINT          geometric.point
     'polygon'   : convertPolygon,   # PG_POLYGON        geometric.polygon
-    'refcursor' : unicode,          # PG_REFCURSOR  S   unicode XXX: what? identitiy?
-    'regproc'   : unicode,          # PG_REGPROC    S   unicode XXX: what? identitiy?
-    'reltime'   : unicode,           # PG_RELTIME        XXX datetime.delta (obsolet)
-    'rowid'     : long,             # PG_ROWID      S   longint; rowid is oid in pgpPgAdmin
-    'text'      : identity,         # PG_TEXT           unicode 
+    'refcursor' : convertUnicode,    # PG_REFCURSOR  S   unicode XXX: what? identitiy?
+    'regproc'   : convertUnicode,    # PG_REGPROC    S   unicode XXX: what? identitiy?
+    'reltime'   : convertUnicode,    # PG_RELTIME        XXX datetime.delta (obsolet)
+    'rowid'     : convertLong,      # PG_ROWID      S   longint; rowid is oid in pgpPgAdmin
+    'text'      : convertUnicode,   # PG_TEXT           unicode 
     'tid'       : debug,            # PG_TID        S   unicode XXX number? what?
                                     # need more information, could be transaction id
     'time'      : convertTime,      # PG_TIME           datetime.time
+    'timetz'    : convertTimeTZ,    # XXX not supported by pyPgSQL, only found in postgres sources
     'timestamp' : convertTimestamp, # PG_TIMESTAMP      datetime.datetime
     'timestamptz' : convertTimestampTZ, # PG_TIMESTAMPTZ    datetime.datetime
-    'tinterval' : unicode,           # PG_TINTERVAL      XXX datetime.delta (obsolet)
-    'unknown'   : unicode,          # PG_UNKNOWN    S?  unicode (unknown), XXX what?
-    'varbit'    : unicode,          # PG_VARBIT         XXX see zpbit!
-    'varchar'   : identity,         # PG_VARCHAR        unicode
-    'xid'       : long,             # PG_XID        S   xid is a longint [was: unicode]
-    'zpbit'     : unicode           # PG_ZPBIT          unicode  XXX: pgsql returns string
+    'tinterval' : convertUnicode,    # PG_TINTERVAL      XXX datetime.delta (obsolet)
+    'unknown'   : convertUnicode,    # PG_UNKNOWN    S?  unicode (unknown), XXX what?
+    'varbit'    : convertBit,       # PG_VARBIT         XXX see zpbit!
+    'varchar'   : convertUnicode,   # PG_VARCHAR        unicode
+    'xid'       : convertLong,      # PG_XID        S   xid is a longint [was: unicode]
+    'zpbit'     : convertBit,       # PG_ZPBIT          unicode  XXX: pgsql returns string
                                     # make int?, this would kill all leading zeros!
     }


=== zopeproducts/pypgsqlda/configure.zcml 1.1.1.1 => 1.1.1.1.2.1 ===
--- zopeproducts/pypgsqlda/configure.zcml:1.1.1.1	Mon Mar 17 12:17:18 2003
+++ zopeproducts/pypgsqlda/configure.zcml	Mon Apr  7 12:17:31 2003
@@ -12,10 +12,10 @@
     </content>
 
 <browser:view
-    name="zopeproducts.pypgsqlda"
+    name="zopeproducts.pypgsqlda_branch"
     for="zope.app.interfaces.container.IAdding."
     class=
-      "zopeproducts.pypgsqlda.browser.pypgsqlDAAddView"
+      "zopeproducts.pypgsqlda_branch.browser.pypgsqlDAAddView"
     permission="zope.Public">
 
   <browser:page name="+" attribute="add" />
@@ -24,6 +24,6 @@
 
 <browser:menuItem menu="add_component"
     for="zope.app.interfaces.container.IAdding."
-    title="pypgsql DA" action="zopeproducts.pypgsqlda"
+    title="pypgsql DA" action="zopeproducts.pypgsqlda_branch"
     description="A PostgreSQL Database Adapter using the pypgsql driver"/>
  </zopeConfigure>

=== Removed File zopeproducts/pypgsqlda/TODO ===

=== Removed File zopeproducts/pypgsqlda/geometric.py ===