Skip to content

Commit 6e5f1ee

Browse files
zzzeekGerrit Code Review
authored andcommitted
Merge "create placeholder tables for non-reflected remotes" into main
2 parents 3e5c8db + a53d2f1 commit 6e5f1ee

File tree

4 files changed

+537
-0
lines changed

4 files changed

+537
-0
lines changed

alembic/autogenerate/compare/constraints.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,44 @@ def _make_foreign_key(
580580
initially=options.get("initially"),
581581
name=params["name"],
582582
)
583+
584+
referred_schema = params["referred_schema"]
585+
referred_table = params["referred_table"]
586+
587+
remote_table_key = sqla_compat._get_table_key(
588+
referred_table, referred_schema
589+
)
590+
if remote_table_key not in conn_table.metadata:
591+
# create a placeholder table
592+
sa_schema.Table(
593+
referred_table,
594+
conn_table.metadata,
595+
schema=(
596+
referred_schema
597+
if referred_schema is not None
598+
else sa_schema.BLANK_SCHEMA
599+
),
600+
*[
601+
sa_schema.Column(remote, conn_table.c[local].type)
602+
for local, remote in zip(
603+
params["constrained_columns"], params["referred_columns"]
604+
)
605+
],
606+
info={"alembic_placeholder": True},
607+
)
608+
elif conn_table.metadata.tables[remote_table_key].info.get(
609+
"alembic_placeholder"
610+
):
611+
# table exists and is a placeholder; ensure needed columns are present
612+
placeholder_table = conn_table.metadata.tables[remote_table_key]
613+
for local, remote in zip(
614+
params["constrained_columns"], params["referred_columns"]
615+
):
616+
if remote not in placeholder_table.c:
617+
placeholder_table.append_column(
618+
sa_schema.Column(remote, conn_table.c[local].type)
619+
)
620+
583621
# needed by 0.7
584622
conn_table.append_constraint(const)
585623
return const
@@ -595,6 +633,7 @@ def _compare_foreign_keys(
595633
) -> PriorityDispatchResult:
596634
# if we're doing CREATE TABLE, all FKs are created
597635
# inline within the table def
636+
598637
if conn_table is None or metadata_table is None:
599638
return PriorityDispatchResult.CONTINUE
600639

alembic/util/sqla_compat.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,13 @@ def _get_variant_mapping(type_):
293293
return type_.impl, type_.mapping
294294

295295

296+
def _get_table_key(name: str, schema: Optional[str]) -> str:
297+
if schema is None:
298+
return name
299+
else:
300+
return schema + "." + name
301+
302+
296303
def _fk_spec(constraint: ForeignKeyConstraint) -> Any:
297304
if TYPE_CHECKING:
298305
assert constraint.columns is not None

docs/build/unreleased/1787.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.. change::
2+
:tags: bug, autogenerate
3+
:tickets: 1787
4+
5+
Fixed regression in version 1.18.0 due to :ticket:`1771` where autogenerate
6+
would raise ``NoReferencedTableError`` when a foreign key constraint
7+
referenced a table that was not part of the initial table load, including
8+
tables filtered out by the
9+
:paramref:`.EnvironmentContext.configure.include_name` callable or tables
10+
in remote schemas that were not included in the initial reflection run.
11+
12+
The change in :ticket:`1771` was a performance optimization that eliminated
13+
additional reflection queries for tables that were only referenced by
14+
foreign keys but not explicitly included in the main reflection run.
15+
However, this optimization inadvertently removed the creation of
16+
:class:`.Table` objects for these referenced tables, causing autogenerate
17+
to fail when processing foreign key constraints that pointed to them.
18+
19+
The fix creates placeholder :class:`.Table` objects for foreign key targets
20+
that are not reflected, allowing the autogenerate comparison to proceed
21+
without error while maintaining the performance improvement from
22+
:ticket:`1771`. When multiple foreign keys reference different columns in
23+
the same filtered table, the placeholder table accumulates all necessary
24+
columns. These placeholder tables may be visible when using the
25+
:paramref:`.EnvironmentContext.configure.include_object` callable to
26+
inspect :class:`.ForeignKeyConstraint` objects; they will have the name,
27+
schema and basic column information for the relevant columns present.

0 commit comments

Comments
 (0)