Revert "Roll NDK to r11c and extract it into its own repository."
[android_tools.git] / ndk / prebuilt / linux-x86_64 / lib / python2.7 / bsddb / dbtables.py
blobe8acdd00555e277719b3000581b176c87bb3b99e
1 #-----------------------------------------------------------------------
3 # Copyright (C) 2000, 2001 by Autonomous Zone Industries
4 # Copyright (C) 2002 Gregory P. Smith
6 # License: This is free software. You may use this software for any
7 # purpose including modification/redistribution, so long as
8 # this header remains intact and that you do not claim any
9 # rights of ownership or authorship of this software. This
10 # software has been tested, but no warranty is expressed or
11 # implied.
13 # -- Gregory P. Smith <greg@krypto.org>
15 # This provides a simple database table interface built on top of
16 # the Python Berkeley DB 3 interface.
18 _cvsid = '$Id$'
20 import re
21 import sys
22 import copy
23 import random
24 import struct
27 if sys.version_info[0] >= 3 :
28 import pickle
29 else :
30 if sys.version_info < (2, 6) :
31 import cPickle as pickle
32 else :
33 # When we drop support for python 2.4
34 # we could use: (in 2.5 we need a __future__ statement)
36 # with warnings.catch_warnings():
37 # warnings.filterwarnings(...)
38 # ...
40 # We can not use "with" as is, because it would be invalid syntax
41 # in python 2.4 and (with no __future__) 2.5.
42 # Here we simulate "with" following PEP 343 :
43 import warnings
44 w = warnings.catch_warnings()
45 w.__enter__()
46 try :
47 warnings.filterwarnings('ignore',
48 message='the cPickle module has been removed in Python 3.0',
49 category=DeprecationWarning)
50 import cPickle as pickle
51 finally :
52 w.__exit__()
53 del w
55 try:
56 # For Pythons w/distutils pybsddb
57 from bsddb3 import db
58 except ImportError:
59 # For Python 2.3
60 from bsddb import db
62 class TableDBError(StandardError):
63 pass
64 class TableAlreadyExists(TableDBError):
65 pass
68 class Cond:
69 """This condition matches everything"""
70 def __call__(self, s):
71 return 1
73 class ExactCond(Cond):
74 """Acts as an exact match condition function"""
75 def __init__(self, strtomatch):
76 self.strtomatch = strtomatch
77 def __call__(self, s):
78 return s == self.strtomatch
80 class PrefixCond(Cond):
81 """Acts as a condition function for matching a string prefix"""
82 def __init__(self, prefix):
83 self.prefix = prefix
84 def __call__(self, s):
85 return s[:len(self.prefix)] == self.prefix
87 class PostfixCond(Cond):
88 """Acts as a condition function for matching a string postfix"""
89 def __init__(self, postfix):
90 self.postfix = postfix
91 def __call__(self, s):
92 return s[-len(self.postfix):] == self.postfix
94 class LikeCond(Cond):
95 """
96 Acts as a function that will match using an SQL 'LIKE' style
97 string. Case insensitive and % signs are wild cards.
98 This isn't perfect but it should work for the simple common cases.
99 """
100 def __init__(self, likestr, re_flags=re.IGNORECASE):
101 # escape python re characters
102 chars_to_escape = '.*+()[]?'
103 for char in chars_to_escape :
104 likestr = likestr.replace(char, '\\'+char)
105 # convert %s to wildcards
106 self.likestr = likestr.replace('%', '.*')
107 self.re = re.compile('^'+self.likestr+'$', re_flags)
108 def __call__(self, s):
109 return self.re.match(s)
112 # keys used to store database metadata
114 _table_names_key = '__TABLE_NAMES__' # list of the tables in this db
115 _columns = '._COLUMNS__' # table_name+this key contains a list of columns
117 def _columns_key(table):
118 return table + _columns
121 # these keys are found within table sub databases
123 _data = '._DATA_.' # this+column+this+rowid key contains table data
124 _rowid = '._ROWID_.' # this+rowid+this key contains a unique entry for each
125 # row in the table. (no data is stored)
126 _rowid_str_len = 8 # length in bytes of the unique rowid strings
129 def _data_key(table, col, rowid):
130 return table + _data + col + _data + rowid
132 def _search_col_data_key(table, col):
133 return table + _data + col + _data
135 def _search_all_data_key(table):
136 return table + _data
138 def _rowid_key(table, rowid):
139 return table + _rowid + rowid + _rowid
141 def _search_rowid_key(table):
142 return table + _rowid
144 def contains_metastrings(s) :
145 """Verify that the given string does not contain any
146 metadata strings that might interfere with dbtables database operation.
148 if (s.find(_table_names_key) >= 0 or
149 s.find(_columns) >= 0 or
150 s.find(_data) >= 0 or
151 s.find(_rowid) >= 0):
152 # Then
153 return 1
154 else:
155 return 0
158 class bsdTableDB :
159 def __init__(self, filename, dbhome, create=0, truncate=0, mode=0600,
160 recover=0, dbflags=0):
161 """bsdTableDB(filename, dbhome, create=0, truncate=0, mode=0600)
163 Open database name in the dbhome Berkeley DB directory.
164 Use keyword arguments when calling this constructor.
166 self.db = None
167 myflags = db.DB_THREAD
168 if create:
169 myflags |= db.DB_CREATE
170 flagsforenv = (db.DB_INIT_MPOOL | db.DB_INIT_LOCK | db.DB_INIT_LOG |
171 db.DB_INIT_TXN | dbflags)
172 # DB_AUTO_COMMIT isn't a valid flag for env.open()
173 try:
174 dbflags |= db.DB_AUTO_COMMIT
175 except AttributeError:
176 pass
177 if recover:
178 flagsforenv = flagsforenv | db.DB_RECOVER
179 self.env = db.DBEnv()
180 # enable auto deadlock avoidance
181 self.env.set_lk_detect(db.DB_LOCK_DEFAULT)
182 self.env.open(dbhome, myflags | flagsforenv)
183 if truncate:
184 myflags |= db.DB_TRUNCATE
185 self.db = db.DB(self.env)
186 # this code relies on DBCursor.set* methods to raise exceptions
187 # rather than returning None
188 self.db.set_get_returns_none(1)
189 # allow duplicate entries [warning: be careful w/ metadata]
190 self.db.set_flags(db.DB_DUP)
191 self.db.open(filename, db.DB_BTREE, dbflags | myflags, mode)
192 self.dbfilename = filename
194 if sys.version_info[0] >= 3 :
195 class cursor_py3k(object) :
196 def __init__(self, dbcursor) :
197 self._dbcursor = dbcursor
199 def close(self) :
200 return self._dbcursor.close()
202 def set_range(self, search) :
203 v = self._dbcursor.set_range(bytes(search, "iso8859-1"))
204 if v is not None :
205 v = (v[0].decode("iso8859-1"),
206 v[1].decode("iso8859-1"))
207 return v
209 def __next__(self) :
210 v = getattr(self._dbcursor, "next")()
211 if v is not None :
212 v = (v[0].decode("iso8859-1"),
213 v[1].decode("iso8859-1"))
214 return v
216 class db_py3k(object) :
217 def __init__(self, db) :
218 self._db = db
220 def cursor(self, txn=None) :
221 return cursor_py3k(self._db.cursor(txn=txn))
223 def has_key(self, key, txn=None) :
224 return getattr(self._db,"has_key")(bytes(key, "iso8859-1"),
225 txn=txn)
227 def put(self, key, value, flags=0, txn=None) :
228 key = bytes(key, "iso8859-1")
229 if value is not None :
230 value = bytes(value, "iso8859-1")
231 return self._db.put(key, value, flags=flags, txn=txn)
233 def put_bytes(self, key, value, txn=None) :
234 key = bytes(key, "iso8859-1")
235 return self._db.put(key, value, txn=txn)
237 def get(self, key, txn=None, flags=0) :
238 key = bytes(key, "iso8859-1")
239 v = self._db.get(key, txn=txn, flags=flags)
240 if v is not None :
241 v = v.decode("iso8859-1")
242 return v
244 def get_bytes(self, key, txn=None, flags=0) :
245 key = bytes(key, "iso8859-1")
246 return self._db.get(key, txn=txn, flags=flags)
248 def delete(self, key, txn=None) :
249 key = bytes(key, "iso8859-1")
250 return self._db.delete(key, txn=txn)
252 def close (self) :
253 return self._db.close()
255 self.db = db_py3k(self.db)
256 else : # Python 2.x
257 pass
259 # Initialize the table names list if this is a new database
260 txn = self.env.txn_begin()
261 try:
262 if not getattr(self.db, "has_key")(_table_names_key, txn):
263 getattr(self.db, "put_bytes", self.db.put) \
264 (_table_names_key, pickle.dumps([], 1), txn=txn)
265 # Yes, bare except
266 except:
267 txn.abort()
268 raise
269 else:
270 txn.commit()
271 # TODO verify more of the database's metadata?
272 self.__tablecolumns = {}
274 def __del__(self):
275 self.close()
277 def close(self):
278 if self.db is not None:
279 self.db.close()
280 self.db = None
281 if self.env is not None:
282 self.env.close()
283 self.env = None
285 def checkpoint(self, mins=0):
286 self.env.txn_checkpoint(mins)
288 def sync(self):
289 self.db.sync()
291 def _db_print(self) :
292 """Print the database to stdout for debugging"""
293 print "******** Printing raw database for debugging ********"
294 cur = self.db.cursor()
295 try:
296 key, data = cur.first()
297 while 1:
298 print repr({key: data})
299 next = cur.next()
300 if next:
301 key, data = next
302 else:
303 cur.close()
304 return
305 except db.DBNotFoundError:
306 cur.close()
309 def CreateTable(self, table, columns):
310 """CreateTable(table, columns) - Create a new table in the database.
312 raises TableDBError if it already exists or for other DB errors.
314 assert isinstance(columns, list)
316 txn = None
317 try:
318 # checking sanity of the table and column names here on
319 # table creation will prevent problems elsewhere.
320 if contains_metastrings(table):
321 raise ValueError(
322 "bad table name: contains reserved metastrings")
323 for column in columns :
324 if contains_metastrings(column):
325 raise ValueError(
326 "bad column name: contains reserved metastrings")
328 columnlist_key = _columns_key(table)
329 if getattr(self.db, "has_key")(columnlist_key):
330 raise TableAlreadyExists, "table already exists"
332 txn = self.env.txn_begin()
333 # store the table's column info
334 getattr(self.db, "put_bytes", self.db.put)(columnlist_key,
335 pickle.dumps(columns, 1), txn=txn)
337 # add the table name to the tablelist
338 tablelist = pickle.loads(getattr(self.db, "get_bytes",
339 self.db.get) (_table_names_key, txn=txn, flags=db.DB_RMW))
340 tablelist.append(table)
341 # delete 1st, in case we opened with DB_DUP
342 self.db.delete(_table_names_key, txn=txn)
343 getattr(self.db, "put_bytes", self.db.put)(_table_names_key,
344 pickle.dumps(tablelist, 1), txn=txn)
346 txn.commit()
347 txn = None
348 except db.DBError, dberror:
349 if txn:
350 txn.abort()
351 if sys.version_info < (2, 6) :
352 raise TableDBError, dberror[1]
353 else :
354 raise TableDBError, dberror.args[1]
357 def ListTableColumns(self, table):
358 """Return a list of columns in the given table.
359 [] if the table doesn't exist.
361 assert isinstance(table, str)
362 if contains_metastrings(table):
363 raise ValueError, "bad table name: contains reserved metastrings"
365 columnlist_key = _columns_key(table)
366 if not getattr(self.db, "has_key")(columnlist_key):
367 return []
368 pickledcolumnlist = getattr(self.db, "get_bytes",
369 self.db.get)(columnlist_key)
370 if pickledcolumnlist:
371 return pickle.loads(pickledcolumnlist)
372 else:
373 return []
375 def ListTables(self):
376 """Return a list of tables in this database."""
377 pickledtablelist = self.db.get_get(_table_names_key)
378 if pickledtablelist:
379 return pickle.loads(pickledtablelist)
380 else:
381 return []
383 def CreateOrExtendTable(self, table, columns):
384 """CreateOrExtendTable(table, columns)
386 Create a new table in the database.
388 If a table of this name already exists, extend it to have any
389 additional columns present in the given list as well as
390 all of its current columns.
392 assert isinstance(columns, list)
394 try:
395 self.CreateTable(table, columns)
396 except TableAlreadyExists:
397 # the table already existed, add any new columns
398 txn = None
399 try:
400 columnlist_key = _columns_key(table)
401 txn = self.env.txn_begin()
403 # load the current column list
404 oldcolumnlist = pickle.loads(
405 getattr(self.db, "get_bytes",
406 self.db.get)(columnlist_key, txn=txn, flags=db.DB_RMW))
407 # create a hash table for fast lookups of column names in the
408 # loop below
409 oldcolumnhash = {}
410 for c in oldcolumnlist:
411 oldcolumnhash[c] = c
413 # create a new column list containing both the old and new
414 # column names
415 newcolumnlist = copy.copy(oldcolumnlist)
416 for c in columns:
417 if not c in oldcolumnhash:
418 newcolumnlist.append(c)
420 # store the table's new extended column list
421 if newcolumnlist != oldcolumnlist :
422 # delete the old one first since we opened with DB_DUP
423 self.db.delete(columnlist_key, txn=txn)
424 getattr(self.db, "put_bytes", self.db.put)(columnlist_key,
425 pickle.dumps(newcolumnlist, 1),
426 txn=txn)
428 txn.commit()
429 txn = None
431 self.__load_column_info(table)
432 except db.DBError, dberror:
433 if txn:
434 txn.abort()
435 if sys.version_info < (2, 6) :
436 raise TableDBError, dberror[1]
437 else :
438 raise TableDBError, dberror.args[1]
441 def __load_column_info(self, table) :
442 """initialize the self.__tablecolumns dict"""
443 # check the column names
444 try:
445 tcolpickles = getattr(self.db, "get_bytes",
446 self.db.get)(_columns_key(table))
447 except db.DBNotFoundError:
448 raise TableDBError, "unknown table: %r" % (table,)
449 if not tcolpickles:
450 raise TableDBError, "unknown table: %r" % (table,)
451 self.__tablecolumns[table] = pickle.loads(tcolpickles)
453 def __new_rowid(self, table, txn) :
454 """Create a new unique row identifier"""
455 unique = 0
456 while not unique:
457 # Generate a random 64-bit row ID string
458 # (note: might have <64 bits of true randomness
459 # but it's plenty for our database id needs!)
460 blist = []
461 for x in xrange(_rowid_str_len):
462 blist.append(random.randint(0,255))
463 newid = struct.pack('B'*_rowid_str_len, *blist)
465 if sys.version_info[0] >= 3 :
466 newid = newid.decode("iso8859-1") # 8 bits
468 # Guarantee uniqueness by adding this key to the database
469 try:
470 self.db.put(_rowid_key(table, newid), None, txn=txn,
471 flags=db.DB_NOOVERWRITE)
472 except db.DBKeyExistError:
473 pass
474 else:
475 unique = 1
477 return newid
480 def Insert(self, table, rowdict) :
481 """Insert(table, datadict) - Insert a new row into the table
482 using the keys+values from rowdict as the column values.
485 txn = None
486 try:
487 if not getattr(self.db, "has_key")(_columns_key(table)):
488 raise TableDBError, "unknown table"
490 # check the validity of each column name
491 if not table in self.__tablecolumns:
492 self.__load_column_info(table)
493 for column in rowdict.keys() :
494 if not self.__tablecolumns[table].count(column):
495 raise TableDBError, "unknown column: %r" % (column,)
497 # get a unique row identifier for this row
498 txn = self.env.txn_begin()
499 rowid = self.__new_rowid(table, txn=txn)
501 # insert the row values into the table database
502 for column, dataitem in rowdict.items():
503 # store the value
504 self.db.put(_data_key(table, column, rowid), dataitem, txn=txn)
506 txn.commit()
507 txn = None
509 except db.DBError, dberror:
510 # WIBNI we could just abort the txn and re-raise the exception?
511 # But no, because TableDBError is not related to DBError via
512 # inheritance, so it would be backwards incompatible. Do the next
513 # best thing.
514 info = sys.exc_info()
515 if txn:
516 txn.abort()
517 self.db.delete(_rowid_key(table, rowid))
518 if sys.version_info < (2, 6) :
519 raise TableDBError, dberror[1], info[2]
520 else :
521 raise TableDBError, dberror.args[1], info[2]
524 def Modify(self, table, conditions={}, mappings={}):
525 """Modify(table, conditions={}, mappings={}) - Modify items in rows matching 'conditions' using mapping functions in 'mappings'
527 * table - the table name
528 * conditions - a dictionary keyed on column names containing
529 a condition callable expecting the data string as an
530 argument and returning a boolean.
531 * mappings - a dictionary keyed on column names containing a
532 condition callable expecting the data string as an argument and
533 returning the new string for that column.
536 try:
537 matching_rowids = self.__Select(table, [], conditions)
539 # modify only requested columns
540 columns = mappings.keys()
541 for rowid in matching_rowids.keys():
542 txn = None
543 try:
544 for column in columns:
545 txn = self.env.txn_begin()
546 # modify the requested column
547 try:
548 dataitem = self.db.get(
549 _data_key(table, column, rowid),
550 txn=txn)
551 self.db.delete(
552 _data_key(table, column, rowid),
553 txn=txn)
554 except db.DBNotFoundError:
555 # XXXXXXX row key somehow didn't exist, assume no
556 # error
557 dataitem = None
558 dataitem = mappings[column](dataitem)
559 if dataitem is not None:
560 self.db.put(
561 _data_key(table, column, rowid),
562 dataitem, txn=txn)
563 txn.commit()
564 txn = None
566 # catch all exceptions here since we call unknown callables
567 except:
568 if txn:
569 txn.abort()
570 raise
572 except db.DBError, dberror:
573 if sys.version_info < (2, 6) :
574 raise TableDBError, dberror[1]
575 else :
576 raise TableDBError, dberror.args[1]
578 def Delete(self, table, conditions={}):
579 """Delete(table, conditions) - Delete items matching the given
580 conditions from the table.
582 * conditions - a dictionary keyed on column names containing
583 condition functions expecting the data string as an
584 argument and returning a boolean.
587 try:
588 matching_rowids = self.__Select(table, [], conditions)
590 # delete row data from all columns
591 columns = self.__tablecolumns[table]
592 for rowid in matching_rowids.keys():
593 txn = None
594 try:
595 txn = self.env.txn_begin()
596 for column in columns:
597 # delete the data key
598 try:
599 self.db.delete(_data_key(table, column, rowid),
600 txn=txn)
601 except db.DBNotFoundError:
602 # XXXXXXX column may not exist, assume no error
603 pass
605 try:
606 self.db.delete(_rowid_key(table, rowid), txn=txn)
607 except db.DBNotFoundError:
608 # XXXXXXX row key somehow didn't exist, assume no error
609 pass
610 txn.commit()
611 txn = None
612 except db.DBError, dberror:
613 if txn:
614 txn.abort()
615 raise
616 except db.DBError, dberror:
617 if sys.version_info < (2, 6) :
618 raise TableDBError, dberror[1]
619 else :
620 raise TableDBError, dberror.args[1]
623 def Select(self, table, columns, conditions={}):
624 """Select(table, columns, conditions) - retrieve specific row data
625 Returns a list of row column->value mapping dictionaries.
627 * columns - a list of which column data to return. If
628 columns is None, all columns will be returned.
629 * conditions - a dictionary keyed on column names
630 containing callable conditions expecting the data string as an
631 argument and returning a boolean.
633 try:
634 if not table in self.__tablecolumns:
635 self.__load_column_info(table)
636 if columns is None:
637 columns = self.__tablecolumns[table]
638 matching_rowids = self.__Select(table, columns, conditions)
639 except db.DBError, dberror:
640 if sys.version_info < (2, 6) :
641 raise TableDBError, dberror[1]
642 else :
643 raise TableDBError, dberror.args[1]
644 # return the matches as a list of dictionaries
645 return matching_rowids.values()
648 def __Select(self, table, columns, conditions):
649 """__Select() - Used to implement Select and Delete (above)
650 Returns a dictionary keyed on rowids containing dicts
651 holding the row data for columns listed in the columns param
652 that match the given conditions.
653 * conditions is a dictionary keyed on column names
654 containing callable conditions expecting the data string as an
655 argument and returning a boolean.
657 # check the validity of each column name
658 if not table in self.__tablecolumns:
659 self.__load_column_info(table)
660 if columns is None:
661 columns = self.tablecolumns[table]
662 for column in (columns + conditions.keys()):
663 if not self.__tablecolumns[table].count(column):
664 raise TableDBError, "unknown column: %r" % (column,)
666 # keyed on rows that match so far, containings dicts keyed on
667 # column names containing the data for that row and column.
668 matching_rowids = {}
669 # keys are rowids that do not match
670 rejected_rowids = {}
672 # attempt to sort the conditions in such a way as to minimize full
673 # column lookups
674 def cmp_conditions(atuple, btuple):
675 a = atuple[1]
676 b = btuple[1]
677 if type(a) is type(b):
679 # Needed for python 3. "cmp" vanished in 3.0.1
680 def cmp(a, b) :
681 if a==b : return 0
682 if a<b : return -1
683 return 1
685 if isinstance(a, PrefixCond) and isinstance(b, PrefixCond):
686 # longest prefix first
687 return cmp(len(b.prefix), len(a.prefix))
688 if isinstance(a, LikeCond) and isinstance(b, LikeCond):
689 # longest likestr first
690 return cmp(len(b.likestr), len(a.likestr))
691 return 0
692 if isinstance(a, ExactCond):
693 return -1
694 if isinstance(b, ExactCond):
695 return 1
696 if isinstance(a, PrefixCond):
697 return -1
698 if isinstance(b, PrefixCond):
699 return 1
700 # leave all unknown condition callables alone as equals
701 return 0
703 if sys.version_info < (2, 6) :
704 conditionlist = conditions.items()
705 conditionlist.sort(cmp_conditions)
706 else : # Insertion Sort. Please, improve
707 conditionlist = []
708 for i in conditions.items() :
709 for j, k in enumerate(conditionlist) :
710 r = cmp_conditions(k, i)
711 if r == 1 :
712 conditionlist.insert(j, i)
713 break
714 else :
715 conditionlist.append(i)
717 # Apply conditions to column data to find what we want
718 cur = self.db.cursor()
719 column_num = -1
720 for column, condition in conditionlist:
721 column_num = column_num + 1
722 searchkey = _search_col_data_key(table, column)
723 # speedup: don't linear search columns within loop
724 if column in columns:
725 savethiscolumndata = 1 # save the data for return
726 else:
727 savethiscolumndata = 0 # data only used for selection
729 try:
730 key, data = cur.set_range(searchkey)
731 while key[:len(searchkey)] == searchkey:
732 # extract the rowid from the key
733 rowid = key[-_rowid_str_len:]
735 if not rowid in rejected_rowids:
736 # if no condition was specified or the condition
737 # succeeds, add row to our match list.
738 if not condition or condition(data):
739 if not rowid in matching_rowids:
740 matching_rowids[rowid] = {}
741 if savethiscolumndata:
742 matching_rowids[rowid][column] = data
743 else:
744 if rowid in matching_rowids:
745 del matching_rowids[rowid]
746 rejected_rowids[rowid] = rowid
748 key, data = cur.next()
750 except db.DBError, dberror:
751 if dberror.args[0] != db.DB_NOTFOUND:
752 raise
753 continue
755 cur.close()
757 # we're done selecting rows, garbage collect the reject list
758 del rejected_rowids
760 # extract any remaining desired column data from the
761 # database for the matching rows.
762 if len(columns) > 0:
763 for rowid, rowdata in matching_rowids.items():
764 for column in columns:
765 if column in rowdata:
766 continue
767 try:
768 rowdata[column] = self.db.get(
769 _data_key(table, column, rowid))
770 except db.DBError, dberror:
771 if sys.version_info < (2, 6) :
772 if dberror[0] != db.DB_NOTFOUND:
773 raise
774 else :
775 if dberror.args[0] != db.DB_NOTFOUND:
776 raise
777 rowdata[column] = None
779 # return the matches
780 return matching_rowids
783 def Drop(self, table):
784 """Remove an entire table from the database"""
785 txn = None
786 try:
787 txn = self.env.txn_begin()
789 # delete the column list
790 self.db.delete(_columns_key(table), txn=txn)
792 cur = self.db.cursor(txn)
794 # delete all keys containing this tables column and row info
795 table_key = _search_all_data_key(table)
796 while 1:
797 try:
798 key, data = cur.set_range(table_key)
799 except db.DBNotFoundError:
800 break
801 # only delete items in this table
802 if key[:len(table_key)] != table_key:
803 break
804 cur.delete()
806 # delete all rowids used by this table
807 table_key = _search_rowid_key(table)
808 while 1:
809 try:
810 key, data = cur.set_range(table_key)
811 except db.DBNotFoundError:
812 break
813 # only delete items in this table
814 if key[:len(table_key)] != table_key:
815 break
816 cur.delete()
818 cur.close()
820 # delete the tablename from the table name list
821 tablelist = pickle.loads(
822 getattr(self.db, "get_bytes", self.db.get)(_table_names_key,
823 txn=txn, flags=db.DB_RMW))
824 try:
825 tablelist.remove(table)
826 except ValueError:
827 # hmm, it wasn't there, oh well, that's what we want.
828 pass
829 # delete 1st, incase we opened with DB_DUP
830 self.db.delete(_table_names_key, txn=txn)
831 getattr(self.db, "put_bytes", self.db.put)(_table_names_key,
832 pickle.dumps(tablelist, 1), txn=txn)
834 txn.commit()
835 txn = None
837 if table in self.__tablecolumns:
838 del self.__tablecolumns[table]
840 except db.DBError, dberror:
841 if txn:
842 txn.abort()
843 raise TableDBError(dberror.args[1])