Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 1 | #---------------------------------------------------------------------- |
| 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 | |
Barry Warsaw | 9a0d779 | 2002-12-30 20:53:52 +0000 | [diff] [blame] | 36 | """Support for BerkeleyDB 3.1 through 4.1. |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 37 | """ |
| 38 | |
Martin v. Löwis | 65730a4 | 2002-11-24 08:26:01 +0000 | [diff] [blame] | 39 | try: |
| 40 | import _bsddb |
| 41 | except ImportError: |
| 42 | # Remove ourselves from sys.modules |
| 43 | import sys |
| 44 | del sys.modules[__name__] |
| 45 | raise |
Tim Peters | 0eadaac | 2003-04-24 16:02:54 +0000 | [diff] [blame] | 46 | |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 47 | # bsddb3 calls it db, but provide _db for backwards compatibility |
| 48 | db = _db = _bsddb |
| 49 | __version__ = db.__version__ |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 50 | |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 51 | error = db.DBError # So bsddb.error will mean something... |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 52 | |
| 53 | #---------------------------------------------------------------------- |
| 54 | |
Gregory P. Smith | cec1b3f | 2003-09-20 23:51:34 +0000 | [diff] [blame^] | 55 | import sys |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 56 | |
Gregory P. Smith | cec1b3f | 2003-09-20 23:51:34 +0000 | [diff] [blame^] | 57 | # for backwards compatibility with python versions older than 2.3, the |
| 58 | # iterator interface is dynamically defined and added using a mixin |
| 59 | # class. old python can't tokenize it due to the yield keyword. |
| 60 | if sys.version >= '2.3': |
| 61 | exec """ |
| 62 | import UserDict |
| 63 | class _iter_mixin(UserDict.DictMixin): |
| 64 | def __iter__(self): |
| 65 | try: |
| 66 | yield self.first()[0] |
| 67 | next = self.next |
| 68 | while 1: |
| 69 | yield next()[0] |
| 70 | except _bsddb.DBNotFoundError: |
| 71 | return |
| 72 | |
| 73 | def iteritems(self): |
| 74 | try: |
| 75 | yield self.first() |
| 76 | next = self.next |
| 77 | while 1: |
| 78 | yield next() |
| 79 | except _bsddb.DBNotFoundError: |
| 80 | return |
| 81 | """ |
| 82 | else: |
| 83 | class _iter_mixin: pass |
| 84 | |
| 85 | |
| 86 | class _DBWithCursor(_iter_mixin): |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 87 | """ |
| 88 | A simple wrapper around DB that makes it look like the bsddbobject in |
| 89 | the old module. It uses a cursor as needed to provide DB traversal. |
| 90 | """ |
| 91 | def __init__(self, db): |
| 92 | self.db = db |
| 93 | self.dbc = None |
| 94 | self.db.set_get_returns_none(0) |
| 95 | |
| 96 | def __del__(self): |
| 97 | self.close() |
| 98 | |
| 99 | def _checkCursor(self): |
| 100 | if self.dbc is None: |
| 101 | self.dbc = self.db.cursor() |
| 102 | |
| 103 | def _checkOpen(self): |
| 104 | if self.db is None: |
| 105 | raise error, "BSDDB object has already been closed" |
| 106 | |
| 107 | def isOpen(self): |
| 108 | return self.db is not None |
| 109 | |
| 110 | def __len__(self): |
| 111 | self._checkOpen() |
| 112 | return len(self.db) |
| 113 | |
| 114 | def __getitem__(self, key): |
| 115 | self._checkOpen() |
| 116 | return self.db[key] |
| 117 | |
| 118 | def __setitem__(self, key, value): |
| 119 | self._checkOpen() |
| 120 | self.db[key] = value |
| 121 | |
| 122 | def __delitem__(self, key): |
| 123 | self._checkOpen() |
| 124 | del self.db[key] |
| 125 | |
| 126 | def close(self): |
| 127 | if self.dbc is not None: |
| 128 | self.dbc.close() |
| 129 | v = 0 |
| 130 | if self.db is not None: |
| 131 | v = self.db.close() |
| 132 | self.dbc = None |
| 133 | self.db = None |
| 134 | return v |
| 135 | |
| 136 | def keys(self): |
| 137 | self._checkOpen() |
| 138 | return self.db.keys() |
| 139 | |
| 140 | def has_key(self, key): |
| 141 | self._checkOpen() |
| 142 | return self.db.has_key(key) |
| 143 | |
| 144 | def set_location(self, key): |
| 145 | self._checkOpen() |
| 146 | self._checkCursor() |
| 147 | return self.dbc.set(key) |
| 148 | |
| 149 | def next(self): |
| 150 | self._checkOpen() |
| 151 | self._checkCursor() |
| 152 | rv = self.dbc.next() |
| 153 | return rv |
| 154 | |
| 155 | def previous(self): |
| 156 | self._checkOpen() |
| 157 | self._checkCursor() |
| 158 | rv = self.dbc.prev() |
| 159 | return rv |
| 160 | |
| 161 | def first(self): |
| 162 | self._checkOpen() |
| 163 | self._checkCursor() |
| 164 | rv = self.dbc.first() |
| 165 | return rv |
| 166 | |
| 167 | def last(self): |
| 168 | self._checkOpen() |
| 169 | self._checkCursor() |
| 170 | rv = self.dbc.last() |
| 171 | return rv |
| 172 | |
| 173 | def sync(self): |
| 174 | self._checkOpen() |
| 175 | return self.db.sync() |
| 176 | |
Raymond Hettinger | 2e9da60 | 2003-09-13 03:18:34 +0000 | [diff] [blame] | 177 | |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 178 | #---------------------------------------------------------------------- |
| 179 | # Compatibility object factory functions |
| 180 | |
| 181 | def hashopen(file, flag='c', mode=0666, pgsize=None, ffactor=None, nelem=None, |
| 182 | cachesize=None, lorder=None, hflags=0): |
| 183 | |
| 184 | flags = _checkflag(flag) |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 185 | d = db.DB() |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 186 | d.set_flags(hflags) |
| 187 | if cachesize is not None: d.set_cachesize(0, cachesize) |
| 188 | if pgsize is not None: d.set_pagesize(pgsize) |
| 189 | if lorder is not None: d.set_lorder(lorder) |
| 190 | if ffactor is not None: d.set_h_ffactor(ffactor) |
| 191 | if nelem is not None: d.set_h_nelem(nelem) |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 192 | d.open(file, db.DB_HASH, flags, mode) |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 193 | return _DBWithCursor(d) |
| 194 | |
| 195 | #---------------------------------------------------------------------- |
| 196 | |
| 197 | def btopen(file, flag='c', mode=0666, |
| 198 | btflags=0, cachesize=None, maxkeypage=None, minkeypage=None, |
| 199 | pgsize=None, lorder=None): |
| 200 | |
| 201 | flags = _checkflag(flag) |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 202 | d = db.DB() |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 203 | if cachesize is not None: d.set_cachesize(0, cachesize) |
| 204 | if pgsize is not None: d.set_pagesize(pgsize) |
| 205 | if lorder is not None: d.set_lorder(lorder) |
| 206 | d.set_flags(btflags) |
| 207 | if minkeypage is not None: d.set_bt_minkey(minkeypage) |
| 208 | if maxkeypage is not None: d.set_bt_maxkey(maxkeypage) |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 209 | d.open(file, db.DB_BTREE, flags, mode) |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 210 | return _DBWithCursor(d) |
| 211 | |
| 212 | #---------------------------------------------------------------------- |
| 213 | |
| 214 | |
| 215 | def rnopen(file, flag='c', mode=0666, |
| 216 | rnflags=0, cachesize=None, pgsize=None, lorder=None, |
| 217 | rlen=None, delim=None, source=None, pad=None): |
| 218 | |
| 219 | flags = _checkflag(flag) |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 220 | d = db.DB() |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 221 | if cachesize is not None: d.set_cachesize(0, cachesize) |
| 222 | if pgsize is not None: d.set_pagesize(pgsize) |
| 223 | if lorder is not None: d.set_lorder(lorder) |
| 224 | d.set_flags(rnflags) |
| 225 | if delim is not None: d.set_re_delim(delim) |
| 226 | if rlen is not None: d.set_re_len(rlen) |
| 227 | if source is not None: d.set_re_source(source) |
| 228 | if pad is not None: d.set_re_pad(pad) |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 229 | d.open(file, db.DB_RECNO, flags, mode) |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 230 | return _DBWithCursor(d) |
| 231 | |
| 232 | #---------------------------------------------------------------------- |
| 233 | |
| 234 | |
| 235 | def _checkflag(flag): |
| 236 | if flag == 'r': |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 237 | flags = db.DB_RDONLY |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 238 | elif flag == 'rw': |
| 239 | flags = 0 |
| 240 | elif flag == 'w': |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 241 | flags = db.DB_CREATE |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 242 | elif flag == 'c': |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 243 | flags = db.DB_CREATE |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 244 | elif flag == 'n': |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 245 | flags = db.DB_CREATE | db.DB_TRUNCATE |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 246 | else: |
| 247 | raise error, "flags should be one of 'r', 'w', 'c' or 'n'" |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 248 | return flags | db.DB_THREAD |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 249 | |
| 250 | #---------------------------------------------------------------------- |
| 251 | |
| 252 | |
| 253 | # This is a silly little hack that allows apps to continue to use the |
| 254 | # DB_THREAD flag even on systems without threads without freaking out |
| 255 | # BerkeleyDB. |
| 256 | # |
| 257 | # This assumes that if Python was built with thread support then |
| 258 | # BerkeleyDB was too. |
| 259 | |
| 260 | try: |
| 261 | import thread |
| 262 | del thread |
| 263 | except ImportError: |
Barry Warsaw | f71de3e | 2003-01-28 17:20:44 +0000 | [diff] [blame] | 264 | db.DB_THREAD = 0 |
Martin v. Löwis | 6aa4a1f | 2002-11-19 08:09:52 +0000 | [diff] [blame] | 265 | |
| 266 | |
| 267 | #---------------------------------------------------------------------- |