| 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(). |
|---|
| 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)) |
|---|