[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--