Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

Changeset 175

Show
Ignore:
Timestamp:
03/02/06 15:39:19
Author:
fumanchu
Message:

Initial implementation of database-level sequencing. Only MSAccess + UnitSequencerInteger? is currently supported. More SM's to follow soon.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/storage/db.py

    r174 r175  
    10281028     
    10291029    def reserve(self, unit): 
    1030         """reserve(unit). -> Reserve a persistent slot for unit. 
    1031          
    1032         Notice in particular that we do not use the auto-number or 
    1033         sequence generation capabilities within some databases, etc. 
    1034         The identifiers should be supplied by UnitSequencers via reserve(). 
     1030        """reserve(unit). -> Reserve a persistent slot for unit.""" 
     1031        self.reserve_lock.acquire() 
     1032        try: 
     1033            # First, see if our db subclass has a handler that 
     1034            # uses the DB to generate the appropriate identifier(s). 
     1035            seqclass = unit.sequencer.__class__.__name__ 
     1036            seq_handler = getattr(self, "_seq_%s" % seqclass, None) 
     1037            if seq_handler: 
     1038                seq_handler(unit) 
     1039            else: 
     1040                self._manual_reserve(unit) 
     1041            unit.cleanse() 
     1042        finally: 
     1043            self.reserve_lock.release() 
     1044     
     1045    def _manual_reserve(self, unit): 
     1046        """Use when the DB cannot automatically generate an identifier. 
     1047        The identifiers will be supplied by UnitSequencer.assign(). 
    10351048        """ 
     1049         
    10361050        cls = unit.__class__ 
    10371051        clsname = cls.__name__ 
    10381052        tablename = self.table_name(clsname) 
    1039         self.reserve_lock.acquire() 
    1040         try: 
    1041             if not unit.sequencer.valid_id(unit.identity()): 
    1042                 # Examine all existing IDs and grant the "next" one. 
    1043                 id_fields = [self.column_name(clsname, prop.key) 
    1044                              for prop in cls.identifiers] 
    1045                 data, cols = self.fetch('SELECT %s FROM %s;' % 
    1046                                         (', '.join(id_fields), tablename)) 
    1047                 if data: 
    1048                     # sqlite 2, for example, has empty cols tuple if no data. 
    1049                     coerce = self.fromAdapter.coerce 
    1050                     coltypes = [cols[x][1] for x in xrange(len(cols))] 
    1051                     expectedTypes = [prop.type for prop in cls.identifiers] 
    1052                     newdata = [] 
    1053                     for row in data: 
    1054                         newrow = [] 
    1055                         for x, cell in enumerate(row): 
    1056                             newrow.append(coerce(cell, coltypes[x], 
    1057                                                  expectedTypes[x])) 
    1058                         newdata.append(newrow) 
    1059                     data = newdata 
    1060                     del newdata 
    1061                 cls.sequencer.assign(unit, data) 
    1062                 del data 
    1063                 del cols 
    1064              
    1065             fields = [] 
    1066             values = [] 
    1067             for key in cls.properties(): 
    1068                 subtype = self.expanded_columns.get((clsname, key)) 
    1069                 if subtype: 
    1070                     self.save_expanded(unit, key, subtype) 
    1071                 else: 
    1072                     val = self.toAdapter.coerce(getattr(unit, key)) 
    1073                     fields.append(self.column_name(clsname, key)) 
    1074                     values.append(val) 
    1075              
    1076             fields = ", ".join(fields) 
    1077             try: 
    1078                 values = ", ".join(values) 
    1079             except UnicodeDecodeError: 
    1080                 print values 
    1081                 raise 
    1082             self.execute('INSERT INTO %s (%s) VALUES (%s);' % 
    1083                          (str(tablename), fields, values)) 
    1084             unit.cleanse() 
    1085         finally: 
    1086             self.reserve_lock.release() 
     1053        if not unit.sequencer.valid_id(unit.identity()): 
     1054            # Examine all existing IDs and grant the "next" one. 
     1055            id_fields = [self.column_name(clsname, prop.key) 
     1056                         for prop in cls.identifiers] 
     1057            data, cols = self.fetch('SELECT %s FROM %s;' % 
     1058                                    (', '.join(id_fields), tablename)) 
     1059            if data: 
     1060                # sqlite 2, for example, has empty cols tuple if no data. 
     1061                coerce = self.fromAdapter.coerce 
     1062                coltypes = [cols[x][1] for x in xrange(len(cols))] 
     1063                expectedTypes = [prop.type for prop in cls.identifiers] 
     1064                newdata = [] 
     1065                for row in data: 
     1066                    newrow = [] 
     1067                    for x, cell in enumerate(row): 
     1068                        newrow.append(coerce(cell, coltypes[x], 
     1069                                             expectedTypes[x])) 
     1070                    newdata.append(newrow) 
     1071                data = newdata 
     1072                del newdata 
     1073            cls.sequencer.assign(unit, data) 
     1074            del data 
     1075            del cols 
     1076         
     1077        fields = [] 
     1078        values = [] 
     1079        for key in cls.properties(): 
     1080            subtype = self.expanded_columns.get((clsname, key)) 
     1081            if subtype: 
     1082                self.save_expanded(unit, key, subtype) 
     1083            else: 
     1084                val = self.toAdapter.coerce(getattr(unit, key)) 
     1085                fields.append(self.column_name(clsname, key)) 
     1086                values.append(val) 
     1087         
     1088        fields = ", ".join(fields) 
     1089        values = ", ".join(values) 
     1090        self.execute('INSERT INTO %s (%s) VALUES (%s);' % 
     1091                     (str(tablename), fields, values)) 
    10871092     
    10881093    def id_clause(self, unit): 
     
    13801385        for key in cls.properties(): 
    13811386            fields.append('%s %s' % (self.column_name(clsname, key), 
    1382                                       typename(cls, key))) 
     1387                                     typename(cls, key))) 
    13831388        self.execute('CREATE TABLE %s (%s);' % (tablename, ", ".join(fields))) 
    13841389         
  • trunk/storage/storeado.py

    r174 r175  
    623623        bytes = int(prop.hints.get('bytes', '4')) 
    624624        if bytes == 1: 
    625             return "BIT" 
     625            typename = "BIT" 
    626626        else: 
    627             return "INTEGER" 
     627            typename = "INTEGER" 
     628        if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
     629            for prop in cls.identifiers: 
     630                if prop.key == key: 
     631                    typename = "AUTOINCREMENT" 
     632                    break 
     633        return typename 
    628634     
    629635    def coerce_long(self, cls, key): 
    630636        prop = getattr(cls, key) 
    631637        bytes = int(prop.hints.get('bytes', 0)) 
    632         return self.numeric_type(cls, key, precision, 0) 
     638        typename = self.numeric_type(cls, key, precision, 0) 
     639        if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
     640            for prop in cls.identifiers: 
     641                if prop.key == key: 
     642                    typename = "AUTOINCREMENT" 
     643                    break 
     644        return typename 
    633645     
    634646    def coerce_str(self, cls, key): 
     
    705717        if os.path.exists(self.dbname): 
    706718            os.remove(self.dbname) 
     719     
     720    def _seq_UnitSequencerInteger(self, unit): 
     721        """Reserve a unit using the table's AUTOINCREMENT field.""" 
     722        cls = unit.__class__ 
     723        clsname = cls.__name__ 
     724        tablename = self.table_name(clsname) 
     725         
     726        fields = [] 
     727        values = [] 
     728        # We have to delay expanded tables until we have an ID. 
     729        to_expand = [] 
     730        idkeys = [prop.key for prop in cls.identifiers] 
     731        for key in cls.properties(): 
     732            if key in idkeys: 
     733                # Skip this field, since we're using AUTOINCREMENT 
     734                continue 
     735            subtype = self.expanded_columns.get((clsname, key)) 
     736            if subtype: 
     737                to_expand.append((key, subtype)) 
     738            else: 
     739                val = self.toAdapter.coerce(getattr(unit, key)) 
     740                fields.append(self.column_name(clsname, key)) 
     741                values.append(val) 
     742         
     743        fields = ", ".join(fields) 
     744        try: 
     745            values = ", ".join(values) 
     746        except UnicodeDecodeError: 
     747            print values 
     748            raise 
     749        self.execute('INSERT INTO %s (%s) VALUES (%s);' % 
     750                     (str(tablename), fields, values)) 
     751         
     752        # Now retrieve the record and grab the new ID. This is safe 
     753        # because db.reserve has a mutex. 
     754        data, col_defs = self.fetch("SELECT @@IDENTITY") 
     755        setattr(unit, cls.identifiers[0].key, data[0][0]) 
     756         
     757        # Now that we have an ID, save our expanded tables. 
     758        for key, subtype in to_expand: 
     759            self.save_expanded(unit, key, subtype) 
    707760 
    708761