PostGIS  3.7.0dev-r@@SVN_REVISION@@
gserialized.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright 2022 Loïc Bartoletti <loic.bartoletti@oslandia.com>
22  * Copyright 2019 Darafei Praliaskouski <me@komzpa.net>
23  * Copyright 2019-2020 Raúl Marín <git@rmr.ninja>
24  * Copyright 2019 Regina Obe <lr@pcorp.us>
25  * Copyright 2019 Paul Ramsey <pramsey@cleverelephant.ca>
26  * Copyright 2004-2024 Sandro Santilli <strk@kbt.io>
27  *
28  **********************************************************************/
29 
30 #include "liblwgeom_internal.h"
31 #include "gserialized1.h"
32 #include "gserialized2.h"
33 
34 /* First four bits don't change between v0 and v1 */
35 #define GFLAG_Z 0x01
36 #define GFLAG_M 0x02
37 #define GFLAG_BBOX 0x04
38 #define GFLAG_GEODETIC 0x08
39 /* v1 and v2 MUST share the same version bits */
40 #define GFLAG_VER_0 0x40
41 #define GFLAGS_GET_VERSION(gflags) (((gflags) & GFLAG_VER_0)>>6)
42 
48 {
49  if (GFLAGS_GET_VERSION(g->gflags))
50  return gserialized2_get_lwflags(g);
51  else
52  return gserialized1_get_lwflags(g);
53 }
54 
61 {
62  if (GFLAGS_GET_VERSION(g->gflags))
63  return gserialized2_set_gbox(g, gbox);
64  else
65  return gserialized1_set_gbox(g, gbox);
66 }
67 
72 {
73  return GFLAGS_GET_VERSION(g->gflags);
74 }
75 
76 
82 {
83  if (GFLAGS_GET_VERSION(g->gflags))
84  return gserialized2_drop_gbox(g);
85  else
86  return gserialized1_drop_gbox(g);
87 }
88 
95 {
96  if (GFLAGS_GET_VERSION(g->gflags))
97  return gserialized2_get_gbox_p(g, gbox);
98  else
99  return gserialized1_get_gbox_p(g, gbox);
100 }
101 
107 {
108  if (GFLAGS_GET_VERSION(g->gflags))
109  return gserialized2_fast_gbox_p(g, gbox);
110  else
111  return gserialized1_fast_gbox_p(g, gbox);
112 }
113 
119 {
120  if (GFLAGS_GET_VERSION(g->gflags))
121  return gserialized2_get_type(g);
122  else
123  return gserialized1_get_type(g);
124 }
125 
131 {
132  size_t sz1 = gserialized1_max_header_size();
133  size_t sz2 = gserialized2_max_header_size();
134  return sz1 > sz2 ? sz1 : sz2;
135 }
136 
142 int32_t
144 {
145  if (GFLAGS_GET_VERSION(g->gflags))
146  return gserialized2_hash(g);
147  else
148  return gserialized1_hash(g);
149 }
150 
156 {
157  if (GFLAGS_GET_VERSION(g->gflags))
158  return gserialized2_get_srid(g);
159  else
160  return gserialized1_get_srid(g);
161 }
162 
167 void gserialized_set_srid(GSERIALIZED *g, int32_t srid)
168 {
169  if (GFLAGS_GET_VERSION(g->gflags))
170  gserialized2_set_srid(g, srid);
171  else
172  gserialized1_set_srid(g, srid);
173 }
174 
182 {
183  if (GFLAGS_GET_VERSION(g->gflags))
184  return gserialized2_is_empty(g);
185  else
186  return gserialized1_is_empty(g);
187 }
188 
193 {
194  if (GFLAGS_GET_VERSION(g->gflags))
195  return gserialized2_has_bbox(g);
196  else
197  return gserialized1_has_bbox(g);
198 }
199 
204 {
205  if (GFLAGS_GET_VERSION(g->gflags))
206  return gserialized2_has_z(g);
207  else
208  return gserialized1_has_z(g);
209 }
210 
215 {
216  if (GFLAGS_GET_VERSION(g->gflags))
217  return gserialized2_has_m(g);
218  else
219  return gserialized1_has_m(g);
220 }
221 
226 {
227  if (GFLAGS_GET_VERSION(g->gflags))
228  return gserialized2_is_geodetic(g);
229  else
230  return gserialized1_is_geodetic(g);
231 }
232 
237 {
238  if (GFLAGS_GET_VERSION(g->gflags))
239  return gserialized2_ndims(g);
240  else
241  return gserialized1_ndims(g);
242 }
243 
252 {
253  return gserialized2_from_lwgeom(geom, size);
254 }
255 
260 {
261  return gserialized2_from_lwgeom_size(geom);
262 }
263 
269 {
270  if (GFLAGS_GET_VERSION(g->gflags))
271  return lwgeom_from_gserialized2(g);
272  else
273  return lwgeom_from_gserialized1(g);
274 }
275 
276 
277 const float * gserialized_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
278 {
279  if (GFLAGS_GET_VERSION(g->gflags))
280  return gserialized2_get_float_box_p(g, ndims);
281  else
282  return gserialized1_get_float_box_p(g, ndims);
283 }
284 
285 int
287 {
288  if (GFLAGS_GET_VERSION(g->gflags))
289  return gserialized2_peek_first_point(g, out_point);
290  else
291  return gserialized1_peek_first_point(g, out_point);
292 }
293 
306 #define G2FLAG_EXTENDED 0x10
307 inline static size_t gserialized_header_size(const GSERIALIZED *g)
308 {
309  size_t sz = 8; /* varsize (4) + srid(3) + flags (1) */
310 
311  if ((GFLAGS_GET_VERSION(g->gflags)) &&
312  (G2FLAG_EXTENDED & g->gflags))
313  sz += 8;
314 
315  if (GFLAG_BBOX & g->gflags)
316  {
317  if (GFLAG_GEODETIC & g->gflags)
318  {
319  sz += 6 * sizeof(float);
320  }
321  else
322  {
323  sz += 4 * sizeof(float) +
324  ((GFLAG_Z & g->gflags) ? 2*sizeof(float) : 0) +
325  ((GFLAG_M & g->gflags) ? 2*sizeof(float) : 0);
326  }
327  }
328 
329  return sz;
330 }
331 
332 inline static int gserialized_cmp_srid(const GSERIALIZED *g1, const GSERIALIZED *g2)
333 {
334  return (
335  g1->srid[0] == g2->srid[0] &&
336  g1->srid[1] == g2->srid[1] &&
337  g1->srid[2] == g2->srid[2]
338  ) ? 0 : 1;
339 }
340 
341 /* ORDER BY hash(g), g::bytea, ST_SRID(g), hasz(g), hasm(g) */
342 int gserialized_cmp(const GSERIALIZED *g1, const GSERIALIZED *g2)
343 {
344  GBOX box1 = {0}, box2 = {0};
345  uint64_t hash1, hash2;
346  size_t sz1 = LWSIZE_GET(g1->size);
347  size_t sz2 = LWSIZE_GET(g2->size);
348  size_t hsz1 = gserialized_header_size(g1);
349  size_t hsz2 = gserialized_header_size(g2);
350  uint8_t *b1 = (uint8_t*)g1 + hsz1;
351  uint8_t *b2 = (uint8_t*)g2 + hsz2;
352  size_t bsz1 = sz1 - hsz1;
353  size_t bsz2 = sz2 - hsz2;
354  size_t bsz_min = bsz1 < bsz2 ? bsz1 : bsz2;
355 
356  /* Equality fast path */
357  /* Return equality for perfect equality only */
358  int cmp_srid = gserialized_cmp_srid(g1, g2);
359  int cmp = memcmp(b1, b2, bsz_min);
360  int g1hasz = gserialized_has_z(g1);
361  int g1hasm = gserialized_has_m(g1);
362  int g2hasz = gserialized_has_z(g2);
363  int g2hasm = gserialized_has_m(g2);
364 
365  if (bsz1 == bsz2 && cmp_srid == 0 && cmp == 0 && g1hasz == g2hasz && g1hasm == g2hasm)
366  return 0;
367  else
368  {
369  int g1_is_empty = (gserialized_get_gbox_p(g1, &box1) == LW_FAILURE);
370  int g2_is_empty = (gserialized_get_gbox_p(g2, &box2) == LW_FAILURE);
371  int32_t srid1 = gserialized_get_srid(g1);
372  int32_t srid2 = gserialized_get_srid(g2);
373 
374  /* Empty < Non-empty */
375  if (g1_is_empty && !g2_is_empty)
376  return -1;
377 
378  /* Non-empty > Empty */
379  if (!g1_is_empty && g2_is_empty)
380  return 1;
381 
382  if (!g1_is_empty && !g2_is_empty)
383  {
384  /* Using the boxes, calculate sortable hash key. */
385  hash1 = gbox_get_sortable_hash(&box1, srid1);
386  hash2 = gbox_get_sortable_hash(&box2, srid2);
387 
388  if (hash1 > hash2)
389  return 1;
390  if (hash1 < hash2)
391  return -1;
392  }
393 
394  /* Prefix comes before longer one. */
395  if (bsz1 != bsz2 && cmp == 0)
396  {
397  if (bsz1 < bsz2)
398  return -1;
399  return 1;
400  }
401 
402  /* If SRID is not equal, sort on it */
403  if (cmp_srid != 0)
404  return (srid1 > srid2) ? 1 : -1;
405 
406  /* ZM flag sort*/
407  if (g1hasz != g2hasz)
408  return (g1hasz > g2hasz) ? 1 : -1;
409 
410  if (g1hasm != g2hasm)
411  return (g1hasm > g2hasm) ? 1 : -1;
412 
413  assert(cmp != 0);
414  return cmp > 0 ? 1 : -1;
415  }
416 }
417 
418 uint64_t
420 {
421  GBOX box;
422  int is_empty = (gserialized_get_gbox_p(g, &box) == LW_FAILURE);
423 
424  if (is_empty)
425  return 0;
426  else
428 }
429 
430 void gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname);
431 void
432 gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname)
433 {
434  int32_t srid1 = gserialized_get_srid(g1);
435  int32_t srid2 = gserialized_get_srid(g2);
436  if (srid1 != srid2)
437  lwerror("%s: Operation on mixed SRID geometries (%s, %d) != (%s, %d)",
438  funcname,
440  srid1,
442  srid2);
443 }
444 
445 void gserialized_error_if_srid_mismatch_reference(const GSERIALIZED *g1, const int32_t srid2, const char *funcname);
446 void
447 gserialized_error_if_srid_mismatch_reference(const GSERIALIZED *g1, const int32_t srid2, const char *funcname)
448 {
449  int32_t srid1 = gserialized_get_srid(g1);
450  if (srid1 != srid2)
451  lwerror("%s: Operation on mixed SRID geometries %s %d != %d",
452  funcname,
454  srid1,
455  srid2);
456 }
uint64_t gbox_get_sortable_hash(const GBOX *g, const int32_t srid)
Return a sortable key based on the center point of the GBOX.
Definition: gbox.c:808
int gserialized1_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: gserialized1.c:204
int gserialized1_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized1.c:96
int32_t gserialized1_hash(const GSERIALIZED *g1)
Returns a hash code for the srid/type/geometry information in the GSERIALIZED.
Definition: gserialized1.c:227
int gserialized1_ndims(const GSERIALIZED *gser)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: gserialized1.c:106
lwflags_t gserialized1_get_lwflags(const GSERIALIZED *g)
Read the flags from a GSERIALIZED and return a standard lwflag integer.
Definition: gserialized1.c:41
int32_t gserialized1_get_srid(const GSERIALIZED *s)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: gserialized1.c:143
int gserialized1_get_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and calculate one if it is not already there.
Definition: gserialized1.c:529
uint32_t gserialized1_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
Definition: gserialized1.c:132
int gserialized1_has_bbox(const GSERIALIZED *gser)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: gserialized1.c:91
GSERIALIZED * gserialized1_set_gbox(GSERIALIZED *g, GBOX *gbox)
Update the bounding box of a GSERIALIZED, allocating a fresh one if there is not enough space to just...
uint32_t gserialized1_max_header_size(void)
Returns the size in bytes to read from toast to get the basic information from a geometry: GSERIALIZE...
Definition: gserialized1.c:116
LWGEOM * lwgeom_from_gserialized1(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized1_has_m(const GSERIALIZED *gser)
Check if a GSERIALIZED has an M ordinate.
Definition: gserialized1.c:101
const float * gserialized1_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
Point into the float box area of the serialization.
int gserialized1_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
Definition: gserialized1.c:492
int gserialized1_is_geodetic(const GSERIALIZED *gser)
Check if a GSERIALIZED is a geography.
Definition: gserialized1.c:111
void gserialized1_set_srid(GSERIALIZED *s, int32_t srid)
Write the SRID into the serialized form (it is packed into three bytes so this is a handy function).
Definition: gserialized1.c:160
GSERIALIZED * gserialized1_drop_gbox(GSERIALIZED *g)
Remove the bounding box from a GSERIALIZED.
int gserialized1_fast_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and fail if it is not already there.
Definition: gserialized1.c:558
int gserialized2_fast_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and fail if it is not already there.
Definition: gserialized2.c:612
int32_t gserialized2_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: gserialized2.c:191
int gserialized2_is_geodetic(const GSERIALIZED *g)
Check if a GSERIALIZED is a geography.
Definition: gserialized2.c:173
void gserialized2_set_srid(GSERIALIZED *g, int32_t srid)
Write the SRID into the serialized form (it is packed into three bytes so this is a handy function).
Definition: gserialized2.c:208
int gserialized2_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized2.c:158
int32_t gserialized2_hash(const GSERIALIZED *g1)
Returns a hash code for the srid/type/geometry information in the GSERIALIZED.
Definition: gserialized2.c:269
const float * gserialized2_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
Point into the float box area of the serialization.
Definition: gserialized2.c:295
uint32_t gserialized2_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
Definition: gserialized2.c:185
int gserialized2_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: gserialized2.c:252
int gserialized2_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
Definition: gserialized2.c:550
int gserialized2_ndims(const GSERIALIZED *g)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: gserialized2.c:168
LWGEOM * lwgeom_from_gserialized2(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized2_get_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and calculate one if it is not already there.
Definition: gserialized2.c:583
size_t gserialized2_from_lwgeom_size(const LWGEOM *geom)
Return the memory size a GSERIALIZED will occupy for a given LWGEOM.
Definition: gserialized2.c:777
GSERIALIZED * gserialized2_set_gbox(GSERIALIZED *g, GBOX *gbox)
Update the bounding box of a GSERIALIZED, allocating a fresh one if there is not enough space to just...
int gserialized2_has_m(const GSERIALIZED *g)
Check if a GSERIALIZED has an M ordinate.
Definition: gserialized2.c:163
GSERIALIZED * gserialized2_drop_gbox(GSERIALIZED *g)
Remove the bounding box from a GSERIALIZED.
GSERIALIZED * gserialized2_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
uint32_t gserialized2_max_header_size(void)
Returns the size in bytes to read from toast to get the basic information from a geometry: GSERIALIZE...
Definition: gserialized2.c:178
lwflags_t gserialized2_get_lwflags(const GSERIALIZED *g)
Read the flags from a GSERIALIZED and return a standard lwflag integer.
Definition: gserialized2.c:59
int gserialized2_has_bbox(const GSERIALIZED *g)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: gserialized2.c:148
size_t gserialized_from_lwgeom_size(const LWGEOM *geom)
Return the memory size a GSERIALIZED will occupy for a given LWGEOM.
Definition: gserialized.c:259
void gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname)
Definition: gserialized.c:432
void gserialized_error_if_srid_mismatch_reference(const GSERIALIZED *g1, const int32_t srid2, const char *funcname)
Definition: gserialized.c:447
#define GFLAG_GEODETIC
Definition: gserialized.c:38
int gserialized_has_bbox(const GSERIALIZED *g)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: gserialized.c:192
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: gserialized.c:155
static size_t gserialized_header_size(const GSERIALIZED *g)
Definition: gserialized.c:307
int gserialized_is_geodetic(const GSERIALIZED *g)
Check if a GSERIALIZED is a geography.
Definition: gserialized.c:225
int gserialized_ndims(const GSERIALIZED *g)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: gserialized.c:236
uint32_t gserialized_get_version(const GSERIALIZED *g)
Return the serialization version.
Definition: gserialized.c:71
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Read the box from the GSERIALIZED or calculate it if necessary.
Definition: gserialized.c:94
int gserialized_has_m(const GSERIALIZED *g)
Check if a GSERIALIZED has an M ordinate.
Definition: gserialized.c:214
int gserialized_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
Pull the first point values of a GSERIALIZED.
Definition: gserialized.c:286
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:268
static int gserialized_cmp_srid(const GSERIALIZED *g1, const GSERIALIZED *g2)
Definition: gserialized.c:332
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: gserialized.c:181
const float * gserialized_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
Access to the float bounding box, if there is one.
Definition: gserialized.c:277
void gserialized_set_srid(GSERIALIZED *g, int32_t srid)
Write the SRID into the serialized form (it is packed into three bytes so this is a handy function).
Definition: gserialized.c:167
#define GFLAGS_GET_VERSION(gflags)
Definition: gserialized.c:41
#define GFLAG_Z
Definition: gserialized.c:35
#define G2FLAG_EXTENDED
Return -1 if g1 is "less than" g2, 1 if g1 is "greater than" g2 and 0 if g1 and g2 are the "same".
Definition: gserialized.c:306
#define GFLAG_BBOX
Definition: gserialized.c:37
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized.c:203
uint64_t gserialized_get_sortable_hash(const GSERIALIZED *g)
Return a sortable key based on gserialized.
Definition: gserialized.c:419
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
Definition: gserialized.c:118
GSERIALIZED * gserialized_set_gbox(GSERIALIZED *g, GBOX *gbox)
Copy a new bounding box into an existing gserialized.
Definition: gserialized.c:60
uint32_t gserialized_max_header_size(void)
Returns the size in bytes to read from toast to get the basic information from a geometry: GSERIALIZE...
Definition: gserialized.c:130
GSERIALIZED * gserialized_drop_gbox(GSERIALIZED *g)
Remove the bounding box from a GSERIALIZED.
Definition: gserialized.c:81
#define GFLAG_M
Definition: gserialized.c:36
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
Definition: gserialized.c:251
int gserialized_fast_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Read the box from the GSERIALIZED or return #LWFAILURE if box is unavailable.
Definition: gserialized.c:106
lwflags_t gserialized_get_lwflags(const GSERIALIZED *g)
Read the flags from a GSERIALIZED and return a standard lwflag integer.
Definition: gserialized.c:47
int32_t gserialized_hash(const GSERIALIZED *g)
Returns a hash code for the srid/type/geometry information in the GSERIALIZED.
Definition: gserialized.c:143
int gserialized_cmp(const GSERIALIZED *g1, const GSERIALIZED *g2)
Return -1 if g1 is "less than" g2, 1 if g1 is "greater than" g2 and 0 if g1 and g2 are the "same".
Definition: gserialized.c:342
#define LW_FAILURE
Definition: liblwgeom.h:96
#define LWSIZE_GET(varsize)
Macro for reading the size from the GSERIALIZED size attribute.
Definition: liblwgeom.h:324
uint16_t lwflags_t
Definition: liblwgeom.h:299
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
uint8_t srid[3]
Definition: liblwgeom.h:445
uint32_t size
Definition: liblwgeom.h:444
uint8_t gflags
Definition: liblwgeom.h:446