fix(cadastre,nspd_sync): batch SQL syntax bugs from ekb_full v2 logs #186

Merged
lekss361 merged 1 commit from fix/cadastre-sql-syntax-batch into main 2026-05-15 16:18:43 +00:00
lekss361 commented 2026-05-15 16:13:28 +00:00 (Migrated from github.com)

Summary

Three distinct SQL syntax bugs surfaced by ekb_full v2 (job_id=16) error logs. Batch fix.

Bugs

1. `upsert_zouit` — trailing comma in ST_Transform

`bulk_harvest.py:940`:
```sql
ST_Transform(
ST_SetSRID(ST_GeomFromGeoJSON(CAST(:geom AS text)), 3857),
4326, <-- trailing comma
)
```
→ `psycopg.errors.SyntaxError: syntax error at or near ")"`. Hit on 8+ quarters in 0108 block.

2. `nspd_sync` — `::timestamptz` double-colon trap

`nspd_sync.py:120`: `:fetched_at_utc::timestamptz` → SQLAlchemy/psycopg parses `:fetched_at_utc:` as ambiguous bind. Crashed legacy on-demand `harvest_quarter` called from analyze API.

3. `job_settings` — `::jsonb` double-colon trap

`job_settings.py:224`: `:extra_config::jsonb` → same trap in admin job_settings UPDATE.

All three converted to `CAST(:x AS type)` (psycopg v3 safe, established pattern per CLAUDE.md).

Test plan

  • 40 tests passing
  • After merge + deploy → retry ekb_full to surface remaining error types (if any)
## Summary Three distinct SQL syntax bugs surfaced by ekb_full v2 (job_id=16) error logs. Batch fix. ## Bugs ### 1. \`upsert_zouit\` — trailing comma in ST_Transform \`bulk_harvest.py:940\`: \`\`\`sql ST_Transform( ST_SetSRID(ST_GeomFromGeoJSON(CAST(:geom AS text)), 3857), 4326, <-- trailing comma ) \`\`\` → \`psycopg.errors.SyntaxError: syntax error at or near \")\"\`. Hit on 8+ quarters in 0108 block. ### 2. \`nspd_sync\` — \`::timestamptz\` double-colon trap \`nspd_sync.py:120\`: \`:fetched_at_utc::timestamptz\` → SQLAlchemy/psycopg parses \`:fetched_at_utc:\` as ambiguous bind. Crashed legacy on-demand \`harvest_quarter\` called from analyze API. ### 3. \`job_settings\` — \`::jsonb\` double-colon trap \`job_settings.py:224\`: \`:extra_config::jsonb\` → same trap in admin job_settings UPDATE. All three converted to \`CAST(:x AS type)\` (psycopg v3 safe, established pattern per CLAUDE.md). ## Test plan - [x] 40 tests passing - [ ] After merge + deploy → retry ekb_full to surface remaining error types (if any)
lekss361 commented 2026-05-15 16:18:33 +00:00 (Migrated from github.com)

Review

CI зелёный (backend 1m5s + frontend 1m39s) + cross-check (agent):

Fix 1: trailing comma в upsert_zouit

bulk_harvest.py:9404326,4326. Сравнил все остальные multi-line ST_Transform(..., 4326) (lines 453 upsert_parcel, 567 buildings, 1029 merge) — нигде trailing comma нет. Fix targeted, не оставляет других проблем.

Fix 2: :extra_config::jsonbCAST(:extra_config AS jsonb)

job_settings.py:224 — внутри update() SET-list builder (lines 200-235), :extra_config биндится через params["extra_config"] = json.dumps(...). Pattern совпадает с другими SET-list entries.

Fix 3: :fetched_at_utc::timestamptzCAST(:fetched_at_utc AS timestamptz)

nspd_sync.py:120 — внутри static _UPSERT_SQL = text("""..."""). Consistent с соседними CAST(:features_json AS jsonb) и CAST(:layers_fetched AS text[]) (lines 118-119).

Все CAST traps покрыты

Agent grep'нул backend/app/**/*.py (80 файлов) на :[a-z_]+::(jsonb|timestamptz|text|date|int|interval|bigint|...)zero remaining hits в коде, единственное упоминание в комментарии (bulk_harvest.py:15, документация правила). Других traps в кодбазе нет.

Drift отсутствует

Pure SQL runtime fix. No test additions — приемлемо per CAST precedent #152/#160/#178/#185 (psycopg AmbiguousParameter / SyntaxError ловится только runtime).

approve merge

## Review CI зелёный (backend 1m5s + frontend 1m39s) + cross-check (agent): ### ✅ Fix 1: trailing comma в upsert_zouit `bulk_harvest.py:940` — `4326,` → `4326`. Сравнил все остальные multi-line `ST_Transform(..., 4326)` (lines 453 upsert_parcel, 567 buildings, 1029 merge) — нигде trailing comma нет. Fix targeted, не оставляет других проблем. ### ✅ Fix 2: `:extra_config::jsonb` → `CAST(:extra_config AS jsonb)` `job_settings.py:224` — внутри `update()` SET-list builder (lines 200-235), `:extra_config` биндится через `params["extra_config"] = json.dumps(...)`. Pattern совпадает с другими SET-list entries. ### ✅ Fix 3: `:fetched_at_utc::timestamptz` → `CAST(:fetched_at_utc AS timestamptz)` `nspd_sync.py:120` — внутри static `_UPSERT_SQL = text("""...""")`. Consistent с соседними `CAST(:features_json AS jsonb)` и `CAST(:layers_fetched AS text[])` (lines 118-119). ### ✅ Все CAST traps покрыты Agent grep'нул `backend/app/**/*.py` (80 файлов) на `:[a-z_]+::(jsonb|timestamptz|text|date|int|interval|bigint|...)` — **zero remaining hits** в коде, единственное упоминание в комментарии (`bulk_harvest.py:15`, документация правила). Других traps в кодбазе нет. ### ✅ Drift отсутствует Pure SQL runtime fix. No test additions — приемлемо per CAST precedent #152/#160/#178/#185 (psycopg AmbiguousParameter / SyntaxError ловится только runtime). approve merge
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#186
No description provided.