home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 May / maximum-cd-2010-05.iso / DiscContents / boxee-0.9.20.10711.exe / system / python / Lib / bsddb / dbtables.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-07-20  |  18.4 KB  |  708 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.4)
  3.  
  4. _cvsid = '$Id: dbtables.py 36901 2004-08-08 00:54:21Z tim_one $'
  5. import re
  6. import sys
  7. import copy
  8. import xdrlib
  9. import random
  10. from types import ListType, StringType
  11. import cPickle as pickle
  12.  
  13. try:
  14.     from bsddb3.db import *
  15. except ImportError:
  16.     from bsddb.db import *
  17.  
  18.  
  19. class TableDBError(StandardError):
  20.     pass
  21.  
  22.  
  23. class TableAlreadyExists(TableDBError):
  24.     pass
  25.  
  26.  
  27. class Cond:
  28.     '''This condition matches everything'''
  29.     
  30.     def __call__(self, s):
  31.         return 1
  32.  
  33.  
  34.  
  35. class ExactCond(Cond):
  36.     '''Acts as an exact match condition function'''
  37.     
  38.     def __init__(self, strtomatch):
  39.         self.strtomatch = strtomatch
  40.  
  41.     
  42.     def __call__(self, s):
  43.         return s == self.strtomatch
  44.  
  45.  
  46.  
  47. class PrefixCond(Cond):
  48.     '''Acts as a condition function for matching a string prefix'''
  49.     
  50.     def __init__(self, prefix):
  51.         self.prefix = prefix
  52.  
  53.     
  54.     def __call__(self, s):
  55.         return s[:len(self.prefix)] == self.prefix
  56.  
  57.  
  58.  
  59. class PostfixCond(Cond):
  60.     '''Acts as a condition function for matching a string postfix'''
  61.     
  62.     def __init__(self, postfix):
  63.         self.postfix = postfix
  64.  
  65.     
  66.     def __call__(self, s):
  67.         return s[-len(self.postfix):] == self.postfix
  68.  
  69.  
  70.  
  71. class LikeCond(Cond):
  72.     """
  73.     Acts as a function that will match using an SQL 'LIKE' style
  74.     string.  Case insensitive and % signs are wild cards.
  75.     This isn't perfect but it should work for the simple common cases.
  76.     """
  77.     
  78.     def __init__(self, likestr, re_flags = re.IGNORECASE):
  79.         chars_to_escape = '.*+()[]?'
  80.         for char in chars_to_escape:
  81.             likestr = likestr.replace(char, '\\' + char)
  82.         
  83.         self.likestr = likestr.replace('%', '.*')
  84.         self.re = re.compile('^' + self.likestr + '$', re_flags)
  85.  
  86.     
  87.     def __call__(self, s):
  88.         return self.re.match(s)
  89.  
  90.  
  91. _table_names_key = '__TABLE_NAMES__'
  92. _columns = '._COLUMNS__'
  93.  
  94. def _columns_key(table):
  95.     return table + _columns
  96.  
  97. _data = '._DATA_.'
  98. _rowid = '._ROWID_.'
  99. _rowid_str_len = 8
  100.  
  101. def _data_key(table, col, rowid):
  102.     return table + _data + col + _data + rowid
  103.  
  104.  
  105. def _search_col_data_key(table, col):
  106.     return table + _data + col + _data
  107.  
  108.  
  109. def _search_all_data_key(table):
  110.     return table + _data
  111.  
  112.  
  113. def _rowid_key(table, rowid):
  114.     return table + _rowid + rowid + _rowid
  115.  
  116.  
  117. def _search_rowid_key(table):
  118.     return table + _rowid
  119.  
  120.  
  121. def contains_metastrings(s):
  122.     '''Verify that the given string does not contain any
  123.     metadata strings that might interfere with dbtables database operation.
  124.     '''
  125.     if s.find(_table_names_key) >= 0 and s.find(_columns) >= 0 and s.find(_data) >= 0 or s.find(_rowid) >= 0:
  126.         return 1
  127.     else:
  128.         return 0
  129.  
  130.  
  131. class bsdTableDB:
  132.     
  133.     def __init__(self, filename, dbhome, create = 0, truncate = 0, mode = 384, recover = 0, dbflags = 0):
  134.         '''bsdTableDB.open(filename, dbhome, create=0, truncate=0, mode=0600)
  135.         Open database name in the dbhome BerkeleyDB directory.
  136.         Use keyword arguments when calling this constructor.
  137.         '''
  138.         self.db = None
  139.         myflags = DB_THREAD
  140.         if create:
  141.             myflags |= DB_CREATE
  142.         
  143.         flagsforenv = DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN | dbflags
  144.         
  145.         try:
  146.             dbflags |= DB_AUTO_COMMIT
  147.         except AttributeError:
  148.             pass
  149.  
  150.         if recover:
  151.             flagsforenv = flagsforenv | DB_RECOVER
  152.         
  153.         self.env = DBEnv()
  154.         self.env.set_lk_detect(DB_LOCK_DEFAULT)
  155.         self.env.open(dbhome, myflags | flagsforenv)
  156.         if truncate:
  157.             myflags |= DB_TRUNCATE
  158.         
  159.         self.db = DB(self.env)
  160.         self.db.set_get_returns_none(1)
  161.         self.db.set_flags(DB_DUP)
  162.         self.db.open(filename, DB_BTREE, dbflags | myflags, mode)
  163.         self.dbfilename = filename
  164.         txn = self.env.txn_begin()
  165.         
  166.         try:
  167.             if not self.db.has_key(_table_names_key, txn):
  168.                 self.db.put(_table_names_key, pickle.dumps([], 1), txn = txn)
  169.         except:
  170.             txn.abort()
  171.             raise 
  172.  
  173.         txn.commit()
  174.         self._bsdTableDB__tablecolumns = { }
  175.  
  176.     
  177.     def __del__(self):
  178.         self.close()
  179.  
  180.     
  181.     def close(self):
  182.         if self.db is not None:
  183.             self.db.close()
  184.             self.db = None
  185.         
  186.         if self.env is not None:
  187.             self.env.close()
  188.             self.env = None
  189.         
  190.  
  191.     
  192.     def checkpoint(self, mins = 0):
  193.         
  194.         try:
  195.             self.env.txn_checkpoint(mins)
  196.         except DBIncompleteError:
  197.             pass
  198.  
  199.  
  200.     
  201.     def sync(self):
  202.         
  203.         try:
  204.             self.db.sync()
  205.         except DBIncompleteError:
  206.             pass
  207.  
  208.  
  209.     
  210.     def _db_print(self):
  211.         '''Print the database to stdout for debugging'''
  212.         print '******** Printing raw database for debugging ********'
  213.         cur = self.db.cursor()
  214.         
  215.         try:
  216.             (key, data) = cur.first()
  217.             while None:
  218.                 print repr({
  219.                     key: data })
  220.                 next = cur.next()
  221.                 if next:
  222.                     (key, data) = next
  223.                     continue
  224.                 cur.close()
  225.                 return None
  226.         except DBNotFoundError:
  227.             cur.close()
  228.  
  229.  
  230.     
  231.     def CreateTable(self, table, columns):
  232.         '''CreateTable(table, columns) - Create a new table in the database
  233.         raises TableDBError if it already exists or for other DB errors.
  234.         '''
  235.         txn = None
  236.         
  237.         try:
  238.             if contains_metastrings(table):
  239.                 raise ValueError('bad table name: contains reserved metastrings')
  240.             
  241.             for column in columns:
  242.                 if contains_metastrings(column):
  243.                     raise ValueError('bad column name: contains reserved metastrings')
  244.                     continue
  245.             
  246.             columnlist_key = _columns_key(table)
  247.             if self.db.has_key(columnlist_key):
  248.                 raise TableAlreadyExists, 'table already exists'
  249.             
  250.             txn = self.env.txn_begin()
  251.             self.db.put(columnlist_key, pickle.dumps(columns, 1), txn = txn)
  252.             tablelist = pickle.loads(self.db.get(_table_names_key, txn = txn, flags = DB_RMW))
  253.             tablelist.append(table)
  254.             self.db.delete(_table_names_key, txn)
  255.             self.db.put(_table_names_key, pickle.dumps(tablelist, 1), txn = txn)
  256.             txn.commit()
  257.             txn = None
  258.         except DBError:
  259.             dberror = None
  260.             if txn:
  261.                 txn.abort()
  262.             
  263.             raise TableDBError, dberror[1]
  264.  
  265.  
  266.     
  267.     def ListTableColumns(self, table):
  268.         """Return a list of columns in the given table.
  269.         [] if the table doesn't exist.
  270.         """
  271.         if contains_metastrings(table):
  272.             raise ValueError, 'bad table name: contains reserved metastrings'
  273.         
  274.         columnlist_key = _columns_key(table)
  275.         if not self.db.has_key(columnlist_key):
  276.             return []
  277.         
  278.         pickledcolumnlist = self.db.get(columnlist_key)
  279.         if pickledcolumnlist:
  280.             return pickle.loads(pickledcolumnlist)
  281.         else:
  282.             return []
  283.  
  284.     
  285.     def ListTables(self):
  286.         '''Return a list of tables in this database.'''
  287.         pickledtablelist = self.db.get(_table_names_key)
  288.         if pickledtablelist:
  289.             return pickle.loads(pickledtablelist)
  290.         else:
  291.             return []
  292.  
  293.     
  294.     def CreateOrExtendTable(self, table, columns):
  295.         '''CreateOrExtendTable(table, columns)
  296.  
  297.         - Create a new table in the database.
  298.         If a table of this name already exists, extend it to have any
  299.         additional columns present in the given list as well as
  300.         all of its current columns.
  301.         '''
  302.         
  303.         try:
  304.             self.CreateTable(table, columns)
  305.         except TableAlreadyExists:
  306.             txn = None
  307.             
  308.             try:
  309.                 columnlist_key = _columns_key(table)
  310.                 txn = self.env.txn_begin()
  311.                 oldcolumnlist = pickle.loads(self.db.get(columnlist_key, txn = txn, flags = DB_RMW))
  312.                 oldcolumnhash = { }
  313.                 for c in oldcolumnlist:
  314.                     oldcolumnhash[c] = c
  315.                 
  316.                 newcolumnlist = copy.copy(oldcolumnlist)
  317.                 for c in columns:
  318.                     if not oldcolumnhash.has_key(c):
  319.                         newcolumnlist.append(c)
  320.                         continue
  321.                 
  322.                 if newcolumnlist != oldcolumnlist:
  323.                     self.db.delete(columnlist_key, txn)
  324.                     self.db.put(columnlist_key, pickle.dumps(newcolumnlist, 1), txn = txn)
  325.                 
  326.                 txn.commit()
  327.                 txn = None
  328.                 self._bsdTableDB__load_column_info(table)
  329.             except DBError:
  330.                 dberror = None
  331.                 if txn:
  332.                     txn.abort()
  333.                 
  334.                 raise TableDBError, dberror[1]
  335.             except:
  336.                 None<EXCEPTION MATCH>DBError
  337.             
  338.  
  339.             None<EXCEPTION MATCH>DBError
  340.  
  341.  
  342.     
  343.     def __load_column_info(self, table):
  344.         '''initialize the self.__tablecolumns dict'''
  345.         
  346.         try:
  347.             tcolpickles = self.db.get(_columns_key(table))
  348.         except DBNotFoundError:
  349.             raise TableDBError, 'unknown table: %r' % (table,)
  350.  
  351.         if not tcolpickles:
  352.             raise TableDBError, 'unknown table: %r' % (table,)
  353.         
  354.         self._bsdTableDB__tablecolumns[table] = pickle.loads(tcolpickles)
  355.  
  356.     
  357.     def __new_rowid(self, table, txn):
  358.         '''Create a new unique row identifier'''
  359.         unique = 0
  360.         while not unique:
  361.             p = xdrlib.Packer()
  362.             p.pack_int(int(random.random() * 2147483647))
  363.             p.pack_int(int(random.random() * 2147483647))
  364.             newid = p.get_buffer()
  365.             
  366.             try:
  367.                 self.db.put(_rowid_key(table, newid), None, txn = txn, flags = DB_NOOVERWRITE)
  368.             except DBKeyExistError:
  369.                 continue
  370.  
  371.             unique = 1
  372.         return newid
  373.  
  374.     
  375.     def Insert(self, table, rowdict):
  376.         '''Insert(table, datadict) - Insert a new row into the table
  377.         using the keys+values from rowdict as the column values.
  378.         '''
  379.         txn = None
  380.         
  381.         try:
  382.             if not self.db.has_key(_columns_key(table)):
  383.                 raise TableDBError, 'unknown table'
  384.             
  385.             if not self._bsdTableDB__tablecolumns.has_key(table):
  386.                 self._bsdTableDB__load_column_info(table)
  387.             
  388.             for column in rowdict.keys():
  389.                 if not self._bsdTableDB__tablecolumns[table].count(column):
  390.                     raise TableDBError, 'unknown column: %r' % (column,)
  391.                     continue
  392.             
  393.             txn = self.env.txn_begin()
  394.             rowid = self._bsdTableDB__new_rowid(table, txn = txn)
  395.             for column, dataitem in rowdict.items():
  396.                 self.db.put(_data_key(table, column, rowid), dataitem, txn = txn)
  397.             
  398.             txn.commit()
  399.             txn = None
  400.         except DBError:
  401.             dberror = None
  402.             info = sys.exc_info()
  403.             if txn:
  404.                 txn.abort()
  405.                 self.db.delete(_rowid_key(table, rowid))
  406.             
  407.             raise TableDBError, dberror[1], info[2]
  408.  
  409.  
  410.     
  411.     def Modify(self, table, conditions = { }, mappings = { }):
  412.         """Modify(table, conditions) - Modify in rows matching 'conditions'
  413.         using mapping functions in 'mappings'
  414.         * conditions is a dictionary keyed on column names
  415.         containing condition functions expecting the data string as an
  416.         argument and returning a boolean.
  417.         * mappings is a dictionary keyed on column names containint condition
  418.         functions expecting the data string as an argument and returning the
  419.         new string for that column.
  420.         """
  421.         
  422.         try:
  423.             matching_rowids = self._bsdTableDB__Select(table, [], conditions)
  424.             columns = mappings.keys()
  425.             for rowid in matching_rowids.keys():
  426.                 txn = None
  427.                 
  428.                 try:
  429.                     for column in columns:
  430.                         txn = self.env.txn_begin()
  431.                         
  432.                         try:
  433.                             dataitem = self.db.get(_data_key(table, column, rowid), txn)
  434.                             self.db.delete(_data_key(table, column, rowid), txn)
  435.                         except DBNotFoundError:
  436.                             dataitem = None
  437.  
  438.                         dataitem = mappings[column](dataitem)
  439.                         if dataitem != None:
  440.                             self.db.put(_data_key(table, column, rowid), dataitem, txn = txn)
  441.                         
  442.                         txn.commit()
  443.                         txn = None
  444.                 continue
  445.                 except DBError:
  446.                     dberror = None
  447.                     if txn:
  448.                         txn.abort()
  449.                     
  450.                     raise 
  451.                     continue
  452.                 
  453.  
  454.         except DBError:
  455.             dberror = None
  456.             raise TableDBError, dberror[1]
  457.  
  458.  
  459.     
  460.     def Delete(self, table, conditions = { }):
  461.         '''Delete(table, conditions) - Delete items matching the given
  462.         conditions from the table.
  463.         * conditions is a dictionary keyed on column names
  464.         containing condition functions expecting the data string as an
  465.         argument and returning a boolean.
  466.         '''
  467.         
  468.         try:
  469.             matching_rowids = self._bsdTableDB__Select(table, [], conditions)
  470.             columns = self._bsdTableDB__tablecolumns[table]
  471.             for rowid in matching_rowids.keys():
  472.                 txn = None
  473.                 
  474.                 try:
  475.                     txn = self.env.txn_begin()
  476.                     for column in columns:
  477.                         
  478.                         try:
  479.                             self.db.delete(_data_key(table, column, rowid), txn)
  480.                         continue
  481.                         except DBNotFoundError:
  482.                             continue
  483.                         
  484.  
  485.                     
  486.                     
  487.                     try:
  488.                         self.db.delete(_rowid_key(table, rowid), txn)
  489.                     except DBNotFoundError:
  490.                         None<EXCEPTION MATCH>DBNotFoundError
  491.                         None<EXCEPTION MATCH>DBNotFoundError
  492.                     except:
  493.                         None<EXCEPTION MATCH>DBNotFoundError
  494.  
  495.                     txn.commit()
  496.                     txn = None
  497.                 continue
  498.                 except DBError:
  499.                     dberror = None
  500.                     if txn:
  501.                         txn.abort()
  502.                     
  503.                     raise 
  504.                     continue
  505.                 
  506.  
  507.         except DBError:
  508.             dberror = None
  509.             raise TableDBError, dberror[1]
  510.  
  511.  
  512.     
  513.     def Select(self, table, columns, conditions = { }):
  514.         '''Select(table, conditions) - retrieve specific row data
  515.         Returns a list of row column->value mapping dictionaries.
  516.         * columns is a list of which column data to return.  If
  517.           columns is None, all columns will be returned.
  518.         * conditions is a dictionary keyed on column names
  519.           containing callable conditions expecting the data string as an
  520.           argument and returning a boolean.
  521.         '''
  522.         
  523.         try:
  524.             if not self._bsdTableDB__tablecolumns.has_key(table):
  525.                 self._bsdTableDB__load_column_info(table)
  526.             
  527.             if columns is None:
  528.                 columns = self._bsdTableDB__tablecolumns[table]
  529.             
  530.             matching_rowids = self._bsdTableDB__Select(table, columns, conditions)
  531.         except DBError:
  532.             dberror = None
  533.             raise TableDBError, dberror[1]
  534.  
  535.         return matching_rowids.values()
  536.  
  537.     
  538.     def __Select(self, table, columns, conditions):
  539.         '''__Select() - Used to implement Select and Delete (above)
  540.         Returns a dictionary keyed on rowids containing dicts
  541.         holding the row data for columns listed in the columns param
  542.         that match the given conditions.
  543.         * conditions is a dictionary keyed on column names
  544.         containing callable conditions expecting the data string as an
  545.         argument and returning a boolean.
  546.         '''
  547.         if not self._bsdTableDB__tablecolumns.has_key(table):
  548.             self._bsdTableDB__load_column_info(table)
  549.         
  550.         if columns is None:
  551.             columns = self.tablecolumns[table]
  552.         
  553.         for column in columns + conditions.keys():
  554.             if not self._bsdTableDB__tablecolumns[table].count(column):
  555.                 raise TableDBError, 'unknown column: %r' % (column,)
  556.                 continue
  557.         
  558.         matching_rowids = { }
  559.         rejected_rowids = { }
  560.         
  561.         def cmp_conditions(atuple, btuple):
  562.             a = atuple[1]
  563.             b = btuple[1]
  564.             if type(a) is type(b):
  565.                 if isinstance(a, PrefixCond) and isinstance(b, PrefixCond):
  566.                     return cmp(len(b.prefix), len(a.prefix))
  567.                 
  568.                 if isinstance(a, LikeCond) and isinstance(b, LikeCond):
  569.                     return cmp(len(b.likestr), len(a.likestr))
  570.                 
  571.                 return 0
  572.             
  573.             if isinstance(a, ExactCond):
  574.                 return -1
  575.             
  576.             if isinstance(b, ExactCond):
  577.                 return 1
  578.             
  579.             if isinstance(a, PrefixCond):
  580.                 return -1
  581.             
  582.             if isinstance(b, PrefixCond):
  583.                 return 1
  584.             
  585.             return 0
  586.  
  587.         conditionlist = conditions.items()
  588.         conditionlist.sort(cmp_conditions)
  589.         cur = self.db.cursor()
  590.         column_num = -1
  591.         for column, condition in conditionlist:
  592.             column_num = column_num + 1
  593.             searchkey = _search_col_data_key(table, column)
  594.             if column in columns:
  595.                 savethiscolumndata = 1
  596.             else:
  597.                 savethiscolumndata = 0
  598.             
  599.             try:
  600.                 (key, data) = cur.set_range(searchkey)
  601.                 while key[:len(searchkey)] == searchkey:
  602.                     rowid = key[-_rowid_str_len:]
  603.                     if not rejected_rowids.has_key(rowid):
  604.                         if not condition or condition(data):
  605.                             if not matching_rowids.has_key(rowid):
  606.                                 matching_rowids[rowid] = { }
  607.                             
  608.                             if savethiscolumndata:
  609.                                 matching_rowids[rowid][column] = data
  610.                             
  611.                         elif matching_rowids.has_key(rowid):
  612.                             del matching_rowids[rowid]
  613.                         
  614.                         rejected_rowids[rowid] = rowid
  615.                     
  616.                     (key, data) = cur.next()
  617.             continue
  618.             except DBError:
  619.                 dberror = None
  620.                 if dberror[0] != DB_NOTFOUND:
  621.                     raise 
  622.                     continue
  623.                 continue
  624.                 continue
  625.             
  626.  
  627.         
  628.         cur.close()
  629.         del rejected_rowids
  630.         if len(columns) > 0:
  631.             for rowid, rowdata in matching_rowids.items():
  632.                 for column in columns:
  633.                     if rowdata.has_key(column):
  634.                         continue
  635.                     
  636.                     
  637.                     try:
  638.                         rowdata[column] = self.db.get(_data_key(table, column, rowid))
  639.                     continue
  640.                     except DBError:
  641.                         dberror = None
  642.                         if dberror[0] != DB_NOTFOUND:
  643.                             raise 
  644.                         
  645.                         rowdata[column] = None
  646.                         continue
  647.                     
  648.  
  649.                 
  650.             
  651.         
  652.         return matching_rowids
  653.  
  654.     
  655.     def Drop(self, table):
  656.         '''Remove an entire table from the database'''
  657.         txn = None
  658.         
  659.         try:
  660.             txn = self.env.txn_begin()
  661.             self.db.delete(_columns_key(table), txn)
  662.             cur = self.db.cursor(txn)
  663.             table_key = _search_all_data_key(table)
  664.             while None:
  665.                 
  666.                 try:
  667.                     (key, data) = cur.set_range(table_key)
  668.                 except DBNotFoundError:
  669.                     break
  670.  
  671.                 if key[:len(table_key)] != table_key:
  672.                     break
  673.                 
  674.             table_key = _search_rowid_key(table)
  675.             while None:
  676.                 
  677.                 try:
  678.                     (key, data) = cur.set_range(table_key)
  679.                 except DBNotFoundError:
  680.                     break
  681.  
  682.                 if key[:len(table_key)] != table_key:
  683.                     break
  684.                 
  685.             cur.close()
  686.             tablelist = pickle.loads(self.db.get(_table_names_key, txn = txn, flags = DB_RMW))
  687.             
  688.             try:
  689.                 tablelist.remove(table)
  690.             except ValueError:
  691.                 pass
  692.  
  693.             self.db.delete(_table_names_key, txn)
  694.             self.db.put(_table_names_key, pickle.dumps(tablelist, 1), txn = txn)
  695.             txn.commit()
  696.             txn = None
  697.             if self._bsdTableDB__tablecolumns.has_key(table):
  698.                 del self._bsdTableDB__tablecolumns[table]
  699.         except DBError:
  700.             dberror = None
  701.             if txn:
  702.                 txn.abort()
  703.             
  704.             raise TableDBError, dberror[1]
  705.  
  706.  
  707.  
  708.