Skip to content

MDEV-39981 Fix ST_GEOMFROMGEOJSON returning wrong result with reverse…#5243

Open
akshatnehra wants to merge 1 commit into
MariaDB:mainfrom
akshatnehra:MDEV-39981
Open

MDEV-39981 Fix ST_GEOMFROMGEOJSON returning wrong result with reverse…#5243
akshatnehra wants to merge 1 commit into
MariaDB:mainfrom
akshatnehra:MDEV-39981

Conversation

@akshatnehra

Copy link
Copy Markdown
Contributor

Description

This PR fixes MDEV-39981 where ST_GEOMFROMGEOJSON() crashes or returns wrong results when GeoJSON keys appear in a non-standard order (e.g., "geometries" before "type").

The GeoJSON parser in spatial.cc expects "type" to appear before other keys. When "geometries", "features", or "geometry" appear first, the parser saves the value start position for later re-parsing but fails to call json_skip_level() to advance the scanner past the value. This leaves the JSON scanner in an inconsistent state, causing crashes or incorrect parsing of subsequent keys.

The fix involves:

  1. Adding json_skip_level() calls in the three affected key handlers (geometries, features, geometry) when the type has not yet been determined — matching the existing pattern already used by the coordinates handler.

How can this PR be tested?

Run the MTR test:

build/mysql-test/mtr main.mdev_39981

Or manually (crashes without fix):

SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[],"type":"GeometryCollection"}'));
SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[5,6]},"properties":{}}],"type":"FeatureCollection"}'));
SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometry":{"type":"Point","coordinates":[7,8]},"type":"Feature","properties":{}}'));

Results from my testing

  1. Before changes (server crashes)
MariaDB> SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[],"type":"GeometryCollection"}'));
ERROR 2026 (HY000): TLS/SSL error: unexpected eof while reading
-- (server crashed)
  1. After changes
MariaDB> SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[],"type":"GeometryCollection"}')) AS r1;
+------------------------+
| r1                     |
+------------------------+
| GEOMETRYCOLLECTION EMPTY|
+------------------------+

MariaDB> SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"features":[...],"type":"FeatureCollection"}')) AS r2;
+------------------------------+
| r2                           |
+------------------------------+
| GEOMETRYCOLLECTION(POINT(5 6))|
+------------------------------+

MariaDB> SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometry":{"type":"Point","coordinates":[7,8]},"type":"Feature","properties":{}}')) AS r3;
+------------+
| r3         |
+------------+
| POINT(7 8) |
+------------+

GeoJSON is now parsed correctly regardless of key order, as required by the RFC 7946 spec (key order MUST NOT affect interpretation).

Basing the PR against the correct MariaDB version

  • This is a bug fix and the PR is based against the latest MariaDB development branch.

PR quality check

  • I have checked the CODING_STANDARDS.md file and my PR conforms to this where appropriate.
  • For any trivial modifications to the PR, I am fine with the reviewer making the changes themselves.

…d key order

ST_GEOMFROMGEOJSON requires JSON keys to appear in a specific order
(type before geometries/features/geometry/coordinates). When keys
appear in a different order, the JSON scanner is left in an
inconsistent state because json_skip_level() is not called to advance
past the value when the type has not yet been determined.

Fix: add json_skip_level() calls in the geometries, features, and
geometry key handlers when the type key has not yet been encountered.
This mirrors the existing pattern in the coordinates handler.

All new code of the whole pull request, including one or several files
that are either new files or modified ones, are contributed under the
BSD-new license. I am contributing on behalf of my employer Amazon Web
Services, Inc.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses MDEV-39981, where ST_GEOMFROMGEOJSON returns incorrect results when GeoJSON keys are in a reversed order (such as coordinates or geometries appearing before the type). The fix introduces calls to json_skip_level in sql/spatial.cc to properly skip over nested structures when searching for the type key. Comprehensive test cases have been added to verify various geometries and key orderings. No review comments were provided, and there is no additional feedback to offer.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@gkodinov gkodinov added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Jun 16, 2026

@grooverdan grooverdan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks very much for writing this. I was currently working on MDEV-39813 and was seeing this gap in implementation.

As a bug fix, can you rebase base to 10.11. There is a chance I could take it to 106 if needed to complete MDEV-39813, but I'm reviewing this to ensure changes don't conflict.

If you can take my suggested fixes on for MDEV-39989 and put them on the same branch it would ensure they don't conflict or merge incorrectly. One more MDEV-39989 fix is in coordinates for type !== JSON_VALUE_ARRAY, break;.

This only fixes part of the geometries processing MDEV-39989 invalid calls, however the MDEV-39813 will replace the json_scan_start additional calls, and might correct the processing of other GIS types.

@@ -0,0 +1,38 @@
--echo #
--echo # MDEV-39981: ST_GEOMFROMGEOJSON returns wrong result with reversed key order

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these tests be moved to the bottom of mysql-test/main/gis-json.test

--echo #

--echo # GeometryCollection: type before geometries (baseline)
SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"type":"GeometryCollection","geometries":[]}'));

@grooverdan grooverdan Jun 16, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you run this test with mtr --view-protocol it will fail. The solution is to use SELECT ST_ASTEXT(......) as exp as a pattern to give every result a simple name. Same with all other queries.

Thanks for the incremental headers as separation.

SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"foo":"bar","geometries":[],"type":"GeometryCollection","extra":123}'));

--echo # Deeply nested geometries before type
SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[{"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[9,10]}]}],"type":"GeometryCollection"}'));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could re-order the "type: Point" and its "coordinates" within the nested version.


--echo # Deeply nested geometries before type
SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"geometries":[{"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[9,10]}]}],"type":"GeometryCollection"}'));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Below would be `--echo # End of 10.11 tests" once moved.

Comment thread sql/spatial.cc
goto create_geom;
}
if (json_skip_level(je))
goto err_return;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just below the below } we could append else break; which would catch where geometries is something other than an array. It could be considered part of MDEV-39989.

Comment thread sql/spatial.cc
if (fcoll_type_found)
goto handle_feature_collection;
if (json_skip_level(je))
goto err_return;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like above, features can only be an array. Same else break (!= JSON_VALUE_ARRAY) to report error.

Comment thread sql/spatial.cc
if (feature_type_found)
goto handle_geometry_key;
if (json_skip_level(je))
goto err_return;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Geometry is a object type only. Like above, can result in error with else break; condition

SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"coordinates":[[[0,0],[1,0],[1,1],[0,1],[0,0]]],"type":"Polygon"}'));

--echo # FeatureCollection: features before type
SELECT ST_ASTEXT(ST_GEOMFROMGEOJSON('{"features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[5,6]},"properties":{}}],"type":"FeatureCollection"}'));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could put type: Feature after geometry and type: point after properties. I expect the same, but it adds to the completeness of type last processing.

@grooverdan grooverdan self-assigned this Jun 16, 2026

@gkodinov gkodinov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution!

Daniel already is doing a great job in reviewing this, so I'll just restrict myself to the formalities: please rebase on 10.11 (as he has already suggested). And also format the test addition properly as suggested by him.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

3 participants