mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-07-24 01:44:31 +02:00
Compound primary keys now resolve in PRIMARY KEY declaration order
PRAGMA table_info sets is_pk to the 1-based position of each column within the PRIMARY KEY, which can differ from table column order. table.pks previously returned table column order, so an implicit compound FOREIGN KEY ... REFERENCES other was introspected with its referenced columns inverted, and transform() baked that inverted order into the rewritten schema - failing with IntegrityError on valid data, or silently reversing the constraint with foreign keys off. table.pks, compound foreign key guessing (create, add_foreign_key) and transform() now all use declaration order, and transform() no longer reorders a compound PRIMARY KEY (b, a) into table column order. Refs https://github.com/simonw/sqlite-utils/issues/769#issuecomment-4900034150 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
66934918c6
commit
8e015d024c
4 changed files with 91 additions and 10 deletions
|
|
@ -2012,10 +2012,9 @@ class Queryable:
|
|||
:param offset: Integer for SQL offset
|
||||
"""
|
||||
column_names = [column.name for column in self.columns]
|
||||
pks = [column.name for column in self.columns if column.is_pk]
|
||||
if not pks:
|
||||
pks = self.pks
|
||||
if self.use_rowid:
|
||||
column_names.insert(0, "rowid")
|
||||
pks = ["rowid"]
|
||||
select = ",".join(quote_identifier(column_name) for column_name in column_names)
|
||||
for row in self.rows_where(
|
||||
select=select,
|
||||
|
|
@ -2148,8 +2147,18 @@ class Table(Queryable):
|
|||
|
||||
@property
|
||||
def pks(self) -> List[str]:
|
||||
"Primary key columns for this table."
|
||||
names = [column.name for column in self.columns if column.is_pk]
|
||||
"""
|
||||
Primary key columns for this table, in PRIMARY KEY declaration order -
|
||||
``PRAGMA table_info`` sets ``is_pk`` to the 1-based position of each
|
||||
column within the primary key, which can differ from the order of the
|
||||
columns in the table. SQLite uses the declaration order to resolve
|
||||
implicit foreign key references, so this order matters.
|
||||
"""
|
||||
pk_columns = sorted(
|
||||
(column for column in self.columns if column.is_pk),
|
||||
key=lambda column: column.is_pk,
|
||||
)
|
||||
names = [column.name for column in pk_columns]
|
||||
if not names:
|
||||
names = ["rowid"]
|
||||
return names
|
||||
|
|
@ -2673,7 +2682,8 @@ class Table(Queryable):
|
|||
|
||||
if pk is DEFAULT:
|
||||
pks_renamed = tuple(
|
||||
rename.get(p.name) or p.name for p in self.columns if p.is_pk
|
||||
rename.get(pk_name) or pk_name
|
||||
for pk_name in (self.pks if not self.use_rowid else [])
|
||||
)
|
||||
if len(pks_renamed) == 1:
|
||||
pk = pks_renamed[0]
|
||||
|
|
@ -3017,7 +3027,10 @@ class Table(Queryable):
|
|||
raise AlterError("table '{}' has no column {}".format(fk, fk_col))
|
||||
else:
|
||||
# automatically set fk_col to first primary_key of fk table
|
||||
pks = [c for c in self.db[fk].columns if c.is_pk]
|
||||
pks = sorted(
|
||||
(c for c in self.db[fk].columns if c.is_pk),
|
||||
key=lambda c: c.is_pk,
|
||||
)
|
||||
if pks:
|
||||
fk_col = pks[0].name
|
||||
fk_col_type = pks[0].type
|
||||
|
|
@ -3770,9 +3783,7 @@ class Table(Queryable):
|
|||
# First we execute the function
|
||||
pk_to_values = {}
|
||||
new_column_types: Dict[str, Set[type]] = {}
|
||||
pks = [column.name for column in self.columns if column.is_pk]
|
||||
if not pks:
|
||||
pks = ["rowid"]
|
||||
pks = self.pks
|
||||
|
||||
with progressbar(
|
||||
length=self.count, silent=not show_progress, label="1: Evaluating"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue