[Zope-dev] SQLAlias Memory Leak?

Brian Lloyd brian@digicool.com
Tue, 19 Dec 2000 10:44:43 -0500


This is a multi-part message in MIME format.

------=_NextPart_000_0042_01C069A8.B27CF610
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit


oops - I sent that before I had my coffee. I should 
have attached the checkin version, not the broken 
one :)

Brian Lloyd        brian@digicool.com
Software Engineer  540.371.6909              
Digital Creations  http://www.digicool.com 



------=_NextPart_000_0042_01C069A8.B27CF610
Content-Type: text/plain;
	name="RDB.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="RDB.py"

#########################################################################=
#####=0A=
# =0A=
# Zope Public License (ZPL) Version 1.0=0A=
# -------------------------------------=0A=
# =0A=
# Copyright (c) Digital Creations.  All rights reserved.=0A=
# =0A=
# This license has been certified as Open Source(tm).=0A=
# =0A=
# Redistribution and use in source and binary forms, with or without=0A=
# modification, are permitted provided that the following conditions are=0A=
# met:=0A=
# =0A=
# 1. Redistributions in source code must retain the above copyright=0A=
#    notice, this list of conditions, and the following disclaimer.=0A=
# =0A=
# 2. Redistributions in binary form must reproduce the above copyright=0A=
#    notice, this list of conditions, and the following disclaimer in=0A=
#    the documentation and/or other materials provided with the=0A=
#    distribution.=0A=
# =0A=
# 3. Digital Creations requests that attribution be given to Zope=0A=
#    in any manner possible. Zope includes a "Powered by Zope"=0A=
#    button that is installed by default. While it is not a license=0A=
#    violation to remove this button, it is requested that the=0A=
#    attribution remain. A significant investment has been put=0A=
#    into Zope, and this effort will continue if the Zope community=0A=
#    continues to grow. This is one way to assure that growth.=0A=
# =0A=
# 4. All advertising materials and documentation mentioning=0A=
#    features derived from or use of this software must display=0A=
#    the following acknowledgement:=0A=
# =0A=
#      "This product includes software developed by Digital Creations=0A=
#      for use in the Z Object Publishing Environment=0A=
#      (http://www.zope.org/)."=0A=
# =0A=
#    In the event that the product being advertised includes an=0A=
#    intact Zope distribution (with copyright and license included)=0A=
#    then this clause is waived.=0A=
# =0A=
# 5. Names associated with Zope or Digital Creations must not be used to=0A=
#    endorse or promote products derived from this software without=0A=
#    prior written permission from Digital Creations.=0A=
# =0A=
# 6. Modified redistributions of any form whatsoever must retain=0A=
#    the following acknowledgment:=0A=
# =0A=
#      "This product includes software developed by Digital Creations=0A=
#      for use in the Z Object Publishing Environment=0A=
#      (http://www.zope.org/)."=0A=
# =0A=
#    Intact (re-)distributions of any official Zope release do not=0A=
#    require an external acknowledgement.=0A=
# =0A=
# 7. Modifications are encouraged but must be packaged separately as=0A=
#    patches to official Zope releases.  Distributions that do not=0A=
#    clearly separate the patches from the original work must be clearly=0A=
#    labeled as unofficial distributions.  Modifications which do not=0A=
#    carry the name Zope may be packaged in any form, as long as they=0A=
#    conform to all of the clauses above.=0A=
# =0A=
# =0A=
# Disclaimer=0A=
# =0A=
#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY=0A=
#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=0A=
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR=0A=
#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS=0A=
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,=0A=
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT=0A=
#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF=0A=
#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND=0A=
#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,=0A=
#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT=0A=
#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF=0A=
#   SUCH DAMAGE.=0A=
# =0A=
# =0A=
# This software consists of contributions made by Digital Creations and=0A=
# many individuals on behalf of Digital Creations.  Specific=0A=
# attributions are listed in the accompanying credits file.=0A=
# =0A=
#########################################################################=
#####=0A=
__doc__=3D'''Class for reading RDB files=0A=
=0A=
=0A=
$Id: RDB.py,v 1.24.32.4 2000/12/19 15:31:53 brian Exp $'''=0A=
__version__=3D'$Revision: 1.24.32.4 $'[11:-2]=0A=
=0A=
import regex, regsub=0A=
from string import split, strip, lower, upper, atof, atoi, atol, find, =
join=0A=
import DateTime=0A=
from Missing import MV=0A=
from array import array=0A=
from Record import Record=0A=
from Acquisition import Implicit=0A=
import ExtensionClass=0A=
=0A=
def parse_text(s):=0A=
    if find(s,'\\') < 0 and (find(s,'\\t') < 0 and find(s,'\\n') < 0): =
return s=0A=
    r=3D[]=0A=
    for x in split(s,'\\\\'):=0A=
        x=3Djoin(split(x,'\\n'),'\n')=0A=
        r.append(join(split(x,'\\t'),'\t'))=0A=
    return join(r,'\\')=0A=
=0A=
=0A=
Parsers=3D{'n': atof,=0A=
         'i': atoi,=0A=
         'l': atol,=0A=
         'd': DateTime.DateTime,=0A=
         't': parse_text,=0A=
         }=0A=
=0A=
class SQLAlias(ExtensionClass.Base):=0A=
    def __init__(self, name): self._n=3Dname=0A=
    def __of__(self, parent): return getattr(parent, self._n)=0A=
 =0A=
class NoBrains: pass=0A=
=0A=
class DatabaseResults:=0A=
    """Class for reading RDB files=0A=
    """=0A=
    _index=3DNone=0A=
=0A=
    # We need to allow access to not-explicitly-protected=0A=
    # individual record objects contained in the result.=0A=
    __allow_access_to_unprotected_subobjects__=3D1=0A=
=0A=
    def __init__(self,file,brains=3DNoBrains, parent=3DNone, =
zbrains=3DNone):=0A=
=0A=
        self._file=3Dfile=0A=
        readline=3Dfile.readline=0A=
        line=3Dreadline()=0A=
        self._parent=3Dparent=0A=
        if zbrains is None: zbrains=3DNoBrains=0A=
=0A=
        comment_pattern=3Dregex.compile('#')=0A=
        while line and comment_pattern.match(line) >=3D 0: =
line=3Dreadline()=0A=
=0A=
        line=3Dline[:-1]=0A=
        if line and line[-1:] in '\r\n': line=3Dline[:-1]=0A=
        self._names=3Dnames=3Dsplit(line,'\t')=0A=
        if not names: raise ValueError, 'No column names'=0A=
=0A=
        aliases=3D[]=0A=
        self._schema=3Dschema=3D{}=0A=
        i=3D0=0A=
        for name in names:=0A=
            name=3Dstrip(name)=0A=
            if not name:=0A=
                raise ValueError, 'Empty column name, %s' % name=0A=
            if schema.has_key(name):=0A=
                raise ValueError, 'Duplicate column name, %s' % name=0A=
            schema[name]=3Di=0A=
=0A=
            # XXX temporary fix: SQLAliases have a leak that needs to=0A=
            # be addressed, then we can take this out.=0A=
            #=0A=
            # n=3Dlower(name)=0A=
            # if n !=3D name: aliases.append((n, SQLAlias(name)))=0A=
            # n=3Dupper(name)=0A=
            # if n !=3D name: aliases.append((n, SQLAlias(name)))=0A=
=0A=
            schema[lower(name)]=3Di=0A=
            schema[upper(name)]=3Di=0A=
=0A=
            # / temporary fix=0A=
            =0A=
            i=3Di+1=0A=
=0A=
        self._nv=3Dnv=3Dlen(names)=0A=
        line=3Dreadline()=0A=
        line=3Dline[:-1]=0A=
        if line[-1:] in '\r\n': line=3Dline[:-1]=0A=
        =0A=
        self._defs=3Ddefs=3Dsplit(line,'\t')=0A=
        if not defs: raise ValueError, 'No column definitions'=0A=
        if len(defs) !=3D nv:=0A=
            raise ValueError, (=0A=
                """The number of column names and the number of column=0A=
                definitions are different.""")=0A=
        =0A=
        i=3D0=0A=
        self._parsers=3Dparsers=3D[]=0A=
        defre=3Dregex.compile('\([0-9]*\)\([a-zA-Z]\)?')=0A=
        self._data_dictionary=3Ddd=3D{}=0A=
        self.__items__=3Ditems=3D[]=0A=
        for _def in defs:=0A=
            _def=3Dstrip(_def)=0A=
            if not _def:=0A=
                raise ValueError, ('Empty column definition for %s' % =
names[i])=0A=
            if defre.match(_def) < 0:=0A=
                raise ValueError, (=0A=
                    'Invalid column definition for, %s, for %s'=0A=
                    % _def, names[i])=0A=
            type=3Dlower(defre.group(2))=0A=
            width=3Ddefre.group(1)=0A=
            if width: width=3Datoi(width)=0A=
            else: width=3D8=0A=
=0A=
            try: parser=3DParsers[type]=0A=
            except: parser=3Dstr=0A=
=0A=
            name=3Dnames[i]=0A=
            d=3D{'name': name, 'type': type, 'width': width, 'parser': =
parser}=0A=
            items.append(d)=0A=
            dd[name]=3Dd=0A=
            =0A=
            parsers.append((i,parser))=0A=
            i=3Di+1=0A=
=0A=
        # Create a record class to hold the records.=0A=
        names=3Dtuple(names)=0A=
=0A=
        class r(Record, Implicit, brains, zbrains):=0A=
            'Result record class'               =0A=
=0A=
        r.__record_schema__=3Dschema=0A=
        for k in filter(lambda k: k[:2]=3D=3D'__', =
Record.__dict__.keys()):=0A=
            setattr(r,k,getattr(Record,k))=0A=
=0A=
        # XXX temporary fix: SQLAliases have a leak that needs to=0A=
        # be addressed, then we can add this back.=0A=
        #=0A=
        # Add SQL Aliases=0A=
        # d=3Dr.__dict__=0A=
        # for k, v in aliases:=0A=
        #     if not hasattr(r,k): d[k]=3Dv=0A=
=0A=
        if hasattr(brains, '__init__'):=0A=
            binit=3Dbrains.__init__=0A=
            if hasattr(binit,'im_func'): binit=3Dbinit.im_func=0A=
            def __init__(self, data, parent, binit=3Dbinit):=0A=
                Record.__init__(self,data)=0A=
                binit(self.__of__(parent))=0A=
=0A=
            r.__dict__['__init__']=3D__init__=0A=
                    =0A=
=0A=
        self._class=3Dr=0A=
=0A=
        # OK, we've read meta data, now get line indexes=0A=
=0A=
        p=3Dfile.tell()=0A=
        save=3Dself._lines=3Darray('i')=0A=
        save=3Dsave.append=0A=
        l=3Dreadline()=0A=
        while l:=0A=
            save(p)=0A=
            p=3Dp+len(l)=0A=
            l=3Dreadline()=0A=
=0A=
    def _searchable_result_columns(self): return self.__items__=0A=
    def names(self): return self._names=0A=
    def data_dictionary(self): return self._data_dictionary=0A=
=0A=
    def __len__(self): return len(self._lines)=0A=
=0A=
    def __getitem__(self,index):=0A=
        if index=3D=3Dself._index: return self._row=0A=
        file=3Dself._file=0A=
        file.seek(self._lines[index])=0A=
        line=3Dfile.readline()=0A=
        line=3Dline[:-1]=0A=
        if line and line[-1:] in '\r\n': line=3Dline[:-1]=0A=
        fields=3Dsplit(line,'\t')=0A=
        l=3Dlen(fields)=0A=
        nv=3Dself._nv=0A=
        if l !=3D nv:=0A=
            if l < nv:=0A=
                fields=3Dfields+['']*(nv-l)=0A=
            else:=0A=
                raise ValueError, (=0A=
                    """The number of items in record %s is invalid=0A=
                    <pre>%s\n%s\n%s\n%s</pre>=0A=
                    """ =0A=
                    % (index, ('=3D'*40), line, ('=3D'*40), fields))=0A=
        for i, parser in self._parsers:=0A=
            try: v=3Dparser(fields[i])=0A=
            except:=0A=
                if fields[i]:=0A=
                    raise ValueError, (=0A=
                        """Invalid value, %s, for %s in record %s"""=0A=
                        % (fields[i], self._names[i], index))=0A=
                else: v=3DMV=0A=
            fields[i]=3Dv=0A=
=0A=
        parent=3Dself._parent=0A=
        fields=3Dself._class(fields, parent)=0A=
        self._index=3Dindex=0A=
        self._row=3Dfields=0A=
        if parent is None: return fields=0A=
        return fields.__of__(parent)=0A=
=0A=
File=3DDatabaseResults=0A=

------=_NextPart_000_0042_01C069A8.B27CF610--