Changeset 27
- Timestamp:
- 03/10/07 14:35:13
- Files:
-
- trunk/geniusql/objects.py (modified) (2 diffs)
- trunk/geniusql/providers/sqlite.py (modified) (11 diffs)
- trunk/geniusql/test/zoo_fixture.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/geniusql/objects.py
r26 r27 13 13 """Bijective dict. Each key maps to only one value (and vice-versa).""" 14 14 15 def key_for(self, value):15 def key_for(self, obj): 16 16 """For the given value, return its corresponding key.""" 17 17 for key, val in self.iteritems(): 18 if val is value:18 if val is obj: 19 19 return key 20 raise ValueError("The given value could not be found: %r" % value)20 raise ValueError("The given object could not be found: %r" % obj) 21 21 22 22 def alias(self, oldname, newname): … … 757 757 at a time should inspect this value to determine whether they 758 758 need a separate Database instance per Schema instance. 759 """ 760 761 pks_must_be_indexed = True 762 pks_must_be_indexed__doc = """If True, the underlying database 763 implements primary keys by creating an index. Geniusql allows 764 you to define pk's without indexes, but not all databases do. 759 765 """ 760 766 trunk/geniusql/providers/sqlite.py
r26 r27 315 315 """ 316 316 317 def _temp_copy(self): 318 # Make a temporary table. Callers then modify it before binding. 319 schema = self.schema 320 temptable = self.copy() 321 tempkey = "temp_" + schema.key_for(self) 322 temptable.name = schema.table_name(tempkey) 323 temptable.qname = schema.db.quote(temptable.name) 324 # Update index names. 325 for key, i in temptable.indices.iteritems(): 326 i.name = schema.table_name("i" + temptable.name + i.colname) 327 i.qname = schema.db.quote(i.name) 328 i.tablename = temptable.name 329 return tempkey, temptable 330 331 def _copy_from_temp(self, temptable, tempkey): 332 """Copy data from a temp table to a new table for self.""" 333 schema = self.schema 334 335 # Drop the old table and create the new, final table. 336 newtable = temptable.copy() 337 newtable.name = self.name 338 newtable.qname = self.qname 339 # Update index names. 340 for key, i in newtable.indices.iteritems(): 341 i.name = schema.table_name("i" + newtable.name + i.colname) 342 i.qname = schema.db.quote(i.name) 343 i.tablename = newtable.name 344 schema[schema.key_for(self)] = newtable 317 def _start_temp(self): 318 """Convert self into a temporary table. Not thread-safe.""" 319 self.origname = self.name 320 self.origqname = self.qname 321 self.name = "temp_" + self.name 322 self.qname = self.schema.db.quote(self.name) 323 324 def _finish_temp(self, selfields=None): 325 """Convert self from a temporary table. Not thread-safe.""" 326 # CREATE the temporary TABLE. 327 self.schema._create_table(self, skip_indices=True) 328 329 tempqname = self.qname 330 331 # Copy data from the original table to the temp table. 332 if selfields is None: 333 selfields = [c.qname for c in self.itervalues()] 334 self.schema.db.execute_ddl("INSERT INTO %s SELECT %s FROM %s;" % 335 (tempqname, ", ".join(selfields), 336 self.origqname)) 337 338 # DROP the original TABLE. 339 self.schema.db.execute_ddl('DROP TABLE %s;' % self.origqname) 340 341 # CREATE the new TABLE. Note we do not skip indices here; 342 # SQLite dropped the old ones when we dropped the original table. 343 self.name = self.origname 344 self.qname = self.origqname 345 self.schema._create_table(self) 345 346 346 347 # Copy data from the temp table to the final table. 347 348 # For some odd reason, using "SELECT *" 348 349 # mixes up the fields (during rename, at least). 349 selfields = ", ".join([c.qname for c in temptable.values()])350 s chema.db.execute("INSERT INTO %s (%s) SELECT %s FROM %s;" %351 (newtable.qname, selfields, selfields,352 temptable.qname))353 354 # D rop the intermediate table.355 del schema[tempkey]350 selfields = ", ".join([c.qname for c in self.values()]) 351 self.schema.db.execute("INSERT INTO %s (%s) SELECT %s FROM %s;" 352 % (self.qname, selfields, selfields, 353 tempqname)) 354 355 # DROP the temporary TABLE. 356 self.schema.db.execute_ddl('DROP TABLE %s;' % tempqname) 356 357 357 358 if not _add_column_support: … … 364 365 del self[key] 365 366 366 if column.autoincrement: 367 # This may or may not be a no-op, depending on the DB. 368 self.schema.create_sequence(self, column) 369 370 # Make a temporary copy. 371 tempkey, temptable = self._temp_copy() 372 # Add the new column to the copy. 373 dict.__setitem__(temptable, key, column) 374 # Bind the temp table to the DB (this will call CREATE TABLE). 375 self.schema[tempkey] = temptable 376 377 # Copy data from the old table to the temp table. 367 self._start_temp() 368 dict.__setitem__(self, key, column) 369 378 370 selfields = [] 379 for k, c in temptable.iteritems():371 for k, c in self.iteritems(): 380 372 qname = c.qname 381 373 if k == key: … … 383 375 qname = "NULL AS %s" % qname 384 376 selfields.append(qname) 385 self.schema.db.execute_ddl("INSERT INTO %s SELECT %s FROM %s;" % 386 (temptable.qname, ", ".join(selfields), 387 self.qname)) 388 389 # Copy data from the temp table to a new table for self. 390 self._copy_from_temp(temptable, tempkey) 377 self._finish_temp(selfields) 391 378 392 379 def __delitem__(self, key): … … 398 385 return 399 386 387 self._start_temp() 388 dict.__delitem__(self, key) 389 self._finish_temp() 390 400 391 column = self[key] 401 402 # Make a temporary copy.403 tempkey, temptable = self._temp_copy()404 # Drop the column from the copy.405 dict.__delitem__(temptable, key)406 # Bind the temp table to the DB (this will call CREATE TABLE).407 self.schema[tempkey] = temptable408 409 # Copy data from the old table to the temp table.410 selfields = [c.qname for c in temptable.itervalues()]411 self.schema.db.execute_ddl("INSERT INTO %s SELECT %s FROM %s;" %412 (temptable.qname, ", ".join(selfields),413 self.qname))414 415 self._copy_from_temp(temptable, tempkey)416 417 392 if column.autoincrement: 418 393 # This may or may not be a no-op, depending on the DB. … … 426 401 427 402 if oldname != newname: 403 self._start_temp() 404 428 405 dict.__delitem__(self, oldkey) 429 406 dict.__setitem__(self, newkey, oldcol) … … 431 408 oldcol.qname = self.schema.db.quote(newname) 432 409 433 # Make a temporary copy.434 tempkey, temptable = self._temp_copy()435 # Bind the temp table to the DB (this will call CREATE TABLE).436 self.schema[tempkey] = temptable437 438 # Copy data from the old table to the temp table.439 410 selfields = [] 440 for k, c in temptable.iteritems():411 for k, c in self.iteritems(): 441 412 qname = c.qname 442 413 if k == newkey: 443 414 qname = "%s AS %s" % (self.schema.db.quote(oldname), qname) 444 415 selfields.append(qname) 445 self.schema.db.execute_ddl("INSERT INTO %s SELECT %s FROM %s;" % 446 (temptable.qname, ", ".join(selfields), 447 self.qname)) 448 449 self._copy_from_temp(temptable, tempkey) 416 self._finish_temp(selfields) 450 417 451 418 def _grab_new_ids(self, idkeys, conn): … … 457 424 458 425 def add_primary(self): 459 """ Set the PRIMARY KEY for this Table, using its Column.key values."""426 """Assert the PRIMARY KEY for this Table, using its Column.key values.""" 460 427 pk = [column.qname for column in self.itervalues() if column.key] 461 428 if pk: 462 # Make a temporary copy. 463 tempkey, temptable = self._temp_copy() 464 # Bind the temp table to the DB. 465 self.schema[tempkey] = temptable 466 # Copy data from the old table to the temp table. 467 selfields = [c.qname for c in temptable.itervalues()] 468 self.schema.db.execute_ddl("INSERT INTO %s SELECT %s FROM %s;" % 469 (temptable.qname, ", ".join(selfields), 470 self.qname)) 471 # Create the new table and copy data from the temp table to it. 472 self._copy_from_temp(temptable, tempkey) 429 self._start_temp() 430 self._finish_temp() 473 431 474 432 def drop_primary(self): 475 433 """Remove any PRIMARY KEY for this Table.""" 476 # Make a temporary copy. 477 tempkey, temptable = self._temp_copy() 478 # Drop all .key's from the copy. 479 for col in temptable.itervalues(): 434 self._start_temp() 435 for col in self.itervalues(): 480 436 col.key = False 481 # Bind the temp table to the DB. 482 self.schema[tempkey] = temptable 483 484 # Copy data from the old table to the temp table. 485 selfields = [c.qname for c in temptable.itervalues()] 486 self.schema.db.execute_ddl("INSERT INTO %s SELECT %s FROM %s;" % 487 (temptable.qname, ", ".join(selfields), 488 self.qname)) 489 # Create the new table and copy data from the temp table to it. 490 self._copy_from_temp(temptable, tempkey) 437 self._finish_temp() 491 438 492 439 … … 708 655 data, _ = self.db.fetch( 709 656 "SELECT name, tbl_name, sql FROM sqlite_master " 710 "WHERE type = 'index' ;", conn)657 "WHERE type = 'index' AND tbl_name = '%s';" % tablename, conn) 711 658 712 659 indices = [] … … 768 715 del self[key] 769 716 717 self._create_table(table) 718 770 719 # Set table.created to True, which should "turn on" 771 720 # any future ALTER TABLE statements. 772 721 table.created = True 773 722 723 dict.__setitem__(self, key, table) 724 725 def _create_table(self, table, skip_indices=False): 774 726 fields = [] 775 727 pk = [] … … 795 747 (table.qname, ", ".join(fields), pk)) 796 748 797 for index in table.indices.itervalues():798 self.db.execute_ddl('CREATE INDEX %s ON %s (%s);' %799 (index.qname, table.qname,800 self.db.quote(index.colname)))801 802 749 if autoincr_col: 803 750 self.create_sequence(table, autoincr_col) 804 751 805 dict.__setitem__(self, key, table) 752 if not skip_indices: 753 for index in table.indices.itervalues(): 754 self.db.execute_ddl('CREATE INDEX %s ON %s (%s);' % 755 (index.qname, table.qname, 756 self.db.quote(index.colname))) 806 757 807 758 def _rename(self, oldtable, newtable): … … 836 787 schemaclass = SQLiteSchema 837 788 multischema = False 789 790 pks_must_be_indexed = False 838 791 839 792 def __init__(self, **kwargs): trunk/geniusql/test/zoo_fixture.py
r26 r27 41 41 Animal = schema.table('Animal') 42 42 Animal['ID'] = schema.column(int, autoincrement=True, key=True) 43 Animal.add_index('ID')43 ## Animal.add_index('ID') 44 44 Animal['ZooID'] = schema.column(int) 45 45 Animal['Name'] = schema.column(hints={'bytes': 100}) … … 606 606 def test_primary_key_support(self): 607 607 # Drop and re-add the PK on, oh, how about the Animal table? 608 schema['Animal'].drop_primary() 609 schema['Animal'].add_primary() 608 Animal = schema['Animal'] 609 Animal.drop_primary() 610 Animal.add_primary() 611 612 Animal = schema.discover('Animal') 613 if schema.db.pks_must_be_indexed: 614 self.assertEqual(len(Animal.indices), 2) 615 else: 616 # Since we did not add an index on Animal.ID... 617 self.assertEqual(len(Animal.indices), 1) 610 618 611 619 def test_insert_into(self):
