16aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis#----------------------------------------------------------------------- 26aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# 36aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# Copyright (C) 2000, 2001 by Autonomous Zone Industries 4b2c7affbaab984915b9401105334afffeedf706dMartin v. Löwis# Copyright (C) 2002 Gregory P. Smith 56aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# 66aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# License: This is free software. You may use this software for any 76aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# purpose including modification/redistribution, so long as 86aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# this header remains intact and that you do not claim any 96aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# rights of ownership or authorship of this software. This 106aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# software has been tested, but no warranty is expressed or 116aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# implied. 126aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# 13f80578548d46dbe6dad87b8b8f1ac0002bf6aef8Gregory P. Smith# -- Gregory P. Smith <greg@krypto.org> 146aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 156aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# This provides a simple database table interface built on top of 16ca3939cd52664cce10283cb47b360f1df1552fa0Jesus Cea# the Python Berkeley DB 3 interface. 176aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# 186aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis_cvsid = '$Id$' 196aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 206aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwisimport re 21f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsawimport sys 226aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwisimport copy 2395334a5d1e224548d16b358c1314be444625b925Tim Petersimport random 24afed3a4552e0df61477c322f60b10d3ae59edf1cGregory P. Smithimport struct 256557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea 266557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea 276557aac599f1c22051ee61ba61c8c43add406e94Jesus Ceaif sys.version_info[0] >= 3 : 286557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea import pickle 296557aac599f1c22051ee61ba61c8c43add406e94Jesus Ceaelse : 306557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea if sys.version_info < (2, 6) : 316557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea import cPickle as pickle 326557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea else : 334950a3b6ccb91e0ffe937374836caa825e93c742doko@ubuntu.com # When we drop support for python 2.4 346557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea # we could use: (in 2.5 we need a __future__ statement) 356557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea # 366557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea # with warnings.catch_warnings(): 376557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea # warnings.filterwarnings(...) 386557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea # ... 396557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea # 406557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea # We can not use "with" as is, because it would be invalid syntax 414950a3b6ccb91e0ffe937374836caa825e93c742doko@ubuntu.com # in python 2.4 and (with no __future__) 2.5. 426557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea # Here we simulate "with" following PEP 343 : 436557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea import warnings 446557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea w = warnings.catch_warnings() 456557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea w.__enter__() 466557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea try : 476557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea warnings.filterwarnings('ignore', 486557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea message='the cPickle module has been removed in Python 3.0', 496557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea category=DeprecationWarning) 506557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea import cPickle as pickle 516557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea finally : 526557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea w.__exit__() 536557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea del w 546aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 55f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsawtry: 5641631e8f668c9c2c724731d207edcc39c6fcf38cGregory P. Smith # For Pythons w/distutils pybsddb 574907d27c1fcc7bd990715d3023932433076e152fJesus Cea from bsddb3 import db 5841631e8f668c9c2c724731d207edcc39c6fcf38cGregory P. Smithexcept ImportError: 59f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw # For Python 2.3 604907d27c1fcc7bd990715d3023932433076e152fJesus Cea from bsddb import db 616aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 62f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsawclass TableDBError(StandardError): 63f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw pass 64f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsawclass TableAlreadyExists(TableDBError): 65f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw pass 666aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 676aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 686aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwisclass Cond: 696aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """This condition matches everything""" 706aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def __call__(self, s): 716aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return 1 726aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 736aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwisclass ExactCond(Cond): 746aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """Acts as an exact match condition function""" 756aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def __init__(self, strtomatch): 766aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.strtomatch = strtomatch 776aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def __call__(self, s): 786aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return s == self.strtomatch 796aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 806aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwisclass PrefixCond(Cond): 816aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """Acts as a condition function for matching a string prefix""" 826aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def __init__(self, prefix): 836aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.prefix = prefix 846aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def __call__(self, s): 856aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return s[:len(self.prefix)] == self.prefix 866aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 87b2c7affbaab984915b9401105334afffeedf706dMartin v. Löwisclass PostfixCond(Cond): 88b2c7affbaab984915b9401105334afffeedf706dMartin v. Löwis """Acts as a condition function for matching a string postfix""" 89b2c7affbaab984915b9401105334afffeedf706dMartin v. Löwis def __init__(self, postfix): 90b2c7affbaab984915b9401105334afffeedf706dMartin v. Löwis self.postfix = postfix 91b2c7affbaab984915b9401105334afffeedf706dMartin v. Löwis def __call__(self, s): 92b2c7affbaab984915b9401105334afffeedf706dMartin v. Löwis return s[-len(self.postfix):] == self.postfix 93b2c7affbaab984915b9401105334afffeedf706dMartin v. Löwis 946aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwisclass LikeCond(Cond): 956aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 966aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis Acts as a function that will match using an SQL 'LIKE' style 976aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis string. Case insensitive and % signs are wild cards. 986aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis This isn't perfect but it should work for the simple common cases. 996aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 1006aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def __init__(self, likestr, re_flags=re.IGNORECASE): 1016aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # escape python re characters 1026aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis chars_to_escape = '.*+()[]?' 1036aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis for char in chars_to_escape : 104f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw likestr = likestr.replace(char, '\\'+char) 1056aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # convert %s to wildcards 106f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw self.likestr = likestr.replace('%', '.*') 1076aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.re = re.compile('^'+self.likestr+'$', re_flags) 1086aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def __call__(self, s): 1096aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return self.re.match(s) 1106aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 1116aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# 1126aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# keys used to store database metadata 1136aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# 1146aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis_table_names_key = '__TABLE_NAMES__' # list of the tables in this db 1156aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis_columns = '._COLUMNS__' # table_name+this key contains a list of columns 116f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw 117f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsawdef _columns_key(table): 118f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw return table + _columns 1196aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 1206aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# 1216aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# these keys are found within table sub databases 1226aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis# 1236aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis_data = '._DATA_.' # this+column+this+rowid key contains table data 1246aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis_rowid = '._ROWID_.' # this+rowid+this key contains a unique entry for each 1256aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # row in the table. (no data is stored) 1266aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis_rowid_str_len = 8 # length in bytes of the unique rowid strings 127f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw 1284907d27c1fcc7bd990715d3023932433076e152fJesus Cea 129f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsawdef _data_key(table, col, rowid): 130f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw return table + _data + col + _data + rowid 131f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw 132f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsawdef _search_col_data_key(table, col): 133f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw return table + _data + col + _data 134f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw 135f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsawdef _search_all_data_key(table): 136f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw return table + _data 137f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw 138f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsawdef _rowid_key(table, rowid): 139f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw return table + _rowid + rowid + _rowid 140f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw 141f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsawdef _search_rowid_key(table): 142f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw return table + _rowid 1436aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 1446aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwisdef contains_metastrings(s) : 1456aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """Verify that the given string does not contain any 1466aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis metadata strings that might interfere with dbtables database operation. 1476aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 148f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if (s.find(_table_names_key) >= 0 or 149f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw s.find(_columns) >= 0 or 150f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw s.find(_data) >= 0 or 151f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw s.find(_rowid) >= 0): 152f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw # Then 1536aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return 1 154f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw else: 1556aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return 0 1566aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 1576aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 1586aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwisclass bsdTableDB : 1599a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw def __init__(self, filename, dbhome, create=0, truncate=0, mode=0600, 160f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw recover=0, dbflags=0): 161ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith """bsdTableDB(filename, dbhome, create=0, truncate=0, mode=0600) 162ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith 163ca3939cd52664cce10283cb47b360f1df1552fa0Jesus Cea Open database name in the dbhome Berkeley DB directory. 1646aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis Use keyword arguments when calling this constructor. 1656aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 1669a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw self.db = None 1674907d27c1fcc7bd990715d3023932433076e152fJesus Cea myflags = db.DB_THREAD 1689a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw if create: 1694907d27c1fcc7bd990715d3023932433076e152fJesus Cea myflags |= db.DB_CREATE 1704907d27c1fcc7bd990715d3023932433076e152fJesus Cea flagsforenv = (db.DB_INIT_MPOOL | db.DB_INIT_LOCK | db.DB_INIT_LOG | 1714907d27c1fcc7bd990715d3023932433076e152fJesus Cea db.DB_INIT_TXN | dbflags) 1729a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # DB_AUTO_COMMIT isn't a valid flag for env.open() 1739a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw try: 1744907d27c1fcc7bd990715d3023932433076e152fJesus Cea dbflags |= db.DB_AUTO_COMMIT 1759a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw except AttributeError: 1769a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw pass 1779a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw if recover: 1784907d27c1fcc7bd990715d3023932433076e152fJesus Cea flagsforenv = flagsforenv | db.DB_RECOVER 1794907d27c1fcc7bd990715d3023932433076e152fJesus Cea self.env = db.DBEnv() 1809a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # enable auto deadlock avoidance 1814907d27c1fcc7bd990715d3023932433076e152fJesus Cea self.env.set_lk_detect(db.DB_LOCK_DEFAULT) 1826aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.env.open(dbhome, myflags | flagsforenv) 1839a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw if truncate: 1844907d27c1fcc7bd990715d3023932433076e152fJesus Cea myflags |= db.DB_TRUNCATE 1854907d27c1fcc7bd990715d3023932433076e152fJesus Cea self.db = db.DB(self.env) 186455d46f0d921337405ebd3a098c210f3614ae77cGregory P. Smith # this code relies on DBCursor.set* methods to raise exceptions 187455d46f0d921337405ebd3a098c210f3614ae77cGregory P. Smith # rather than returning None 188455d46f0d921337405ebd3a098c210f3614ae77cGregory P. Smith self.db.set_get_returns_none(1) 1899a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # allow duplicate entries [warning: be careful w/ metadata] 1904907d27c1fcc7bd990715d3023932433076e152fJesus Cea self.db.set_flags(db.DB_DUP) 1914907d27c1fcc7bd990715d3023932433076e152fJesus Cea self.db.open(filename, db.DB_BTREE, dbflags | myflags, mode) 1926aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.dbfilename = filename 1934907d27c1fcc7bd990715d3023932433076e152fJesus Cea 1944907d27c1fcc7bd990715d3023932433076e152fJesus Cea if sys.version_info[0] >= 3 : 1954907d27c1fcc7bd990715d3023932433076e152fJesus Cea class cursor_py3k(object) : 1964907d27c1fcc7bd990715d3023932433076e152fJesus Cea def __init__(self, dbcursor) : 1974907d27c1fcc7bd990715d3023932433076e152fJesus Cea self._dbcursor = dbcursor 1984907d27c1fcc7bd990715d3023932433076e152fJesus Cea 1994907d27c1fcc7bd990715d3023932433076e152fJesus Cea def close(self) : 2004907d27c1fcc7bd990715d3023932433076e152fJesus Cea return self._dbcursor.close() 2014907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2024907d27c1fcc7bd990715d3023932433076e152fJesus Cea def set_range(self, search) : 2034907d27c1fcc7bd990715d3023932433076e152fJesus Cea v = self._dbcursor.set_range(bytes(search, "iso8859-1")) 2048d3f130d41d0c3f437f37a18c624955ce8bf65d3Ezio Melotti if v is not None : 2054907d27c1fcc7bd990715d3023932433076e152fJesus Cea v = (v[0].decode("iso8859-1"), 2064907d27c1fcc7bd990715d3023932433076e152fJesus Cea v[1].decode("iso8859-1")) 2074907d27c1fcc7bd990715d3023932433076e152fJesus Cea return v 2084907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2094907d27c1fcc7bd990715d3023932433076e152fJesus Cea def __next__(self) : 2104907d27c1fcc7bd990715d3023932433076e152fJesus Cea v = getattr(self._dbcursor, "next")() 2118d3f130d41d0c3f437f37a18c624955ce8bf65d3Ezio Melotti if v is not None : 2124907d27c1fcc7bd990715d3023932433076e152fJesus Cea v = (v[0].decode("iso8859-1"), 2134907d27c1fcc7bd990715d3023932433076e152fJesus Cea v[1].decode("iso8859-1")) 2144907d27c1fcc7bd990715d3023932433076e152fJesus Cea return v 2154907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2164907d27c1fcc7bd990715d3023932433076e152fJesus Cea class db_py3k(object) : 2174907d27c1fcc7bd990715d3023932433076e152fJesus Cea def __init__(self, db) : 2184907d27c1fcc7bd990715d3023932433076e152fJesus Cea self._db = db 2194907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2204907d27c1fcc7bd990715d3023932433076e152fJesus Cea def cursor(self, txn=None) : 2214907d27c1fcc7bd990715d3023932433076e152fJesus Cea return cursor_py3k(self._db.cursor(txn=txn)) 2224907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2234907d27c1fcc7bd990715d3023932433076e152fJesus Cea def has_key(self, key, txn=None) : 2244907d27c1fcc7bd990715d3023932433076e152fJesus Cea return getattr(self._db,"has_key")(bytes(key, "iso8859-1"), 2254907d27c1fcc7bd990715d3023932433076e152fJesus Cea txn=txn) 2264907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2274907d27c1fcc7bd990715d3023932433076e152fJesus Cea def put(self, key, value, flags=0, txn=None) : 2284907d27c1fcc7bd990715d3023932433076e152fJesus Cea key = bytes(key, "iso8859-1") 2298d3f130d41d0c3f437f37a18c624955ce8bf65d3Ezio Melotti if value is not None : 2304907d27c1fcc7bd990715d3023932433076e152fJesus Cea value = bytes(value, "iso8859-1") 2314907d27c1fcc7bd990715d3023932433076e152fJesus Cea return self._db.put(key, value, flags=flags, txn=txn) 2324907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2334907d27c1fcc7bd990715d3023932433076e152fJesus Cea def put_bytes(self, key, value, txn=None) : 2344907d27c1fcc7bd990715d3023932433076e152fJesus Cea key = bytes(key, "iso8859-1") 2354907d27c1fcc7bd990715d3023932433076e152fJesus Cea return self._db.put(key, value, txn=txn) 2364907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2374907d27c1fcc7bd990715d3023932433076e152fJesus Cea def get(self, key, txn=None, flags=0) : 2384907d27c1fcc7bd990715d3023932433076e152fJesus Cea key = bytes(key, "iso8859-1") 2394907d27c1fcc7bd990715d3023932433076e152fJesus Cea v = self._db.get(key, txn=txn, flags=flags) 2408d3f130d41d0c3f437f37a18c624955ce8bf65d3Ezio Melotti if v is not None : 2414907d27c1fcc7bd990715d3023932433076e152fJesus Cea v = v.decode("iso8859-1") 2424907d27c1fcc7bd990715d3023932433076e152fJesus Cea return v 2434907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2444907d27c1fcc7bd990715d3023932433076e152fJesus Cea def get_bytes(self, key, txn=None, flags=0) : 2454907d27c1fcc7bd990715d3023932433076e152fJesus Cea key = bytes(key, "iso8859-1") 2464907d27c1fcc7bd990715d3023932433076e152fJesus Cea return self._db.get(key, txn=txn, flags=flags) 2474907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2484907d27c1fcc7bd990715d3023932433076e152fJesus Cea def delete(self, key, txn=None) : 2494907d27c1fcc7bd990715d3023932433076e152fJesus Cea key = bytes(key, "iso8859-1") 2504907d27c1fcc7bd990715d3023932433076e152fJesus Cea return self._db.delete(key, txn=txn) 2514907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2524907d27c1fcc7bd990715d3023932433076e152fJesus Cea def close (self) : 2534907d27c1fcc7bd990715d3023932433076e152fJesus Cea return self._db.close() 2544907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2554907d27c1fcc7bd990715d3023932433076e152fJesus Cea self.db = db_py3k(self.db) 2564907d27c1fcc7bd990715d3023932433076e152fJesus Cea else : # Python 2.x 2574907d27c1fcc7bd990715d3023932433076e152fJesus Cea pass 2584907d27c1fcc7bd990715d3023932433076e152fJesus Cea 2596aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # Initialize the table names list if this is a new database 2609a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw txn = self.env.txn_begin() 2619a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw try: 2624907d27c1fcc7bd990715d3023932433076e152fJesus Cea if not getattr(self.db, "has_key")(_table_names_key, txn): 2634907d27c1fcc7bd990715d3023932433076e152fJesus Cea getattr(self.db, "put_bytes", self.db.put) \ 2644907d27c1fcc7bd990715d3023932433076e152fJesus Cea (_table_names_key, pickle.dumps([], 1), txn=txn) 2659a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # Yes, bare except 2669a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw except: 2679a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw txn.abort() 2689a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw raise 2699a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw else: 2709a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw txn.commit() 2716aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # TODO verify more of the database's metadata? 2726aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.__tablecolumns = {} 2736aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 2746aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def __del__(self): 2756aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.close() 2766aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 2776aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def close(self): 2786aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if self.db is not None: 2796aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.db.close() 2806aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.db = None 2816aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if self.env is not None: 2826aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.env.close() 2836aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.env = None 2846aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 2856aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def checkpoint(self, mins=0): 2866557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea self.env.txn_checkpoint(mins) 2876aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 2886aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def sync(self): 2896557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea self.db.sync() 2906aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 2916aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def _db_print(self) : 2926aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """Print the database to stdout for debugging""" 2936aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis print "******** Printing raw database for debugging ********" 2946aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis cur = self.db.cursor() 2956aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 2966aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis key, data = cur.first() 297f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw while 1: 29870a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald print repr({key: data}) 2996aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis next = cur.next() 3006aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if next: 3016aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis key, data = next 3026aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis else: 3036aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis cur.close() 3046aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return 3054907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBNotFoundError: 3066aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis cur.close() 3076aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3086aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3099a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw def CreateTable(self, table, columns): 310ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith """CreateTable(table, columns) - Create a new table in the database. 311ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith 3126aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis raises TableDBError if it already exists or for other DB errors. 3136aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 314c5a11fabdb03d032f278f86e600bcdaafdb5d783Jesus Cea assert isinstance(columns, list) 3154907d27c1fcc7bd990715d3023932433076e152fJesus Cea 3166aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 3176aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 3186aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # checking sanity of the table and column names here on 3196aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # table creation will prevent problems elsewhere. 3209a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw if contains_metastrings(table): 3219a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw raise ValueError( 3229a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw "bad table name: contains reserved metastrings") 3236aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis for column in columns : 3249a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw if contains_metastrings(column): 3259a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw raise ValueError( 3269a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw "bad column name: contains reserved metastrings") 3276aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3286aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis columnlist_key = _columns_key(table) 3294907d27c1fcc7bd990715d3023932433076e152fJesus Cea if getattr(self.db, "has_key")(columnlist_key): 3306aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis raise TableAlreadyExists, "table already exists" 3316aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3326aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = self.env.txn_begin() 3336aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # store the table's column info 3344907d27c1fcc7bd990715d3023932433076e152fJesus Cea getattr(self.db, "put_bytes", self.db.put)(columnlist_key, 3354907d27c1fcc7bd990715d3023932433076e152fJesus Cea pickle.dumps(columns, 1), txn=txn) 3366aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3376aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # add the table name to the tablelist 3384907d27c1fcc7bd990715d3023932433076e152fJesus Cea tablelist = pickle.loads(getattr(self.db, "get_bytes", 3394907d27c1fcc7bd990715d3023932433076e152fJesus Cea self.db.get) (_table_names_key, txn=txn, flags=db.DB_RMW)) 3406aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis tablelist.append(table) 3419a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # delete 1st, in case we opened with DB_DUP 342afed3a4552e0df61477c322f60b10d3ae59edf1cGregory P. Smith self.db.delete(_table_names_key, txn=txn) 3434907d27c1fcc7bd990715d3023932433076e152fJesus Cea getattr(self.db, "put_bytes", self.db.put)(_table_names_key, 3444907d27c1fcc7bd990715d3023932433076e152fJesus Cea pickle.dumps(tablelist, 1), txn=txn) 3456aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3466aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.commit() 3476aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 3484907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBError, dberror: 349f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if txn: 3506aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.abort() 3515d62cfe070b63cdb3c80744ef9970facc008750cEzio Melotti if sys.version_info < (2, 6) : 3524907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror[1] 3534907d27c1fcc7bd990715d3023932433076e152fJesus Cea else : 3544907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror.args[1] 3556aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3566aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3576aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def ListTableColumns(self, table): 3589a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw """Return a list of columns in the given table. 3599a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw [] if the table doesn't exist. 3606aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 361c5a11fabdb03d032f278f86e600bcdaafdb5d783Jesus Cea assert isinstance(table, str) 362f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if contains_metastrings(table): 3636aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis raise ValueError, "bad table name: contains reserved metastrings" 3646aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3656aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis columnlist_key = _columns_key(table) 3664907d27c1fcc7bd990715d3023932433076e152fJesus Cea if not getattr(self.db, "has_key")(columnlist_key): 3676aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return [] 3684907d27c1fcc7bd990715d3023932433076e152fJesus Cea pickledcolumnlist = getattr(self.db, "get_bytes", 3694907d27c1fcc7bd990715d3023932433076e152fJesus Cea self.db.get)(columnlist_key) 3706aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if pickledcolumnlist: 3716aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return pickle.loads(pickledcolumnlist) 3726aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis else: 3736aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return [] 3746aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3756aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def ListTables(self): 3766aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """Return a list of tables in this database.""" 3774907d27c1fcc7bd990715d3023932433076e152fJesus Cea pickledtablelist = self.db.get_get(_table_names_key) 3786aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if pickledtablelist: 3796aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return pickle.loads(pickledtablelist) 3806aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis else: 3816aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return [] 3826aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 3836aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def CreateOrExtendTable(self, table, columns): 3849a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw """CreateOrExtendTable(table, columns) 3859a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw 386ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith Create a new table in the database. 387ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith 3886aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis If a table of this name already exists, extend it to have any 3896aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis additional columns present in the given list as well as 3906aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis all of its current columns. 3916aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 392c5a11fabdb03d032f278f86e600bcdaafdb5d783Jesus Cea assert isinstance(columns, list) 3934907d27c1fcc7bd990715d3023932433076e152fJesus Cea 3946aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 3956aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.CreateTable(table, columns) 3966aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis except TableAlreadyExists: 3976aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # the table already existed, add any new columns 3986aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 3996aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 4006aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis columnlist_key = _columns_key(table) 4016aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = self.env.txn_begin() 4026aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4036aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # load the current column list 4049a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw oldcolumnlist = pickle.loads( 4054907d27c1fcc7bd990715d3023932433076e152fJesus Cea getattr(self.db, "get_bytes", 4064907d27c1fcc7bd990715d3023932433076e152fJesus Cea self.db.get)(columnlist_key, txn=txn, flags=db.DB_RMW)) 4079a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # create a hash table for fast lookups of column names in the 4089a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # loop below 4096aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis oldcolumnhash = {} 4106aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis for c in oldcolumnlist: 4116aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis oldcolumnhash[c] = c 4126aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4139a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # create a new column list containing both the old and new 4149a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # column names 4156aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis newcolumnlist = copy.copy(oldcolumnlist) 4166aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis for c in columns: 41763b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou if not c in oldcolumnhash: 4186aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis newcolumnlist.append(c) 4196aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4206aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # store the table's new extended column list 4216aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if newcolumnlist != oldcolumnlist : 4226aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # delete the old one first since we opened with DB_DUP 423afed3a4552e0df61477c322f60b10d3ae59edf1cGregory P. Smith self.db.delete(columnlist_key, txn=txn) 4244907d27c1fcc7bd990715d3023932433076e152fJesus Cea getattr(self.db, "put_bytes", self.db.put)(columnlist_key, 4259a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw pickle.dumps(newcolumnlist, 1), 4269a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw txn=txn) 4276aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4286aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.commit() 4296aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 4306aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4316aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.__load_column_info(table) 4324907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBError, dberror: 4336aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if txn: 4346aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.abort() 4355d62cfe070b63cdb3c80744ef9970facc008750cEzio Melotti if sys.version_info < (2, 6) : 4364907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror[1] 4374907d27c1fcc7bd990715d3023932433076e152fJesus Cea else : 4384907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror.args[1] 4396aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4406aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4416aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def __load_column_info(self, table) : 4426aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """initialize the self.__tablecolumns dict""" 4436aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # check the column names 4446aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 4454907d27c1fcc7bd990715d3023932433076e152fJesus Cea tcolpickles = getattr(self.db, "get_bytes", 4464907d27c1fcc7bd990715d3023932433076e152fJesus Cea self.db.get)(_columns_key(table)) 4474907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBNotFoundError: 44870a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald raise TableDBError, "unknown table: %r" % (table,) 4496aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if not tcolpickles: 45070a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald raise TableDBError, "unknown table: %r" % (table,) 4516aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.__tablecolumns[table] = pickle.loads(tcolpickles) 4526aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4539a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw def __new_rowid(self, table, txn) : 4546aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """Create a new unique row identifier""" 4556aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis unique = 0 456f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw while not unique: 4576aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # Generate a random 64-bit row ID string 4586d331ca9a49245c5d18d3aa9b0f72cc54f9521c3Gregory P. Smith # (note: might have <64 bits of true randomness 4596aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # but it's plenty for our database id needs!) 4603ef21cb7c61236453b257c30ce08f8f58489e802Gregory P. Smith blist = [] 4613ef21cb7c61236453b257c30ce08f8f58489e802Gregory P. Smith for x in xrange(_rowid_str_len): 4626d331ca9a49245c5d18d3aa9b0f72cc54f9521c3Gregory P. Smith blist.append(random.randint(0,255)) 4633ef21cb7c61236453b257c30ce08f8f58489e802Gregory P. Smith newid = struct.pack('B'*_rowid_str_len, *blist) 4646aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4654907d27c1fcc7bd990715d3023932433076e152fJesus Cea if sys.version_info[0] >= 3 : 4664907d27c1fcc7bd990715d3023932433076e152fJesus Cea newid = newid.decode("iso8859-1") # 8 bits 4674907d27c1fcc7bd990715d3023932433076e152fJesus Cea 4686aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # Guarantee uniqueness by adding this key to the database 4696aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 4709a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw self.db.put(_rowid_key(table, newid), None, txn=txn, 4714907d27c1fcc7bd990715d3023932433076e152fJesus Cea flags=db.DB_NOOVERWRITE) 4724907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBKeyExistError: 4736aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis pass 4746aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis else: 4756aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis unique = 1 4766aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4776aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return newid 4786aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4796aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4806aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def Insert(self, table, rowdict) : 4816aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """Insert(table, datadict) - Insert a new row into the table 4826aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis using the keys+values from rowdict as the column values. 4836aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 4844907d27c1fcc7bd990715d3023932433076e152fJesus Cea 4856aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 4866aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 4874907d27c1fcc7bd990715d3023932433076e152fJesus Cea if not getattr(self.db, "has_key")(_columns_key(table)): 4886aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis raise TableDBError, "unknown table" 4896aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4906aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # check the validity of each column name 49163b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou if not table in self.__tablecolumns: 4926aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.__load_column_info(table) 4936aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis for column in rowdict.keys() : 494f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if not self.__tablecolumns[table].count(column): 49570a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald raise TableDBError, "unknown column: %r" % (column,) 4966aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 4976aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # get a unique row identifier for this row 4986aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = self.env.txn_begin() 4999a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw rowid = self.__new_rowid(table, txn=txn) 5006aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 5016aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # insert the row values into the table database 502f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw for column, dataitem in rowdict.items(): 5036aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # store the value 5046aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.db.put(_data_key(table, column, rowid), dataitem, txn=txn) 5056aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 5066aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.commit() 5076aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 5086aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 5094907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBError, dberror: 5109a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # WIBNI we could just abort the txn and re-raise the exception? 5119a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # But no, because TableDBError is not related to DBError via 5129a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # inheritance, so it would be backwards incompatible. Do the next 5139a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # best thing. 5149a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw info = sys.exc_info() 5159a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw if txn: 5166aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.abort() 5176aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.db.delete(_rowid_key(table, rowid)) 5185d62cfe070b63cdb3c80744ef9970facc008750cEzio Melotti if sys.version_info < (2, 6) : 5194907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror[1], info[2] 5204907d27c1fcc7bd990715d3023932433076e152fJesus Cea else : 5214907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror.args[1], info[2] 5226aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 5236aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 524f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw def Modify(self, table, conditions={}, mappings={}): 525ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith """Modify(table, conditions={}, mappings={}) - Modify items in rows matching 'conditions' using mapping functions in 'mappings' 526ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith 527ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith * table - the table name 528ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith * conditions - a dictionary keyed on column names containing 529ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith a condition callable expecting the data string as an 530ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith argument and returning a boolean. 531ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith * mappings - a dictionary keyed on column names containing a 532ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith condition callable expecting the data string as an argument and 533ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith returning the new string for that column. 5346aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 5354907d27c1fcc7bd990715d3023932433076e152fJesus Cea 5366aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 5376aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis matching_rowids = self.__Select(table, [], conditions) 5386aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 5396aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # modify only requested columns 5406aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis columns = mappings.keys() 541f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw for rowid in matching_rowids.keys(): 5426aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 5436aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 544f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw for column in columns: 5456aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = self.env.txn_begin() 5466aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # modify the requested column 5476aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 5489a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw dataitem = self.db.get( 5499a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw _data_key(table, column, rowid), 550afed3a4552e0df61477c322f60b10d3ae59edf1cGregory P. Smith txn=txn) 5519a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw self.db.delete( 5529a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw _data_key(table, column, rowid), 553afed3a4552e0df61477c322f60b10d3ae59edf1cGregory P. Smith txn=txn) 5544907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBNotFoundError: 5559a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # XXXXXXX row key somehow didn't exist, assume no 5569a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # error 5579a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw dataitem = None 5586aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis dataitem = mappings[column](dataitem) 5598d3f130d41d0c3f437f37a18c624955ce8bf65d3Ezio Melotti if dataitem is not None: 5609a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw self.db.put( 5619a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw _data_key(table, column, rowid), 5629a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw dataitem, txn=txn) 5636aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.commit() 5646aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 5656aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 566ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith # catch all exceptions here since we call unknown callables 567ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith except: 568f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if txn: 5696aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.abort() 5706aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis raise 5716aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 5724907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBError, dberror: 5735d62cfe070b63cdb3c80744ef9970facc008750cEzio Melotti if sys.version_info < (2, 6) : 5744907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror[1] 5754907d27c1fcc7bd990715d3023932433076e152fJesus Cea else : 5764907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror.args[1] 5776aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 578f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw def Delete(self, table, conditions={}): 5796aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """Delete(table, conditions) - Delete items matching the given 5806aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis conditions from the table. 581ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith 582ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith * conditions - a dictionary keyed on column names containing 583ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith condition functions expecting the data string as an 584ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith argument and returning a boolean. 5856aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 5864907d27c1fcc7bd990715d3023932433076e152fJesus Cea 5876aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 5886aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis matching_rowids = self.__Select(table, [], conditions) 5896aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 5906aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # delete row data from all columns 5916aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis columns = self.__tablecolumns[table] 592f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw for rowid in matching_rowids.keys(): 5936aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 5946aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 5956aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = self.env.txn_begin() 596f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw for column in columns: 5976aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # delete the data key 5986aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 5999a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw self.db.delete(_data_key(table, column, rowid), 600afed3a4552e0df61477c322f60b10d3ae59edf1cGregory P. Smith txn=txn) 6014907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBNotFoundError: 6029a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # XXXXXXX column may not exist, assume no error 6039a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw pass 6046aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 6056aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 606afed3a4552e0df61477c322f60b10d3ae59edf1cGregory P. Smith self.db.delete(_rowid_key(table, rowid), txn=txn) 6074907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBNotFoundError: 6089a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # XXXXXXX row key somehow didn't exist, assume no error 6099a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw pass 6106aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.commit() 6116aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 6124907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBError, dberror: 613f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if txn: 6146aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.abort() 6156aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis raise 6164907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBError, dberror: 6175d62cfe070b63cdb3c80744ef9970facc008750cEzio Melotti if sys.version_info < (2, 6) : 6184907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror[1] 6194907d27c1fcc7bd990715d3023932433076e152fJesus Cea else : 6204907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror.args[1] 6216aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 6226aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 623f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw def Select(self, table, columns, conditions={}): 624ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith """Select(table, columns, conditions) - retrieve specific row data 6256aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis Returns a list of row column->value mapping dictionaries. 626ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith 627ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith * columns - a list of which column data to return. If 6286aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis columns is None, all columns will be returned. 629ff7d991a07f21a0a368f422efcf17b27c363e1d2Gregory P. Smith * conditions - a dictionary keyed on column names 6306aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis containing callable conditions expecting the data string as an 6316aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis argument and returning a boolean. 6326aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 6336aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 63463b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou if not table in self.__tablecolumns: 6356aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.__load_column_info(table) 636f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if columns is None: 6376aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis columns = self.__tablecolumns[table] 6386aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis matching_rowids = self.__Select(table, columns, conditions) 6394907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBError, dberror: 6405d62cfe070b63cdb3c80744ef9970facc008750cEzio Melotti if sys.version_info < (2, 6) : 6414907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror[1] 6424907d27c1fcc7bd990715d3023932433076e152fJesus Cea else : 6434907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise TableDBError, dberror.args[1] 6446aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # return the matches as a list of dictionaries 6456aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return matching_rowids.values() 6466aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 6476aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 648f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw def __Select(self, table, columns, conditions): 6496aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """__Select() - Used to implement Select and Delete (above) 6506aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis Returns a dictionary keyed on rowids containing dicts 6516aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis holding the row data for columns listed in the columns param 6526aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis that match the given conditions. 6536aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis * conditions is a dictionary keyed on column names 6546aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis containing callable conditions expecting the data string as an 6556aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis argument and returning a boolean. 6566aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis """ 6576aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # check the validity of each column name 65863b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou if not table in self.__tablecolumns: 6596aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis self.__load_column_info(table) 660f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if columns is None: 6616aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis columns = self.tablecolumns[table] 662f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw for column in (columns + conditions.keys()): 663f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if not self.__tablecolumns[table].count(column): 66470a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald raise TableDBError, "unknown column: %r" % (column,) 6656aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 6666aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # keyed on rows that match so far, containings dicts keyed on 6676aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # column names containing the data for that row and column. 6686aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis matching_rowids = {} 669f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw # keys are rowids that do not match 670f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw rejected_rowids = {} 6716aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 6729a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # attempt to sort the conditions in such a way as to minimize full 6739a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # column lookups 6746aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis def cmp_conditions(atuple, btuple): 6756aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis a = atuple[1] 6766aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis b = btuple[1] 677f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if type(a) is type(b): 6786557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea 6796557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea # Needed for python 3. "cmp" vanished in 3.0.1 6806557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea def cmp(a, b) : 6816557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea if a==b : return 0 6826557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea if a<b : return -1 6836557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea return 1 6846557aac599f1c22051ee61ba61c8c43add406e94Jesus Cea 6856aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if isinstance(a, PrefixCond) and isinstance(b, PrefixCond): 6869a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # longest prefix first 6879a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw return cmp(len(b.prefix), len(a.prefix)) 6886aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if isinstance(a, LikeCond) and isinstance(b, LikeCond): 6899a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # longest likestr first 6909a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw return cmp(len(b.likestr), len(a.likestr)) 6916aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return 0 6926aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if isinstance(a, ExactCond): 6936aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return -1 6946aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if isinstance(b, ExactCond): 6956aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return 1 6966aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if isinstance(a, PrefixCond): 6976aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return -1 6986aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis if isinstance(b, PrefixCond): 6996aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return 1 7006aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # leave all unknown condition callables alone as equals 7016aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return 0 7026aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7035d62cfe070b63cdb3c80744ef9970facc008750cEzio Melotti if sys.version_info < (2, 6) : 7044907d27c1fcc7bd990715d3023932433076e152fJesus Cea conditionlist = conditions.items() 7054907d27c1fcc7bd990715d3023932433076e152fJesus Cea conditionlist.sort(cmp_conditions) 7064907d27c1fcc7bd990715d3023932433076e152fJesus Cea else : # Insertion Sort. Please, improve 7074907d27c1fcc7bd990715d3023932433076e152fJesus Cea conditionlist = [] 7084907d27c1fcc7bd990715d3023932433076e152fJesus Cea for i in conditions.items() : 7094907d27c1fcc7bd990715d3023932433076e152fJesus Cea for j, k in enumerate(conditionlist) : 7104907d27c1fcc7bd990715d3023932433076e152fJesus Cea r = cmp_conditions(k, i) 7114907d27c1fcc7bd990715d3023932433076e152fJesus Cea if r == 1 : 7124907d27c1fcc7bd990715d3023932433076e152fJesus Cea conditionlist.insert(j, i) 7134907d27c1fcc7bd990715d3023932433076e152fJesus Cea break 7144907d27c1fcc7bd990715d3023932433076e152fJesus Cea else : 7154907d27c1fcc7bd990715d3023932433076e152fJesus Cea conditionlist.append(i) 7166aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7176aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # Apply conditions to column data to find what we want 7186aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis cur = self.db.cursor() 7196aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis column_num = -1 720f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw for column, condition in conditionlist: 7216aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis column_num = column_num + 1 7226aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis searchkey = _search_col_data_key(table, column) 7236aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # speedup: don't linear search columns within loop 724f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if column in columns: 7256aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis savethiscolumndata = 1 # save the data for return 726f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw else: 7276aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis savethiscolumndata = 0 # data only used for selection 7286aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7296aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 7306aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis key, data = cur.set_range(searchkey) 731f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw while key[:len(searchkey)] == searchkey: 7326aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # extract the rowid from the key 7336aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis rowid = key[-_rowid_str_len:] 7346aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 73563b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou if not rowid in rejected_rowids: 7366aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # if no condition was specified or the condition 7376aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # succeeds, add row to our match list. 738f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if not condition or condition(data): 73963b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou if not rowid in matching_rowids: 740b2c7affbaab984915b9401105334afffeedf706dMartin v. Löwis matching_rowids[rowid] = {} 741f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if savethiscolumndata: 742b2c7affbaab984915b9401105334afffeedf706dMartin v. Löwis matching_rowids[rowid][column] = data 743f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw else: 74463b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou if rowid in matching_rowids: 7456aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis del matching_rowids[rowid] 7466aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis rejected_rowids[rowid] = rowid 7476aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7486aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis key, data = cur.next() 7496aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7504907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBError, dberror: 75163b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou if dberror.args[0] != db.DB_NOTFOUND: 75263b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou raise 7536aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis continue 7546aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7556aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis cur.close() 7566aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7576aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # we're done selecting rows, garbage collect the reject list 7586aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis del rejected_rowids 7596aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7606aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # extract any remaining desired column data from the 7616aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # database for the matching rows. 762f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if len(columns) > 0: 763f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw for rowid, rowdata in matching_rowids.items(): 764f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw for column in columns: 76563b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou if column in rowdata: 7666aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis continue 7676aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 7689a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw rowdata[column] = self.db.get( 7699a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw _data_key(table, column, rowid)) 7704907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBError, dberror: 7715d62cfe070b63cdb3c80744ef9970facc008750cEzio Melotti if sys.version_info < (2, 6) : 7724907d27c1fcc7bd990715d3023932433076e152fJesus Cea if dberror[0] != db.DB_NOTFOUND: 7734907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise 7744907d27c1fcc7bd990715d3023932433076e152fJesus Cea else : 7754907d27c1fcc7bd990715d3023932433076e152fJesus Cea if dberror.args[0] != db.DB_NOTFOUND: 7764907d27c1fcc7bd990715d3023932433076e152fJesus Cea raise 7776aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis rowdata[column] = None 7786aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7796aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # return the matches 7806aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis return matching_rowids 7816aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7826aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 783f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw def Drop(self, table): 784f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw """Remove an entire table from the database""" 7856aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 7866aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 7876aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = self.env.txn_begin() 7886aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7896aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # delete the column list 790afed3a4552e0df61477c322f60b10d3ae59edf1cGregory P. Smith self.db.delete(_columns_key(table), txn=txn) 7916aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7926aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis cur = self.db.cursor(txn) 7936aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 7946aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # delete all keys containing this tables column and row info 7956aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis table_key = _search_all_data_key(table) 796f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw while 1: 7976aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 7986aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis key, data = cur.set_range(table_key) 7994907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBNotFoundError: 8006aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis break 8016aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # only delete items in this table 802f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if key[:len(table_key)] != table_key: 8036aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis break 8046aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis cur.delete() 8056aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 8066aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # delete all rowids used by this table 8076aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis table_key = _search_rowid_key(table) 808f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw while 1: 8096aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 8106aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis key, data = cur.set_range(table_key) 8114907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBNotFoundError: 8126aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis break 8136aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # only delete items in this table 814f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if key[:len(table_key)] != table_key: 8156aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis break 8166aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis cur.delete() 8176aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 8186aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis cur.close() 8196aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 8206aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis # delete the tablename from the table name list 8219a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw tablelist = pickle.loads( 8224907d27c1fcc7bd990715d3023932433076e152fJesus Cea getattr(self.db, "get_bytes", self.db.get)(_table_names_key, 8234907d27c1fcc7bd990715d3023932433076e152fJesus Cea txn=txn, flags=db.DB_RMW)) 8246aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis try: 8256aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis tablelist.remove(table) 8266aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis except ValueError: 8279a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # hmm, it wasn't there, oh well, that's what we want. 8289a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw pass 8299a0d779c7d39ba5f4666eac7c3f913720198e0f8Barry Warsaw # delete 1st, incase we opened with DB_DUP 830afed3a4552e0df61477c322f60b10d3ae59edf1cGregory P. Smith self.db.delete(_table_names_key, txn=txn) 8314907d27c1fcc7bd990715d3023932433076e152fJesus Cea getattr(self.db, "put_bytes", self.db.put)(_table_names_key, 8324907d27c1fcc7bd990715d3023932433076e152fJesus Cea pickle.dumps(tablelist, 1), txn=txn) 8336aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 8346aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.commit() 8356aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn = None 8366aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 83763b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou if table in self.__tablecolumns: 8386aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis del self.__tablecolumns[table] 8396aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis 8404907d27c1fcc7bd990715d3023932433076e152fJesus Cea except db.DBError, dberror: 841f71de3e9a017d698be8ee4db3e2ec5fbc68bfc8cBarry Warsaw if txn: 8426aa4a1f29ca575e25fc595857b2a5168a02c9780Martin v. Löwis txn.abort() 84363b0cb2f39e26be7f6b636ddd40cc8d6a1400d51Antoine Pitrou raise TableDBError(dberror.args[1]) 844