Skip to content

Commit 1185c3b

Browse files
committed
Verify variable mappings and concurrent init ownership
1 parent f18e02b commit 1185c3b

1 file changed

Lines changed: 58 additions & 3 deletions

File tree

‎src/openstatspec/sql/wide.py‎

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,6 +1356,52 @@ def _catalog_dataset_bijection_state(
13561356
return "valid" if set(legacy_rows) == set(normative_rows) else "unverified"
13571357

13581358

1359+
def _catalog_variable_bijection_state(
1360+
connection: Any, *, normative: Any, legacy: Iterable[Table],
1361+
) -> str:
1362+
"""Require exact legacy-to-normative variable identity mappings."""
1363+
variables = tuple(legacy)[1]
1364+
legacy_rows = [
1365+
(
1366+
row["dataset_id"], row["ordinal"], row["source_name"],
1367+
row["physical_name"],
1368+
)
1369+
for row in connection.execute(select(
1370+
variables.c.dataset_id, variables.c.ordinal,
1371+
variables.c.source_name, variables.c.physical_name,
1372+
)).mappings()
1373+
]
1374+
normative_rows = [
1375+
(
1376+
row["dataset_name"], row["source_ordinal"], row["source_name"],
1377+
row["physical_name"],
1378+
)
1379+
for row in connection.execute(
1380+
select(
1381+
normative.dataset.c.dataset_name,
1382+
normative.variable.c.source_ordinal,
1383+
normative.variable.c.source_name,
1384+
normative.variable.c.physical_name,
1385+
).join(
1386+
normative.variable,
1387+
normative.variable.c.dataset_id == normative.dataset.c.dataset_id,
1388+
)
1389+
).mappings()
1390+
]
1391+
for rows in (legacy_rows, normative_rows):
1392+
if any(
1393+
not isinstance(dataset_name, str) or not dataset_name.strip()
1394+
or not isinstance(ordinal, int) or ordinal < 1
1395+
or not isinstance(source_name, str) or not source_name.strip()
1396+
or not isinstance(physical_name, str) or not physical_name.strip()
1397+
for dataset_name, ordinal, source_name, physical_name in rows
1398+
):
1399+
return "unverified"
1400+
if len(set(rows)) != len(rows):
1401+
return "ambiguous"
1402+
return "valid" if set(legacy_rows) == set(normative_rows) else "unverified"
1403+
1404+
13591405
def _catalog_state(
13601406
connection: Any, normative: Any, legacy: Iterable[Table],
13611407
*, allowed_migrations: Mapping[str, set[str]] | None = None,
@@ -1424,6 +1470,11 @@ def _catalog_state(
14241470
)
14251471
if mapping_state != "valid":
14261472
return mapping_state
1473+
variable_mapping_state = _catalog_variable_bijection_state(
1474+
connection, normative=normative, legacy=legacy,
1475+
)
1476+
if variable_mapping_state != "valid":
1477+
return variable_mapping_state
14271478
return "verified"
14281479

14291480

@@ -1472,9 +1523,12 @@ def _catalog_snapshot(
14721523

14731524
def _compensate_catalog_initialization(
14741525
connection: Any, *, metadata: MetaData, before_tables: set[str],
1475-
before_columns: Mapping[str, set[str]],
1526+
before_columns: Mapping[str, set[str]], normative: Any,
1527+
legacy: Iterable[Table],
14761528
) -> None:
1477-
"""Restore the pre-initialization relation/column inventory after DDL failure."""
1529+
"""Restore only when no concurrent initializer completed the catalog."""
1530+
if _catalog_state(connection, normative, legacy) == "verified":
1531+
return
14781532
current_tables = set(inspect(connection).get_table_names())
14791533
for table in reversed(metadata.sorted_tables):
14801534
if table.name in current_tables and table.name not in before_tables:
@@ -1626,7 +1680,8 @@ def initialize_wide_catalog(
16261680
with connection.begin():
16271681
_compensate_catalog_initialization(
16281682
connection, metadata=metadata, before_tables=before_tables,
1629-
before_columns=before_columns,
1683+
before_columns=before_columns, normative=normative,
1684+
legacy=legacy,
16301685
)
16311686
except Exception as cleanup_error:
16321687
inventory = _catalog_residual_inventory(

0 commit comments

Comments
 (0)