Support ClickHouse geo types (Point, Ring, LineString, MultiLineString, Polygon, MultiPolygon) - #144
Open
Maksim-Burtsev wants to merge 2 commits into
Open
Support ClickHouse geo types (Point, Ring, LineString, MultiLineString, Polygon, MultiPolygon)#144Maksim-Burtsev wants to merge 2 commits into
Maksim-Burtsev wants to merge 2 commits into
Conversation
ClickHouse 26.7 made `explain_query_plan_default = 'pretty'` the default,
and the pretty plan carries a blank line between the output columns and
the plan tree. A blank TSV line decodes to an empty Record (that is what
the `WITH TOTALS` separator looks like), so indexing every row of an
EXPLAIN result stopped working.
EXPLAIN SYNTAX also renders operators as function calls now
("SELECT plus(1, 1)"), so the test no longer asserts the exact spelling.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Point, Ring, LineString, MultiLineString, Polygon and MultiPolygon are named composites, so each one is a type class inheriting the Tuple/Array it is stored as. Works on all three engines (TSV, RowBinary, Native). In _types.pyx TupleType and ArrayType now parse their name in __init__ instead of __cinit__: Cython runs a base __cinit__ before the subclass and with the original arguments, so a geo subclass could not otherwise hand its composite name down. Closes maximdanilchenko#136 partially (geo part only). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Maksim-Burtsev
force-pushed
the
geo-types
branch
from
August 21, 2026 20:47
71a63f4 to
fa7a79d
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.
Adds the geo types requested in #136. The other types from that issue (JSON/Object, Variant, Dynamic) are untouched here — they need their own serialization work, so I kept this PR to geo.
What's inside
Geo types are named composites:
PointisTuple(Float64, Float64),RingandLineStringareArray(Point),PolygonisArray(Ring),MultiPolygonisArray(Polygon), and ClickHouse serializes them exactly that way on every format. So there are no new codecs here — each geo type is a type class that inherits the composite it is stored as and hands that composite's name to the base:They are registered in
CH_TYPES_MAPPINGlike every other type, so TSV and RowBinary work through the existing machinery in both directions, nesting included (Array(Point),Nullable(Point),Map(String, Polygon)).what_py_typeitself is unchanged.The Native engine dispatches on the type string rather than on a type object — a columnar
Array/Tupleis offsets plus sub-columns, not per-value RowBinary — so it resolves the composite throughGEO_WIRE_TYPES, a table derived from the geo classes themselves rather than maintained by hand. Both lookups sit where the existing checks have already missed, so nothing extra runs for anyone who doesn't use geo columns.The Python → ClickHouse direction needed nothing: a point is a
tuple, a ring is alist.One structural change worth your attention
In
_types.pyx,TupleTypeandArrayTypenow parse their name in__init__instead of__cinit__. Cython runs a base__cinit__before the subclass and with the original arguments, so otherwise a geo subclass has no way to pass its composite name down (it blows up onRE_TUPLE.findall("Point")[0]). The bodies are unchanged, and the whole Tuple/Array/Map/Nested suite covers the change. Type objects are built once per column per query, so__cinit__vs__init__makes no measurable difference — benchmarks before/after are within noise.TupleType.nameandArrayType.namebecamereadonlysoGEO_WIRE_TYPEScan read the composite back out of the classes.Tests
New
test_geo_typesinTestTypes, which is already parametrized over all three engines and both inserts and reads through the engine under test.TestNative.test_unsupported_type_raisesandtest_gc_state_restored_after_decode_errorusedPointas their "not in the type mapping" example; they now useINTERVAL 1 DAY.I also ran, outside the suite: all nine insert-engine × read-engine combinations; nested geo (
Array(Point),Tuple(String, Polygon),Map(String, Ring), andNullable(Point)withenable_nullable_tuple_type=1); empty rings and polygons; a polygon with a hole; negative and fractional coordinates. Full suite passes in both builds (pure Python and with the Cython extension).LineString/MultiLineStringrequire ClickHouse 24.x+; the other four are fine on 22.x+. README and CHANGELOG updated.Unrelated, but noticed while running the suite:
TestFetching::test_explain_with_fetchfails on current master against ClickHouse 26.7 —EXPLAIN SELECT 1now returns an empty line in the middle of its output, which becomes an emptyRecord. Not touched here.