fix(places): resolve places on PostgreSQL without PostGIS - #36
Open
torvalstrom wants to merge 1 commit into
Open
fix(places): resolve places on PostgreSQL without PostGIS#36torvalstrom wants to merge 1 commit into
torvalstrom wants to merge 1 commit into
Conversation
queryPoint() calls ST_MakePoint/ST_SetSRID/ST_Contains on the PostgreSQL path. PostGIS is not part of a default Nextcloud database, and Memories does not ask for it: it stores memories_planet_geometry.geometry as PostgreSQL's built-in `polygon` type and queries it with built-in operators. So on a stock install this path throws for every single point. The failure is swallowed by the catch, which falls back to the per-file place map Memories precomputed. That hides it from users, but it leaves three real problems: - a doomed query issued once per photo per clustering run; - 183,700 identical error lines in one day on the install this was found on, each embedding the full SQL statement - 99% of that server's total error volume across all namespaces; - the app's own spatial lookup is dead, so results exist only for points backed by a file Memories has already indexed. queryPoint() cannot answer for an arbitrary coordinate, which is what its signature offers. Use the built-in geometric operators instead. They need no extension, and they are the indexable ones: the GiST index Memories creates on that column uses the `poly_ops` operator class, which covers polygon-vs-polygon `<@` but not point-vs-polygon - hence the degenerate single-vertex polygon built from the point. This is the same construction Memories itself uses in lib/Service/Places.php, so the semantics match the app that wrote the data. Verified on Nextcloud 34 / PostgreSQL 17, 660k-row planet table, no PostGIS. Called without a fileId so the fallback cannot mask the result, which isolates the spatial path - every one of these returned 0 places before: Kobenhavn 9.5 ms Europe/Copenhagen, Danmark, Region Hovedstaden, Kobenhavns Kommune Aarhus 32.2 ms Europe/Copenhagen, Danmark, Region Midtjylland, Aarhus Kommune Aalborg 14.0 ms Europe/Copenhagen, Danmark, Region Nordjylland, Aalborg Kommune Odense 3.0 ms Europe/Copenhagen, Danmark, Region Syddanmark, Odense Kommune Skagen 5.7 ms Europe/Copenhagen, Danmark, Region Nordjylland, Frederikshavn Kommune Atlantic 53.9 ms Etc/GMT+3 only The open-ocean control returns just a timezone, so the predicate is genuinely spatial and not matching everything. EXPLAIN ANALYZE: Bitmap Index Scan, 10 candidate rows, 1.7 ms - against a 437 ms parallel sequential scan for the non-indexable point form. Also in this change, both smaller and same theme - a failure that recurs per photo must not log per photo: - probe MySQL/MariaDB spatial support instead of assuming it, so a stripped build falls back cleanly rather than erroring per point; - log the resolver's DB errors once per request instead of once per point. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MX4KbhMZnJbCEWixnCETP5
torvalstrom
force-pushed
the
fix/postgres-place-lookup-without-postgis
branch
from
August 15, 2026 09:54
c443a0f to
f94b6c7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
SimplePlaceResolver::queryPoint()uses PostGIS functions on the PostgreSQL path:PostGIS is not part of a default Nextcloud database, and Memories does not ask for it — it stores
memories_planet_geometry.geometryas PostgreSQL's built-inpolygontype and queries it with built-in operators. So on a stock PostgreSQL install this path throws for every single point.The
catchswallows it and falls back to the per-file place map, so users mostly don't see wrong results. What it leaves behind:queryPoint()cannot answer for an arbitrary coordinate, which is what its signature offers.The fix
Use PostgreSQL's built-in geometric operators. No extension needed, and they are the indexable ones:
The GiST index Memories creates on that column uses the
poly_opsoperator class, which covers polygon-vs-polygon<@but not point-vs-polygon — hence the degenerate single-vertex polygon built from the point. This is the same construction Memories itself uses inlib/Service/Places.php, so the semantics match the app that wrote the data.sprintf('%.8F')rather than interpolation, so a float rendered under a locale with a decimal comma cannot producePOLYGON('55,67,12,56').Verification
Nextcloud 34, PostgreSQL 17, 660k-row planet table, no PostGIS. Driven through the real service via Nextcloud's DI container, and called without a
fileIdso the per-file fallback cannot mask the result — this isolates the spatial path. Every one of these returned 0 places before:The open-ocean control returns only a timezone, so the predicate is genuinely spatial rather than matching everything. Skagen correctly resolves to Frederikshavn Kommune.
EXPLAIN ANALYZEon the same table:planet_osm_polygon_geometry_idx, 10 candidate rows, 1.7 msAlso included
Both smaller, and the same theme — a failure that recurs per photo must not log per photo:
Happy to split those out if you'd prefer this PR to stay strictly to the PostgreSQL fix.
🤖 Generated with Claude Code