blob: 51cc4545487b485936b8c168ac06c065e84a4174 [file] [log] [blame]
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +00001#----------------------------------------------------------------------
2# Copyright (c) 1999-2001, Digital Creations, Fredericksburg, VA, USA
3# and Andrew Kuchling. All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# o Redistributions of source code must retain the above copyright
10# notice, this list of conditions, and the disclaimer that follows.
11#
12# o Redistributions in binary form must reproduce the above copyright
13# notice, this list of conditions, and the following disclaimer in
14# the documentation and/or other materials provided with the
15# distribution.
16#
17# o Neither the name of Digital Creations nor the names of its
18# contributors may be used to endorse or promote products derived
19# from this software without specific prior written permission.
20#
21# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
22# IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
25# CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32# DAMAGE.
33#----------------------------------------------------------------------
34
35
Gregory P. Smith41631e82003-09-21 00:08:14 +000036"""Support for BerkeleyDB 3.2 through 4.2.
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +000037"""
38
Martin v. Löwis65730a42002-11-24 08:26:01 +000039try:
Gregory P. Smith41631e82003-09-21 00:08:14 +000040 if __name__ == 'bsddb3':
41 # import _pybsddb binary as it should be the more recent version from
42 # a standalone pybsddb addon package than the version included with
43 # python as bsddb._bsddb.
44 import _pybsddb
45 _bsddb = _pybsddb
46 else:
47 import _bsddb
Martin v. Löwis65730a42002-11-24 08:26:01 +000048except ImportError:
49 # Remove ourselves from sys.modules
50 import sys
51 del sys.modules[__name__]
52 raise
Tim Peters0eadaac2003-04-24 16:02:54 +000053
Barry Warsawf71de3e2003-01-28 17:20:44 +000054# bsddb3 calls it db, but provide _db for backwards compatibility
55db = _db = _bsddb
56__version__ = db.__version__
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +000057
Barry Warsawf71de3e2003-01-28 17:20:44 +000058error = db.DBError # So bsddb.error will mean something...
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +000059
60#----------------------------------------------------------------------
61
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +000062import sys
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +000063
Gregory P. Smithcec1b3f2003-09-20 23:51:34 +000064# for backwards compatibility with python versions older than 2.3, the
65# iterator interface is dynamically defined and added using a mixin
66# class. old python can't tokenize it due to the yield keyword.
67if sys.version >= '2.3':
68 exec """
69import UserDict
70class _iter_mixin(UserDict.DictMixin):
71 def __iter__(self):
72 try:
73 yield self.first()[0]
74 next = self.next
75 while 1:
76 yield next()[0]
77 except _bsddb.DBNotFoundError:
78 return
79
80 def iteritems(self):
81 try:
82 yield self.first()
83 next = self.next
84 while 1:
85 yield next()
86 except _bsddb.DBNotFoundError:
87 return
88"""
89else:
90 class _iter_mixin: pass
91
92
93class _DBWithCursor(_iter_mixin):
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +000094 """
95 A simple wrapper around DB that makes it look like the bsddbobject in
96 the old module. It uses a cursor as needed to provide DB traversal.
97 """
98 def __init__(self, db):
99 self.db = db
100 self.dbc = None
101 self.db.set_get_returns_none(0)
102
103 def __del__(self):
104 self.close()
105
106 def _checkCursor(self):
107 if self.dbc is None:
108 self.dbc = self.db.cursor()
109
110 def _checkOpen(self):
111 if self.db is None:
112 raise error, "BSDDB object has already been closed"
113
114 def isOpen(self):
115 return self.db is not None
116
117 def __len__(self):
118 self._checkOpen()
119 return len(self.db)
120
121 def __getitem__(self, key):
122 self._checkOpen()
123 return self.db[key]
124
125 def __setitem__(self, key, value):
126 self._checkOpen()
127 self.db[key] = value
128
129 def __delitem__(self, key):
130 self._checkOpen()
131 del self.db[key]
132
133 def close(self):
134 if self.dbc is not None:
135 self.dbc.close()
136 v = 0
137 if self.db is not None:
138 v = self.db.close()
139 self.dbc = None
140 self.db = None
141 return v
142
143 def keys(self):
144 self._checkOpen()
145 return self.db.keys()
146
147 def has_key(self, key):
148 self._checkOpen()
149 return self.db.has_key(key)
150
151 def set_location(self, key):
152 self._checkOpen()
153 self._checkCursor()
154 return self.dbc.set(key)
155
156 def next(self):
157 self._checkOpen()
158 self._checkCursor()
159 rv = self.dbc.next()
160 return rv
161
162 def previous(self):
163 self._checkOpen()
164 self._checkCursor()
165 rv = self.dbc.prev()
166 return rv
167
168 def first(self):
169 self._checkOpen()
170 self._checkCursor()
171 rv = self.dbc.first()
172 return rv
173
174 def last(self):
175 self._checkOpen()
176 self._checkCursor()
177 rv = self.dbc.last()
178 return rv
179
180 def sync(self):
181 self._checkOpen()
182 return self.db.sync()
183
Raymond Hettinger2e9da602003-09-13 03:18:34 +0000184
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000185#----------------------------------------------------------------------
186# Compatibility object factory functions
187
188def hashopen(file, flag='c', mode=0666, pgsize=None, ffactor=None, nelem=None,
189 cachesize=None, lorder=None, hflags=0):
190
191 flags = _checkflag(flag)
Gregory P. Smith1eb41e22003-09-27 23:00:19 +0000192 e = _openDBEnv()
193 d = db.DB(e)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000194 d.set_flags(hflags)
195 if cachesize is not None: d.set_cachesize(0, cachesize)
196 if pgsize is not None: d.set_pagesize(pgsize)
197 if lorder is not None: d.set_lorder(lorder)
198 if ffactor is not None: d.set_h_ffactor(ffactor)
199 if nelem is not None: d.set_h_nelem(nelem)
Barry Warsawf71de3e2003-01-28 17:20:44 +0000200 d.open(file, db.DB_HASH, flags, mode)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000201 return _DBWithCursor(d)
202
203#----------------------------------------------------------------------
204
205def btopen(file, flag='c', mode=0666,
206 btflags=0, cachesize=None, maxkeypage=None, minkeypage=None,
207 pgsize=None, lorder=None):
208
209 flags = _checkflag(flag)
Gregory P. Smith1eb41e22003-09-27 23:00:19 +0000210 e = _openDBEnv()
211 d = db.DB(e)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000212 if cachesize is not None: d.set_cachesize(0, cachesize)
213 if pgsize is not None: d.set_pagesize(pgsize)
214 if lorder is not None: d.set_lorder(lorder)
215 d.set_flags(btflags)
216 if minkeypage is not None: d.set_bt_minkey(minkeypage)
217 if maxkeypage is not None: d.set_bt_maxkey(maxkeypage)
Barry Warsawf71de3e2003-01-28 17:20:44 +0000218 d.open(file, db.DB_BTREE, flags, mode)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000219 return _DBWithCursor(d)
220
221#----------------------------------------------------------------------
222
223
224def rnopen(file, flag='c', mode=0666,
225 rnflags=0, cachesize=None, pgsize=None, lorder=None,
226 rlen=None, delim=None, source=None, pad=None):
227
228 flags = _checkflag(flag)
Gregory P. Smith1eb41e22003-09-27 23:00:19 +0000229 e = _openDBEnv()
230 d = db.DB(e)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000231 if cachesize is not None: d.set_cachesize(0, cachesize)
232 if pgsize is not None: d.set_pagesize(pgsize)
233 if lorder is not None: d.set_lorder(lorder)
234 d.set_flags(rnflags)
235 if delim is not None: d.set_re_delim(delim)
236 if rlen is not None: d.set_re_len(rlen)
237 if source is not None: d.set_re_source(source)
238 if pad is not None: d.set_re_pad(pad)
Barry Warsawf71de3e2003-01-28 17:20:44 +0000239 d.open(file, db.DB_RECNO, flags, mode)
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000240 return _DBWithCursor(d)
241
242#----------------------------------------------------------------------
243
Gregory P. Smith1eb41e22003-09-27 23:00:19 +0000244def _openDBEnv():
245 e = db.DBEnv()
246 e.open('.', db.DB_PRIVATE | db.DB_CREATE | db.DB_THREAD | db.DB_INIT_LOCK | db.DB_INIT_MPOOL)
247 return e
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000248
249def _checkflag(flag):
250 if flag == 'r':
Barry Warsawf71de3e2003-01-28 17:20:44 +0000251 flags = db.DB_RDONLY
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000252 elif flag == 'rw':
253 flags = 0
254 elif flag == 'w':
Barry Warsawf71de3e2003-01-28 17:20:44 +0000255 flags = db.DB_CREATE
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000256 elif flag == 'c':
Barry Warsawf71de3e2003-01-28 17:20:44 +0000257 flags = db.DB_CREATE
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000258 elif flag == 'n':
Barry Warsawf71de3e2003-01-28 17:20:44 +0000259 flags = db.DB_CREATE | db.DB_TRUNCATE
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000260 else:
261 raise error, "flags should be one of 'r', 'w', 'c' or 'n'"
Barry Warsawf71de3e2003-01-28 17:20:44 +0000262 return flags | db.DB_THREAD
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000263
264#----------------------------------------------------------------------
265
266
267# This is a silly little hack that allows apps to continue to use the
268# DB_THREAD flag even on systems without threads without freaking out
269# BerkeleyDB.
270#
271# This assumes that if Python was built with thread support then
272# BerkeleyDB was too.
273
274try:
275 import thread
276 del thread
277except ImportError:
Barry Warsawf71de3e2003-01-28 17:20:44 +0000278 db.DB_THREAD = 0
Martin v. Löwis6aa4a1f2002-11-19 08:09:52 +0000279
280
281#----------------------------------------------------------------------