fix(cadastre): cad_territorial_zones MULTIPOLYGON typmod + ST_Multi coercion (#1344) #1673
2 changed files with 76 additions and 6 deletions
|
|
@ -555,9 +555,7 @@ async def backfill_parcel_geom(
|
|||
# Один сбойный квартал не валит весь backfill — лог + продолжаем.
|
||||
# (WAF 403 пробросится из client и прервёт прогон — это ожидаемо,
|
||||
# caller-task ловит и не ретраит, как в bulk_harvest.)
|
||||
logger.warning(
|
||||
"backfill_parcel_geom: grid-walk failed quarter=%s: %s", quarter, e
|
||||
)
|
||||
logger.warning("backfill_parcel_geom: grid-walk failed quarter=%s: %s", quarter, e)
|
||||
db.rollback()
|
||||
continue
|
||||
|
||||
|
|
@ -1477,6 +1475,21 @@ def _save_territorial_zones(db: Session, quarter_cad: str, features: list[dict])
|
|||
zone_name = props.get("zone_name") or props.get("zone_type_name") or props.get("type_zone")
|
||||
permitted_use = props.get("permitted_use") or props.get("vri")
|
||||
|
||||
# cad_territorial_zones.geom — geography(MultiPolygon, 4326).
|
||||
# Polygon допустим (ST_Multi обернёт в SQL), но Point/LineString →
|
||||
# geography-INSERT fail → SAVEPOINT откат → строка дропается молча.
|
||||
# Зеркалит фильтр upsert_zouit (~1196).
|
||||
geom_type = geom.get("type") if isinstance(geom, dict) else None
|
||||
if geom_type not in ("Polygon", "MultiPolygon"):
|
||||
if geom_type:
|
||||
logger.info(
|
||||
"_save_territorial_zones: zone_id=%s geom type=%s (не Polygon/MultiPolygon)"
|
||||
" — geom=NULL",
|
||||
zone_id,
|
||||
geom_type,
|
||||
)
|
||||
geom_geojson = None
|
||||
|
||||
try:
|
||||
# begin_nested() требует активной outer-транзакции для SAVEPOINT.
|
||||
# SQLAlchemy Session (autobegin=True) автоматически начинает tx при первом
|
||||
|
|
@ -1495,9 +1508,11 @@ def _save_territorial_zones(db: Session, quarter_cad: str, features: list[dict])
|
|||
CAST(:permitted_use AS text),
|
||||
CAST(:raw_props AS jsonb),
|
||||
CASE WHEN CAST(:geom AS text) IS NOT NULL
|
||||
THEN ST_Transform(
|
||||
ST_SetSRID(ST_GeomFromGeoJSON(CAST(:geom AS text)), 3857),
|
||||
4326
|
||||
THEN ST_Multi(
|
||||
ST_Transform(
|
||||
ST_SetSRID(ST_GeomFromGeoJSON(CAST(:geom AS text)), 3857),
|
||||
4326
|
||||
)
|
||||
)::geography
|
||||
ELSE NULL
|
||||
END
|
||||
|
|
|
|||
55
data/sql/159_alter_cad_territorial_zones_multipolygon.sql
Normal file
55
data/sql/159_alter_cad_territorial_zones_multipolygon.sql
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
-- 159_alter_cad_territorial_zones_multipolygon.sql
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Контекст:
|
||||
-- NSPD ПЗЗ территориальные зоны (layer 875838) зачастую возвращают
|
||||
-- MultiPolygon (у зоны несколько геометрических контуров). Колонка
|
||||
-- cad_territorial_zones.geom = GEOGRAPHY(POLYGON, 4326) strict → INSERT
|
||||
-- падал через SAVEPOINT в per-row begin_nested() и строки молча дропались.
|
||||
--
|
||||
-- Поведение зеркалит cad_zouit (фикс в 93_cad_parcels_geom_multipolygon.sql
|
||||
-- как прецедент); патч _save_territorial_zones аналогичен upsert_zouit.
|
||||
--
|
||||
-- Действия:
|
||||
-- 1. ALTER COLUMN geom TYPE geography(MultiPolygon, 4326)
|
||||
-- USING ST_Multi(geom::geometry)::geography
|
||||
-- — lossless conversion существующих Polygon-строк в MultiPolygon.
|
||||
-- 2. DROP + CREATE GIST-индекса (ALTER TYPE требует пересоздания индекса
|
||||
-- для geography-колонки).
|
||||
--
|
||||
-- Idempotent: DO $$...END$$ проверяет текущий type по geometry_columns
|
||||
-- (geography тоже попадает через postgis_topology_views). Если уже
|
||||
-- MultiPolygon — пропускает ALTER; GIST пересоздаётся DROP IF EXISTS + IF NOT EXISTS.
|
||||
--
|
||||
-- Зависимые VIEW: нет (проверено grep data/sql/ и backend/).
|
||||
-- Apply after: 158_pzz_zones_ekb_nulls_not_distinct.sql
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1. ALTER COLUMN: POLYGON → MULTIPOLYGON (idempotent через geometry_columns)
|
||||
DO $$
|
||||
DECLARE
|
||||
current_type TEXT;
|
||||
BEGIN
|
||||
SELECT upper(type) INTO current_type
|
||||
FROM geometry_columns
|
||||
WHERE f_table_name = 'cad_territorial_zones'
|
||||
AND f_geometry_column = 'geom';
|
||||
|
||||
IF current_type = 'POLYGON' THEN
|
||||
ALTER TABLE cad_territorial_zones
|
||||
ALTER COLUMN geom TYPE geography(MultiPolygon, 4326)
|
||||
USING ST_Multi(geom::geometry)::geography;
|
||||
RAISE NOTICE 'cad_territorial_zones.geom converted POLYGON -> MULTIPOLYGON (rows: %)',
|
||||
(SELECT COUNT(*) FROM cad_territorial_zones WHERE geom IS NOT NULL);
|
||||
ELSE
|
||||
RAISE NOTICE 'cad_territorial_zones.geom type=% — skip ALTER', current_type;
|
||||
END IF;
|
||||
END$$;
|
||||
|
||||
-- 2. GIST индекс — DROP + CREATE (тип column изменился, индекс пересоздаём)
|
||||
DROP INDEX IF EXISTS cad_territorial_zones_geom_gist;
|
||||
CREATE INDEX IF NOT EXISTS cad_territorial_zones_geom_gist
|
||||
ON cad_territorial_zones USING GIST (geom);
|
||||
|
||||
COMMIT;
|
||||
Loading…
Add table
Reference in a new issue