Changeset 2
- Timestamp:
- 02/11/07 02:31:31
- Files:
-
- trunk/geniusql/__init__.py (modified) (7 diffs)
- trunk/geniusql/providers/__init__.py (modified) (1 diff)
- trunk/geniusql/providers/ado.py (modified) (2 diffs)
- trunk/geniusql/providers/mysql.py (modified) (1 diff)
- trunk/geniusql/providers/psycopg.py (modified) (11 diffs)
- trunk/geniusql/providers/pypgsql.py (modified) (1 diff)
- trunk/geniusql/providers/sqlite.py (modified) (28 diffs)
- trunk/geniusql/select.py (modified) (1 diff)
- trunk/geniusql/test (added)
- trunk/geniusql/test/__init__.py (added)
- trunk/geniusql/test/test.py (added)
- trunk/geniusql/test/test_firebird.py (added)
- trunk/geniusql/test/test_msaccess.py (added)
- trunk/geniusql/test/test_mysql.py (added)
- trunk/geniusql/test/test_psycopg.py (added)
- trunk/geniusql/test/test_pypgsql.py (added)
- trunk/geniusql/test/test_sqlite.py (added)
- trunk/geniusql/test/test_sqlserver.py (added)
- trunk/geniusql/test/testdb (added)
- trunk/geniusql/test/tools.py (added)
- trunk/geniusql/test/zoo_fixture.py (added)
- trunk/geniusql/xray.py (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/geniusql/__init__.py
r1 r2 15 15 """ 16 16 17 __version__ = "1.0alpha" 18 17 19 import threading 20 from geniusql import xray 18 21 19 22 from geniusql import errors, typerefs … … 23 26 from geniusql.isolation import * 24 27 from geniusql.select import * 28 29 from geniusql import providers 30 31 32 def db(cls, name, options): 33 """Create a Database model object for the given cls, name, and options. 34 35 cls: Either a subclass of geniusql.Database or a 'shortcut name' 36 registered in geniusql.providers.providers. 37 name: the database name as used by the underlying database. 38 39 This function does not call CREATE DATABASE, nor should it open any 40 database connections. It simply instantiates the proper Database class. 41 """ 42 if isinstance(cls, basestring): 43 try: 44 cls = providers.providers[cls] 45 except KeyError: 46 pass 47 48 if isinstance(cls, basestring): 49 cls = xray.classes(cls) 50 51 opts = dict([(str(k), v) for k, v in options.iteritems()]) 52 53 return cls(name, **opts) 25 54 26 55 … … 126 155 self.autoincrement = False 127 156 self.sequence_name = None 128 self.initial = 0157 self.initial = 1 129 158 130 159 self.imperfect_type = False … … 162 191 set the 'db' arg late. 163 192 indices: a dict-like IndexSet of Index objects. 164 references: a dict of the form: {name: (near Key, farTable, farKey)}.193 references: a dict of the form: {name: (nearColKey, farTableKey, farColKey)}. 165 194 """ 166 195 … … 617 646 return self.sql_name(columnkey) 618 647 619 def make_column(self, tablekey, columnkey, pytype , default, hints):648 def make_column(self, tablekey, columnkey, pytype=unicode, default=None, hints=None): 620 649 """Return a Column object from the given table and column keys.""" 621 650 name = self.column_name(tablekey, columnkey) 622 col = Column(name, self.quote(name), None, default, hints.copy()) 651 if hints is None: 652 hints = {} 653 else: 654 hints = hints.copy() 655 col = Column(name, self.quote(name), None, default, hints) 623 656 col.dbtype = self.typeadapter.coerce(col, pytype) 624 657 pytype2 = self.python_type(col.dbtype) … … 631 664 # to DB table names, override this method. 632 665 return self.sql_name(self.Prefix + key) 666 667 def make_table(self, name): 668 """Create and return a Table object for the given name.""" 669 name = self.table_name(name) 670 return self.tableclass(name, self.quote(name)) 633 671 634 672 def make_index(self, tablekey, columnkey): … … 846 884 raise errors.TransactionLock("Unlock called inside transaction.") 847 885 del self.transactions[key] 848 849 886 887 # OLTP/CRUD # 888 889 def id_clause(self, tablekey, **inputs): 890 """Return an SQL expression for the identifiers of the given table.""" 891 t = self[tablekey] 892 coerce = self.adaptertosql.coerce 893 pairs = [] 894 for key, col in t.iteritems(): 895 if col.key: 896 val = coerce(inputs[key], col.dbtype) 897 pairs.append("%s = %s" % (col.qname, val)) 898 return " AND ".join(pairs) 899 900 def insert(self, tablekey, **inputs): 901 """Insert a row and return {idcolkey: newid}.""" 902 t = self[tablekey] 903 904 fields = [] 905 idkeys = [] 906 values = [] 907 for key, col in t.iteritems(): 908 if col.autoincrement: 909 # Skip this field, since we're using a sequencer 910 idkeys.append(key) 911 continue 912 if key in inputs: 913 val = self.adaptertosql.coerce(inputs[key], col.dbtype) 914 fields.append(col.qname) 915 values.append(val) 916 917 transconn = self.get_transaction() 918 919 fields = ", ".join(fields) 920 values = ", ".join(values) 921 self.execute('INSERT INTO %s (%s) VALUES (%s);' % 922 (t.qname, fields, values), transconn) 923 924 return self._grab_new_ids(t, idkeys, transconn) 925 926 def _grab_new_ids(self, table, idkeys): 927 raise NotImplementedError 928 929 def save(self, tablekey, **inputs): 930 """Update a row using the given inputs.""" 931 t = self[tablekey] 932 933 parms = [] 934 coerce = self.adaptertosql.coerce 935 for key, val in inputs.iteritems(): 936 col = t[key] 937 val = coerce(val, col.dbtype) 938 parms.append('%s = %s' % (col.qname, val)) 939 940 if parms: 941 sql = ('UPDATE %s SET %s WHERE %s;' % 942 (t.qname, ", ".join(parms), self.id_clause(tablekey, **inputs))) 943 self.execute(sql, self.get_transaction()) 944 trunk/geniusql/providers/__init__.py
r1 r2 41 41 42 42 providers = { 43 "access": "geniusql.providers.ado. StorageManagerADO_MSAccess",44 "msaccess": "geniusql.providers.ado. StorageManagerADO_MSAccess",43 "access": "geniusql.providers.ado.MSAccessDatabase", 44 "msaccess": "geniusql.providers.ado.MSAccessDatabase", 45 45 46 "firebird": "geniusql.providers.firebird. StorageManagerFirebird",47 "mysql": "geniusql.providers.mysql. StorageManagerMySQL",46 "firebird": "geniusql.providers.firebird.FirebirdDatabase", 47 "mysql": "geniusql.providers.mysql.MySQLDatabase", 48 48 49 "postgres": "geniusql.providers.pypgsql. StorageManagerPgSQL",50 "postgresql": "geniusql.providers.pypgsql. StorageManagerPgSQL",51 "pypgsql": "geniusql.providers.pypgsql. StorageManagerPgSQL",49 "postgres": "geniusql.providers.pypgsql.PgDatabase", 50 "postgresql": "geniusql.providers.pypgsql.PgDatabase", 51 "pypgsql": "geniusql.providers.pypgsql.PgDatabase", 52 52 53 "psycopg": "geniusql.providers.psycopg. StorageManagerPsycoPg",54 "psycopg2": "geniusql.providers.psycopg. StorageManagerPsycoPg",53 "psycopg": "geniusql.providers.psycopg.PsycoPgDatabase", 54 "psycopg2": "geniusql.providers.psycopg.PsycoPgDatabase", 55 55 56 "sqlite": "geniusql.providers.sqlite.S torageManagerSQLite",56 "sqlite": "geniusql.providers.sqlite.SQLiteDatabase", 57 57 58 "sqlserver": "geniusql.providers.ado.S torageManagerADO_SQLServer",59 "mssql": "geniusql.providers.ado.S torageManagerADO_SQLServer",58 "sqlserver": "geniusql.providers.ado.SQLServerDatabase", 59 "mssql": "geniusql.providers.ado.SQLServerDatabase", 60 60 } trunk/geniusql/providers/ado.py
r1 r2 917 917 return '%s %s%s' % (column.qname, dbtype, clause) 918 918 919 def _grab_new_ids(self, table, idkeys, conn): 920 """Insert a row using the table's SERIAL field.""" 921 # For some reason, using SCOPE_IDENTITY or IDENTITY failed (returned 922 # None) when retrieving ID's just after a 99-thread-test ran. Moving 923 # the multithreading test fixed it. IDENT_CURRENT worked regardless. 924 data, _ = self.fetch("SELECT IDENT_CURRENT('%s');" % table.qname, conn) 925 return {idkeys[0]: data[0][0]} 926 919 927 # Transactions # 920 928 … … 1127 1135 return '%s %s' % (column.qname, dbtype) 1128 1136 1137 def _grab_new_ids(self, table, idkeys, conn): 1138 data, _ = self.fetch("SELECT @@IDENTITY;", conn) 1139 return {idkeys[0]: data[0][0]} 1140 1129 1141 # Connecting # 1130 1142 trunk/geniusql/providers/mysql.py
r1 r2 1 1 """ 2 References the MySQLdb package at:2 Uses the MySQLdb package at: 3 3 http://sourceforge.net/projects/mysql-python 4 4 trunk/geniusql/providers/psycopg.py
r1 r2 20 20 replace_unoct = lambda m: chr(int(m.group(1), 8)) 21 21 22 import dejavu 23 from dejavu import errors 24 from dejavu.storage import db 25 26 27 class AdapterToPsycoPg(db.AdapterToSQL): 22 import geniusql 23 from geniusql import errors, typerefs 24 25 26 class AdapterToPsycoPg(geniusql.AdapterToSQL): 28 27 29 28 like_escapes = [("%", r"\\%"), ("_", r"\\_")] … … 72 71 73 72 74 class AdapterFromPsycoPg( db.AdapterFromDB):73 class AdapterFromPsycoPg(geniusql.AdapterFromDB): 75 74 76 75 def coerce_any_to_str(self, value): … … 92 91 93 92 94 class PsycoPgDecompiler( db.SQLDecompiler):93 class PsycoPgDecompiler(geniusql.SQLDecompiler): 95 94 96 95 def dejavu_icontainedby(self, op1, op2): 97 if isinstance(op1, db.ConstWrapper):96 if isinstance(op1, geniusql.ConstWrapper): 98 97 # Looking for text in a field. Use ILike (reverse terms). 99 98 return op2 + " ILIKE '%" + self.adapter.escape_like(op1) + "%'" … … 124 123 125 124 126 class PsycoPgIndexSet( db.IndexSet):125 class PsycoPgIndexSet(geniusql.IndexSet): 127 126 128 127 def __delitem__(self, key): … … 137 136 138 137 139 class PsycoPgTable( db.Table):138 class PsycoPgTable(geniusql.Table): 140 139 141 140 indexsetclass = PsycoPgIndexSet 142 141 143 142 144 class PsycoPgDatabase( db.Database):143 class PsycoPgDatabase(geniusql.Database): 145 144 146 145 sql_name_max_length = 63 … … 217 216 else: 218 217 dbtype = None 219 c = db.Column(row[0], self.quote(row[0]), dbtype,220 key=row[2] in indices)218 c = geniusql.Column(row[0], self.quote(row[0]), dbtype, 219 key=row[2] in indices) 221 220 222 221 if dbtype in ('FLOAT4', 'FLOAT8'): … … 279 278 "WHERE attrelid = %s AND attnum = %s" 280 279 % (table_OID, col), conn=conn) 281 i = db.Index(row[0], self.quote(row[0]), tablename,282 d[0][0], bool(row[3]))280 i = geniusql.Index(row[0], self.quote(row[0]), tablename, 281 d[0][0], bool(row[3])) 283 282 indices.append(i) 284 283 … … 297 296 return float 298 297 elif dbtype.startswith('NUMERIC'): 299 if db.decimal:300 return db.decimal.Decimal301 elif db.fixedpoint:302 return db.fixedpoint.FixedPoint298 if typerefs.decimal: 299 return typerefs.decimal.Decimal 300 elif typerefs.fixedpoint: 301 return typerefs.fixedpoint.FixedPoint 303 302 elif dbtype == 'DATE': 304 303 return datetime.date … … 355 354 356 355 def sql_name(self, name): 357 name = db.Database.sql_name(self, name)356 name = geniusql.Database.sql_name(self, name) 358 357 if not self.quote_all: 359 358 name = name.lower() … … 369 368 except _psycopg.DatabaseError, x: 370 369 if x.args[0].startswith('could not connect'): 371 raise db.OutOfConnectionsError()370 raise errors.OutOfConnectionsError() 372 371 raise 373 372 … … 458 457 return "%s\npsycopg version: %s" % (v, _psycopg.__version__) 459 458 460 461 462 class StorageManagerPsycoPg(db.StorageManagerDB):463 """StoreManager to save and retrieve Units via psycopg2."""464 465 databaseclass = PsycoPgDatabase466 467 def __init__(self, arena, allOptions={}):468 for atom in allOptions['Connect'].split(" "):469 k, v = atom.split("=", 1)470 if k == "dbname":471 allOptions['name'] = v472 db.StorageManagerDB.__init__(self, arena, allOptions)473 474 def _seq_UnitSequencerInteger(self, unit):475 """Reserve a unit using the table's SERIAL field."""476 cls = unit.__class__477 t = self.db[cls.__name__]478 479 fields = []480 values = []481 for key in cls.properties:482 col = t[key]483 if col.autoincrement:484 # Skip this field, since we're using a sequencer485 continue486 val = self.db.adaptertosql.coerce(getattr(unit, key), col.dbtype)487 fields.append(col.qname)488 values.append(val)489 490 transconn = self.db.get_transaction()491 492 fields = ", ".join(fields)493 values = ", ".join(values)494 self.db.execute('INSERT INTO %s (%s) VALUES (%s);' %495 (t.qname, fields, values), transconn)496 497 # Grab the new ID. This is threadsafe because db.reserve has a mutex.498 idcol = cls.identifiers[0]499 seqname = t[idcol].sequence_name500 data, col_defs = self.db.fetch("SELECT last_value FROM %s;" % seqname,501 transconn)502 setattr(unit, idcol, data[0][0])503 trunk/geniusql/providers/pypgsql.py
r1 r2 415 415 c.finish() 416 416 return v 417 417 418 def _grab_new_ids(self, table, idkeys, conn): 419 """Insert a row using the table's SERIAL field.""" 420 newids = {} 421 for idkey in idkeys: 422 col = table[idkey] 423 seq = col.sequence_name 424 data, _ = self.fetch("SELECT last_value FROM %s;" % seq, conn) 425 newids[idkey] = data[0][0] 426 return newids 427 trunk/geniusql/providers/sqlite.py
r1 r2 1 1 import datetime 2 2 import os 3 import threading4 3 import time 5 4 6 import dejavu 7 from dejavu import errors, logic, storage 8 from dejavu.storage import db, isolation as _isolation 5 import geniusql 6 from geniusql import errors, typerefs, providers 9 7 10 8 try: … … 12 10 # This assumes the one built into Python 2.5+ 13 11 import _sqlite3 as _sqlite 14 _version = storage.Version(_sqlite.sqlite_version)12 _version = providers.Version(_sqlite.sqlite_version) 15 13 _cursor_required = True 16 14 _fetchall_required = True … … 21 19 # using e.g. pysqlite 1.1.7 22 20 import _sqlite 23 _version = storage.Version(_sqlite.sqlite_version())21 _version = providers.Version(_sqlite.sqlite_version()) 24 22 _cursor_required = False 25 23 _fetchall_required = False … … 28 26 29 27 # ESCAPE keyword was added Nov 2004, 1 month after 3.0.8 release. 30 _escape_support = (_version > storage.Version([3, 0, 8]))28 _escape_support = (_version > providers.Version([3, 0, 8])) 31 29 if not _escape_support: 32 30 _escape_warning = ("Version %s of sqlite does not support " 33 31 "wildcard literals." % _version) 34 import warnings35 warnings.warn(_escape_warning, errors.StorageWarning) 36 37 _ add_column_support = (_version >= storage.Version([3, 2, 0]))38 _ rename_table_support = (_version >= storage.Version([3, 1, 0]))39 _ autoincrement_support = (_version >= storage.Version([3, 1, 0]))40 _cast_support = (_version >= storage.Version([3, 2, 3])) 41 42 class AdapterToSQLite( db.AdapterToSQL):32 errors.warn(_escape_warning) 33 34 _add_column_support = (_version >= providers.Version([3, 2, 0])) 35 _rename_table_support = (_version >= providers.Version([3, 1, 0])) 36 _autoincrement_support = (_version >= providers.Version([3, 1, 0])) 37 _cast_support = (_version >= providers.Version([3, 2, 3])) 38 39 40 class AdapterToSQLite(geniusql.AdapterToSQL): 43 41 44 42 # C-style backslash escapes are not supported. … … 60 58 61 59 62 class AdapterFromSQLite( db.AdapterFromDB):60 class AdapterFromSQLite(geniusql.AdapterFromDB): 63 61 64 62 def coerce_any_to_bool(self, value): … … 70 68 71 69 72 class SQLiteDecompiler( db.SQLDecompiler):70 class SQLiteDecompiler(geniusql.SQLDecompiler): 73 71 74 72 def visit_COMPARE_OP(self, lo, hi): … … 83 81 # comparison. 84 82 for i, op in enumerate((op1, op2)): 85 if (isinstance(op, db.ConstWrapper) and83 if (isinstance(op, geniusql.ConstWrapper) and 86 84 isinstance(op.basevalue, (datetime.date, datetime.datetime))): 87 85 op1 = "julianday(" + op1 + ")" … … 100 98 self.stack.append(op2) 101 99 102 db.SQLDecompiler.visit_COMPARE_OP(self, lo, hi)100 geniusql.SQLDecompiler.visit_COMPARE_OP(self, lo, hi) 103 101 104 102 def attr_startswith(self, tos, arg): … … 121 119 122 120 def containedby(self, op1, op2): 123 if isinstance(op1, db.ConstWrapper):121 if isinstance(op1, geniusql.ConstWrapper): 124 122 # Looking for text in a field. Use Like (reverse terms). 125 123 if _escape_support: … … 136 134 137 135 def dejavu_icontainedby(self, op1, op2): 138 if isinstance(op1, db.ConstWrapper):136 if isinstance(op1, geniusql.ConstWrapper): 139 137 # Looking for text in a field. Use Like (reverse terms). 140 138 if _escape_support: … … 181 179 else: 182 180 self.imperfect = True 183 return db.cannot_represent181 return geniusql.cannot_represent 184 182 185 183 dejavu_today = dejavu_now … … 190 188 else: 191 189 self.imperfect = True 192 return db.cannot_represent190 return geniusql.cannot_represent 193 191 194 192 def dejavu_month(self, x): … … 197 195 else: 198 196 self.imperfect = True 199 return db.cannot_represent197 return geniusql.cannot_represent 200 198 201 199 def dejavu_day(self, x): … … 204 202 else: 205 203 self.imperfect = True 206 return db.cannot_represent207 208 209 class TypeAdapterSQLite( db.TypeAdapter):204 return geniusql.cannot_represent 205 206 207 class TypeAdapterSQLite(geniusql.TypeAdapter): 210 208 """For a column and Python type, return a database type. 211 209 … … 262 260 263 261 264 class TypeAdapterSQLiteTypeless( db.TypeAdapter):262 class TypeAdapterSQLiteTypeless(geniusql.TypeAdapter): 265 263 266 264 def coerce(self, col, pytype): … … 270 268 271 269 272 class SQLiteTable( db.Table):270 class SQLiteTable(geniusql.Table): 273 271 274 272 def _parent_key(self): … … 418 416 419 417 420 class SQLiteSelectWriter( db.SelectWriter):418 class SQLiteSelectWriter(geniusql.SelectWriter): 421 419 422 420 def _joinclause(self, join): 423 421 on_clauses = [] 424 422 425 t1, t2 = join.table1, unitjoin.table2426 if isinstance(t1, db.Join):423 t1, t2 = join.table1, join.table2 424 if isinstance(t1, geniusql.Join): 427 425 name1, oc = self._joinclause(t1) 428 426 on_clauses.extend(oc) … … 433 431 tlist1 = [t1] 434 432 435 if isinstance(t2, Join):433 if isinstance(t2, geniusql.Join): 436 434 name2, oc = self._joinclause(t2) 437 435 on_clauses.extend(oc) … … 476 474 477 475 478 class SQLiteDatabase( db.Database):476 class SQLiteDatabase(geniusql.Database): 479 477 480 478 sql_name_max_length = 0 … … 488 486 tableclass = SQLiteTable 489 487 488 def __init__(self, name, **kwargs): 489 if name != ':memory:': 490 if not os.path.isabs(name): 491 name = os.path.join(os.getcwd(), name) 492 geniusql.Database.__init__(self, name, **kwargs) 493 494 def _get_upd(self): 495 return self.adaptertosql.using_perfect_dates 496 def _set_upd(self, value): 497 self.adaptertosql.using_perfect_dates = value 498 using_perfect_dates = property(_get_upd, _set_upd) 499 490 500 def isrelatedtype(self, pytype1, pytype2): 491 501 if (self.using_perfect_dates and … … 493 503 issubclass(pytype2, self.python_type(self.typeadapter.coerce(None, pytype1)))): 494 504 return True 495 return db.Database.isrelatedtype(self, pytype1, pytype2)505 return geniusql.Database.isrelatedtype(self, pytype1, pytype2) 496 506 497 507 def _get_tables(self, conn=None): … … 516 526 cols = [] 517 527 for row in data: 518 c = db.Column(row[1], self.quote(row[1]), row[2].upper(),519 default=row[4], key=bool(row[5]))528 c = geniusql.Column(row[1], self.quote(row[1]), row[2].upper(), 529 default=row[4], key=bool(row[5])) 520 530 521 531 # "A single row can hold up to 2 ** 30 bytes of data … … 553 563 if row[2]: 554 564 colname = row[2].split("(")[-1] 555 i = db.Index(row[0], self.quote(row[0]), row[1], colname[1:-2]) 565 i = geniusql.Index(row[0], self.quote(row[0]), 566 row[1], colname[1:-2]) 556 567 indices.append(i) 557 568 return indices … … 565 576 return float 566 577 elif dbtype == "NUMERIC": 567 if db.decimal:568 return db.decimal.Decimal569 elif db.fixedpoint:570 return db.fixedpoint.FixedPoint578 if typerefs.decimal: 579 return typerefs.decimal.Decimal 580 elif typerefs.fixedpoint: 581 return typerefs.fixedpoint.FixedPoint 571 582 elif dbtype.startswith("INTEGER"): 572 583 return int … … 695 706 # http://www.sqlite.org/cvstrac/wiki?p=InMemoryDatabase 696 707 # So we need to give :memory: databases a SingleConnection. 697 self.connection = db.SingleConnection(self._get_conn, self._del_conn)698 else: 699 return db.Database.connect(self)708 self.connection = geniusql.SingleConnection(self._get_conn, self._del_conn) 709 else: 710 return geniusql.Database.connect(self) 700 711 701 712 if _cursor_required: … … 750 761 isolation = self.default_isolation 751 762 752 if isinstance(isolation, _isolation.IsolationLevel):763 if isinstance(isolation, geniusql.IsolationLevel): 753 764 # Map the given IsolationLevel object to a native value. 754 765 # This base class uses the four ANSI names as native values. … … 802 813 msg == "database schema has changed")): 803 814 tx = self.transactions.get(self.transaction_key()) 804 if tx is None or isinstance(tx, db.TransactionLock):815 if tx is None or isinstance(tx, errors.TransactionLock): 805 816 # Bah. Shut down all connections and get a new one, 806 817 # since some previous connection changed the schema. … … 834 845 res = self.execute(query, conn) 835 846 return res.row_list, res.col_defs 836 837 838 class StorageManagerSQLite(db.StorageManagerDB):839 """StoreManager to save and retrieve Units via _sqlite."""840 841 databaseclass = SQLiteDatabase842 843 def __init__(self, arena, allOptions={}):844 allOptions = allOptions.copy()845 dbfile = allOptions.pop('Database', '')846 if dbfile != ':memory:':847 if not os.path.isabs(dbfile):848 dbfile = os.path.join(os.getcwd(), dbfile)849 allOptions['name'] = dbfile850 allOptions['mode'] = int(allOptions.pop('Mode', '0755'), 8)851 db.StorageManagerDB.__init__(self, arena, allOptions)852 pd = str(allOptions.get('Perfect Dates', 'False')).lower() == "true"853 self.databaseclass.using_perfect_dates = pd854 self.databaseclass.adaptertosql.using_perfect_dates = pd855 847 856 848 def version(self): 857 849 return "SQLite Version: %s" % _version 858 859 def reserve(self, unit): 860 """reserve(unit). -> Reserve a persistent slot for unit.""" 861 self.reserve_lock.acquire() 862 try: 863 # First, see if our db subclass has a handler that 864 # uses the DB to generate the appropriate identifier(s). 865 seqclass = unit.sequencer.__class__.__name__ 866 if seqclass == "UnitSequencerInteger" and _autoincrement_support: 867 self._seq_UnitSequencerInteger(unit) 868 else: 869 self._manual_reserve(unit) 870 unit.cleanse() 871 finally: 872 self.reserve_lock.release() 873 874 def _seq_UnitSequencerInteger(self, unit): 875 """Reserve a unit using the table's AUTOINCREMENT field.""" 876 cls = unit.__class__ 877 t = self.db[cls.__name__] 878 879 fields = [] 880 values = [] 881 for key in cls.properties: 882 col = t[key] 883 if col.autoincrement: 884 # Skip this field, since we're using AUTOINCREMENT 885 continue 886 val = self.db.adaptertosql.coerce(getattr(unit, key), col.dbtype) 887 fields.append(col.qname) 888 values.append(val) 889 890 fields = ", ".join(fields) 891 values = ", ".join(values) 892 893 # Use the same conn for INSERT and last row id 894 conn = self.db.get_transaction() 895 self.db.execute('INSERT INTO %s (%s) VALUES (%s);' % 896 (t.qname, fields, values), conn) 897 898 # Grab the new ID. This is safe because db.reserve has a mutex. 899 if _lastrowid_support: 900 new_id = conn.lastrowid 901 else: 902 new_id = conn.sqlite_last_insert_rowid() 903 setattr(unit, cls.identifiers[0], new_id) 904 905 # Schemas # 906 907 def _make_column(self, cls, key): 908 col = db.StorageManagerDB._make_column(self, cls, key) 909 if col.autoincrement and not _autoincrement_support: 910 col.autoincrement = False 911 col.initial = 0 912 return col 913 850 trunk/geniusql/select.py
r1 r2 606 606 portion of an SQL JOIN clause. 607 607 """ 608 ref = A.table.references.get(path or B.table.name, None) 608 if path is None: 609 db = B.table.db 610 for tkey in db: 611 if db[tkey] is B.table: 612 path = tkey 613 break 614 ref = A.table.references.get(path, None) 609 615 if ref: 610 616 nearkey, _, farkey = ref
