Re: St_GeoHash: boundary handling in non-point case

Paul Ramsey via postgis-users <[email protected]> Fri, 30 Jan 2026 11:57:37 -0800
Newsgroups gmane.comp.gis.postgis
Message-ID <CACowWR2cZrvZp7ByxKJQyNqNjK8RZO49r7Oo28beP3iNjfDeuQ@mail.gmail.com>
--0000000000005428660649a0631a
Content-Type: multipart/alternative; boundary="0000000000005428640649a06318"

--0000000000005428640649a06318
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

It looks like just adjusting some gt/lt tests into gte/lte effects your
rount-trip test... it breaks one regression test, for ticket
https://trac.osgeo.org/postgis/ticket/4399 but that's it, and the test
isn't really pushing on geohash behaviour. I would need to add some tests
and confirm the behaviour is consistent in other ways.

P.

On Wed, Jan 28, 2026 at 9:26=E2=80=AFAM Sztegi <[email protected]> wrote:

> Hi!
>
> I have bumped into something I find counter intuitive with
> St_GeoHash() - boundary checking for non-point objects seems stricter
> than for points in case precision is not set:
>
> select st_geohash(ST_MakeLine(st_point(0, 0), st_point(0.00002, 0.00002))=
);
> -- returns "" <- this is unexpected, I expected "s00000000"
>
> This breaks my assumption that st_geoshash(st_geomfromgeohash(hash))
> will return the original geohash:
> select st_geohash(st_geomfromgeohash('s0'));
> -- returns "" <- I expected "s0"
>
> I bumped to this in Postgis 3.2.1 and it is still reproducible in 3.6.1
>
> Meanwhile if precision is set OR the geometry is a point OR it doesn't
> touch geohash boundaries then I get what I expect:
>
> select st_geohash(st_point(0, 0), 8));
> -- returns "s0000000"
>
> select st_geohash(st_point(0, 0));
> --- returns "s0000000000000000000"
>
> select st_geohash(ST_MakeLine(st_point(0, 0), st_point(0.00002, 0.00002))=
,
> 8);
> -- returns "s0000000"
>
> select st_geohash(ST_MakeLine(st_point(0.00001, 0.00001),
> st_point(0.00002, 0.00002)), 8);
> -- returns "s0000000"
>
> select st_geohash(ST_MakeLine(st_point(0.00001, 0.00001),
> st_point(0.00002, 0.00002)));
> -- returns "s00000000"
>
> I plan to create a bug report about this, but wanted to check first on
> the mailing list if this is something intended.
>
> These edge cases are interesting to me because I am trying to create
> an implementation of st_geohash()/st_geomfromgeohash() for two Apache
> projects (Hive, Impala), and cross- checked my tests with the results
> in postgis.
>
> regards,
> Csaba
>

--0000000000005428640649a06318
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">It looks like just adjusting some gt/lt tests into gte/lte=
 effects your rount-trip test... it breaks one regression test, for ticket=
=C2=A0<a href=3D"https://trac.osgeo.org/postgis/ticket/4399">https://trac.o=
sgeo.org/postgis/ticket/4399</a> but that&#39;s it, and the test isn&#39;t =
really pushing on geohash behaviour. I would need to add some tests and con=
firm the behaviour is consistent in other ways.<div><br></div><div>P.</div>=
</div><br><div class=3D"gmail_quote gmail_quote_container"><div dir=3D"ltr"=
 class=3D"gmail_attr">On Wed, Jan 28, 2026 at 9:26=E2=80=AFAM Sztegi &lt;<a=
 href=3D"mailto:[email protected]">[email protected]</a>&gt; wrote:<br></div>=
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);p=
adding-left:1ex">Hi!<br>
<br>
I have bumped into something I find counter intuitive with<br>
St_GeoHash() - boundary checking for non-point objects seems stricter<br>
than for points in case precision is not set:<br>
<br>
select st_geohash(ST_MakeLine(st_point(0, 0), st_point(0.00002, 0.00002)));=
<br>
-- returns &quot;&quot; &lt;- this is unexpected, I expected &quot;s0000000=
0&quot;<br>
<br>
This breaks my assumption that st_geoshash(st_geomfromgeohash(hash))<br>
will return the original geohash:<br>
select st_geohash(st_geomfromgeohash(&#39;s0&#39;));<br>
-- returns &quot;&quot; &lt;- I expected &quot;s0&quot;<br>
<br>
I bumped to this in Postgis 3.2.1 and it is still reproducible in 3.6.1<br>
<br>
Meanwhile if precision is set OR the geometry is a point OR it doesn&#39;t<=
br>
touch geohash boundaries then I get what I expect:<br>
<br>
select st_geohash(st_point(0, 0), 8));<br>
-- returns &quot;s0000000&quot;<br>
<br>
select st_geohash(st_point(0, 0));<br>
--- returns &quot;s0000000000000000000&quot;<br>
<br>
select st_geohash(ST_MakeLine(st_point(0, 0), st_point(0.00002, 0.00002)), =
8);<br>
-- returns &quot;s0000000&quot;<br>
<br>
select st_geohash(ST_MakeLine(st_point(0.00001, 0.00001),<br>
st_point(0.00002, 0.00002)), 8);<br>
-- returns &quot;s0000000&quot;<br>
<br>
select st_geohash(ST_MakeLine(st_point(0.00001, 0.00001),<br>
st_point(0.00002, 0.00002)));<br>
-- returns &quot;s00000000&quot;<br>
<br>
I plan to create a bug report about this, but wanted to check first on<br>
the mailing list if this is something intended.<br>
<br>
These edge cases are interesting to me because I am trying to create<br>
an implementation of st_geohash()/st_geomfromgeohash() for two Apache<br>
projects (Hive, Impala), and cross- checked my tests with the results<br>
in postgis.<br>
<br>
regards,<br>
Csaba<br>
</blockquote></div>

--0000000000005428640649a06318--

--0000000000005428660649a0631a
Content-Type: application/octet-stream; name="geohash-bounds.patch"
Content-Disposition: attachment; filename="geohash-bounds.patch"
Content-Transfer-Encoding: base64
Content-ID: <f_ml1axuqn0>
X-Attachment-Id: f_ml1axuqn0

ZGlmZiAtLWdpdCBhL2xpYmx3Z2VvbS9sd2FsZ29yaXRobS5jIGIvbGlibHdnZW9tL2x3YWxnb3Jp
dGhtLmMKaW5kZXggMGE0NjdkZmI2Li4yZGRjNzIxZGEgMTAwNjQ0Ci0tLSBhL2xpYmx3Z2VvbS9s
d2FsZ29yaXRobS5jCisrKyBiL2xpYmx3Z2VvbS9sd2FsZ29yaXRobS5jCkBAIC04MTIsMTEgKzgx
MiwxMSBAQCBpbnQgbHdnZW9tX2dlb2hhc2hfcHJlY2lzaW9uKEdCT1ggYmJveCwgR0JPWCAqYm91
bmRzKQogCQlsYXR3aWR0aCA9IGxhdG1heCAtIGxhdG1pbjsKIAkJbGF0bWF4YWRqdXN0ID0gbG9u
bWF4YWRqdXN0ID0gbGF0bWluYWRqdXN0ID0gbG9ubWluYWRqdXN0ID0gMC4wOwogCi0JCWlmICgg
bWlueCA+IGxvbm1pbiArIGxvbndpZHRoIC8gMi4wICkKKwkJaWYgKCBtaW54ID49IGxvbm1pbiAr
IGxvbndpZHRoIC8gMi4wICkKIAkJewogCQkJbG9ubWluYWRqdXN0ID0gbG9ud2lkdGggLyAyLjA7
CiAJCX0KLQkJZWxzZSBpZiAoIG1heHggPCBsb25tYXggLSBsb253aWR0aCAvIDIuMCApCisJCWVs
c2UgaWYgKCBtYXh4IDw9IGxvbm1heCAtIGxvbndpZHRoIC8gMi4wICkKIAkJewogCQkJbG9ubWF4
YWRqdXN0ID0gLTEgKiBsb253aWR0aCAvIDIuMDsKIAkJfQpAQCAtODMzLDExICs4MzMsMTEgQEAg
aW50IGx3Z2VvbV9nZW9oYXNoX3ByZWNpc2lvbihHQk9YIGJib3gsIEdCT1ggKmJvdW5kcykKIAkJ
CWJyZWFrOwogCQl9CiAKLQkJaWYgKCBtaW55ID4gbGF0bWluICsgbGF0d2lkdGggLyAyLjAgKQor
CQlpZiAoIG1pbnkgPj0gbGF0bWluICsgbGF0d2lkdGggLyAyLjAgKQogCQl7CiAJCQlsYXRtaW5h
ZGp1c3QgPSBsYXR3aWR0aCAvIDIuMDsKIAkJfQotCQllbHNlIGlmIChtYXh5IDwgbGF0bWF4IC0g
bGF0d2lkdGggLyAyLjAgKQorCQllbHNlIGlmIChtYXh5IDw9IGxhdG1heCAtIGxhdHdpZHRoIC8g
Mi4wICkKIAkJewogCQkJbGF0bWF4YWRqdXN0ID0gLTEgKiBsYXR3aWR0aCAvIDIuMDsKIAkJfQo=
--0000000000005428660649a0631a--