PostGIS  3.0.6dev-r@@SVN_REVISION@@
gserialized.c
Go to the documentation of this file.
1 #include "liblwgeom_internal.h"
2 #include "gserialized1.h"
3 #include "gserialized2.h"
4 
5 /* First four bits don't change between v0 and v1 */
6 #define GFLAG_Z 0x01
7 #define GFLAG_M 0x02
8 #define GFLAG_BBOX 0x04
9 #define GFLAG_GEODETIC 0x08
10 /* v1 and v2 MUST share the same version bits */
11 #define GFLAG_VER_0 0x40
12 #define GFLAGS_GET_VERSION(gflags) (((gflags) & GFLAG_VER_0)>>6)
13 
19 {
20  if (GFLAGS_GET_VERSION(g->gflags))
21  return gserialized2_get_lwflags(g);
22  else
23  return gserialized1_get_lwflags(g);
24 };
25 
32 {
33  if (GFLAGS_GET_VERSION(g->gflags))
34  return gserialized2_set_gbox(g, gbox);
35  else
36  return gserialized1_set_gbox(g, gbox);
37 }
38 
43 {
44  return GFLAGS_GET_VERSION(g->gflags);
45 }
46 
47 
53 {
54  if (GFLAGS_GET_VERSION(g->gflags))
55  return gserialized2_drop_gbox(g);
56  else
57  return gserialized1_drop_gbox(g);
58 }
59 
66 {
67  if (GFLAGS_GET_VERSION(g->gflags))
68  return gserialized2_get_gbox_p(g, gbox);
69  else
70  return gserialized1_get_gbox_p(g, gbox);
71 }
72 
78 {
79  if (GFLAGS_GET_VERSION(g->gflags))
80  return gserialized2_fast_gbox_p(g, gbox);
81  else
82  return gserialized1_fast_gbox_p(g, gbox);
83 }
84 
90 {
91  if (GFLAGS_GET_VERSION(g->gflags))
92  return gserialized2_get_type(g);
93  else
94  return gserialized1_get_type(g);
95 }
96 
102 {
103  size_t sz1 = gserialized1_max_header_size();
104  size_t sz2 = gserialized2_max_header_size();
105  return sz1 > sz2 ? sz1 : sz2;
106 }
107 
113 int32_t
115 {
116  if (GFLAGS_GET_VERSION(g->gflags))
117  return gserialized2_hash(g);
118  else
119  return gserialized1_hash(g);
120 }
121 
127 {
128  if (GFLAGS_GET_VERSION(g->gflags))
129  return gserialized2_get_srid(g);
130  else
131  return gserialized1_get_srid(g);
132 }
133 
138 void gserialized_set_srid(GSERIALIZED *g, int32_t srid)
139 {
140  if (GFLAGS_GET_VERSION(g->gflags))
141  return gserialized2_set_srid(g, srid);
142  else
143  return gserialized1_set_srid(g, srid);
144 }
145 
153 {
154  if (GFLAGS_GET_VERSION(g->gflags))
155  return gserialized2_is_empty(g);
156  else
157  return gserialized1_is_empty(g);
158 }
159 
164 {
165  if (GFLAGS_GET_VERSION(g->gflags))
166  return gserialized2_has_bbox(g);
167  else
168  return gserialized1_has_bbox(g);
169 }
170 
175 {
176  if (GFLAGS_GET_VERSION(g->gflags))
177  return gserialized2_has_z(g);
178  else
179  return gserialized1_has_z(g);
180 }
181 
186 {
187  if (GFLAGS_GET_VERSION(g->gflags))
188  return gserialized2_has_m(g);
189  else
190  return gserialized1_has_m(g);
191 }
192 
197 {
198  if (GFLAGS_GET_VERSION(g->gflags))
199  return gserialized2_is_geodetic(g);
200  else
201  return gserialized1_is_geodetic(g);
202 }
203 
208 {
209  if (GFLAGS_GET_VERSION(g->gflags))
210  return gserialized2_ndims(g);
211  else
212  return gserialized1_ndims(g);
213 }
214 
223 {
224  return gserialized2_from_lwgeom(geom, size);
225 }
226 
231 {
232  return gserialized2_from_lwgeom_size(geom);
233 }
234 
240 {
241  if (GFLAGS_GET_VERSION(g->gflags))
242  return lwgeom_from_gserialized2(g);
243  else
244  return lwgeom_from_gserialized1(g);
245 }
246 
247 
248 const float * gserialized_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
249 {
250  if (GFLAGS_GET_VERSION(g->gflags))
251  return gserialized2_get_float_box_p(g, ndims);
252  else
253  return gserialized1_get_float_box_p(g, ndims);
254 }
255 
256 int
258 {
259  if (GFLAGS_GET_VERSION(g->gflags))
260  return gserialized2_peek_first_point(g, out_point);
261  else
262  return gserialized1_peek_first_point(g, out_point);
263 }
264 
277 #define G2FLAG_EXTENDED 0x10
278 inline static size_t gserialized_header_size(const GSERIALIZED *g)
279 {
280  size_t sz = 8; /* varsize (4) + srid(3) + flags (1) */
281 
282  if ((GFLAGS_GET_VERSION(g->gflags)) &&
283  (G2FLAG_EXTENDED & g->gflags))
284  sz += 8;
285 
286  if (GFLAG_BBOX & g->gflags)
287  {
288  if (GFLAG_GEODETIC & g->gflags)
289  {
290  sz += 6 * sizeof(float);
291  }
292  else
293  {
294  sz += 4 * sizeof(float) +
295  ((GFLAG_Z & g->gflags) ? 2*sizeof(float) : 0) +
296  ((GFLAG_M & g->gflags) ? 2*sizeof(float) : 0);
297  }
298  }
299 
300  return sz;
301 }
302 
303 inline static int gserialized_cmp_srid(const GSERIALIZED *g1, const GSERIALIZED *g2)
304 {
305  return (
306  g1->srid[0] == g2->srid[0] &&
307  g1->srid[1] == g2->srid[1] &&
308  g1->srid[2] == g2->srid[2]
309  ) ? 0 : 1;
310 }
311 
312 /* ORDER BY hash(g), g::bytea, ST_SRID(g), hasz(g), hasm(g) */
313 int gserialized_cmp(const GSERIALIZED *g1, const GSERIALIZED *g2)
314 {
315  GBOX box1, box2;
316  uint64_t hash1, hash2;
317  size_t sz1 = SIZE_GET(g1->size);
318  size_t sz2 = SIZE_GET(g2->size);
319  size_t hsz1 = gserialized_header_size(g1);
320  size_t hsz2 = gserialized_header_size(g2);
321  uint8_t *b1 = (uint8_t*)g1 + hsz1;
322  uint8_t *b2 = (uint8_t*)g2 + hsz2;
323  size_t bsz1 = sz1 - hsz1;
324  size_t bsz2 = sz2 - hsz2;
325  size_t bsz_min = bsz1 < bsz2 ? bsz1 : bsz2;
326 
327  /* Equality fast path */
328  /* Return equality for perfect equality only */
329  int cmp_srid = gserialized_cmp_srid(g1, g2);
330  int cmp = memcmp(b1, b2, bsz_min);
331  int g1hasz = gserialized_has_z(g1);
332  int g1hasm = gserialized_has_m(g1);
333  int g2hasz = gserialized_has_z(g2);
334  int g2hasm = gserialized_has_m(g2);
335 
336  if (bsz1 == bsz2 && cmp_srid == 0 && cmp == 0 && g1hasz == g2hasz && g1hasm == g2hasm)
337  return 0;
338  else
339  {
340  int g1_is_empty = (gserialized_get_gbox_p(g1, &box1) == LW_FAILURE);
341  int g2_is_empty = (gserialized_get_gbox_p(g2, &box2) == LW_FAILURE);
342  int32_t srid1 = gserialized_get_srid(g1);
343  int32_t srid2 = gserialized_get_srid(g2);
344 
345  /* Empty < Non-empty */
346  if (g1_is_empty && !g2_is_empty)
347  return -1;
348 
349  /* Non-empty > Empty */
350  if (!g1_is_empty && g2_is_empty)
351  return 1;
352 
353  if (!g1_is_empty && !g2_is_empty)
354  {
355  /* Using the boxes, calculate sortable hash key. */
356  hash1 = gbox_get_sortable_hash(&box1, srid1);
357  hash2 = gbox_get_sortable_hash(&box2, srid2);
358 
359  if (hash1 > hash2)
360  return 1;
361  if (hash1 < hash2)
362  return -1;
363  }
364 
365  /* Prefix comes before longer one. */
366  if (bsz1 != bsz2 && cmp == 0)
367  {
368  if (bsz1 < bsz2)
369  return -1;
370  else if (bsz1 > bsz2)
371  return 1;
372  }
373 
374  /* If SRID is not equal, sort on it */
375  if (cmp_srid != 0)
376  return (srid1 > srid2) ? 1 : -1;
377 
378  /* ZM flag sort*/
379  if (g1hasz != g2hasz)
380  return (g1hasz > g2hasz) ? 1 : -1;
381 
382  if (g1hasm != g2hasm)
383  return (g1hasm > g2hasm) ? 1 : -1;
384 
385  assert(cmp != 0);
386  return cmp > 0 ? 1 : -1;
387  }
388 }
389 
390 uint64_t
392 {
393  GBOX box;
394  int is_empty = (gserialized_get_gbox_p(g, &box) == LW_FAILURE);
395 
396  if (is_empty)
397  return 0;
398  else
400 }
401 
402 void gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname);
403 void
404 gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname)
405 {
406  int32_t srid1 = gserialized_get_srid(g1);
407  int32_t srid2 = gserialized_get_srid(g2);
408  if (srid1 != srid2)
409  lwerror("%s: Operation on mixed SRID geometries (%s, %d) != (%s, %d)",
410  funcname,
412  srid1,
414  srid2);
415 }
416 
417 void gserialized_error_if_srid_mismatch_reference(const GSERIALIZED *g1, const int32_t srid2, const char *funcname);
418 void
419 gserialized_error_if_srid_mismatch_reference(const GSERIALIZED *g1, const int32_t srid2, const char *funcname)
420 {
421  int32_t srid1 = gserialized_get_srid(g1);
422  if (srid1 != srid2)
423  lwerror("%s: Operation on mixed SRID geometries %s %d != %d",
424  funcname,
426  srid1,
427  srid2);
428 }
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:893
int gserialized1_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: gserialized1.c:203
int gserialized1_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized1.c:94
int32_t gserialized1_hash(const GSERIALIZED *g1)
Returns a hash code for the srid/type/geometry information in the GSERIALIZED.
Definition: gserialized1.c:226
int gserialized1_ndims(const GSERIALIZED *gser)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: gserialized1.c:104
lwflags_t gserialized1_get_lwflags(const GSERIALIZED *g)
Read the flags from a GSERIALIZED and return a standard lwflag integer.
Definition: gserialized1.c:39
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:142
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:528
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:131
int gserialized1_has_bbox(const GSERIALIZED *gser)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: gserialized1.c:89
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:114
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:99
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:491
int gserialized1_is_geodetic(const GSERIALIZED *gser)
Check if a GSERIALIZED is a geography.
Definition: gserialized1.c:109
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:159
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:557
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:610
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:190
int gserialized2_is_geodetic(const GSERIALIZED *g)
Check if a GSERIALIZED is a geography.
Definition: gserialized2.c:171
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:207
int gserialized2_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized2.c:156
int32_t gserialized2_hash(const GSERIALIZED *g1)
Returns a hash code for the srid/type/geometry information in the GSERIALIZED.
Definition: gserialized2.c:268
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:294
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:184
int gserialized2_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: gserialized2.c:251
int gserialized2_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
Definition: gserialized2.c:548
int gserialized2_ndims(const GSERIALIZED *g)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: gserialized2.c:166
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:581
size_t gserialized2_from_lwgeom_size(const LWGEOM *geom)
Return the memory size a GSERIALIZED will occupy for a given LWGEOM.
Definition: gserialized2.c:774
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:161
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:176
lwflags_t gserialized2_get_lwflags(const GSERIALIZED *g)
Read the flags from a GSERIALIZED and return a standard lwflag integer.
Definition: gserialized2.c:57
int gserialized2_has_bbox(const GSERIALIZED *g)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: gserialized2.c:146
size_t gserialized_from_lwgeom_size(const LWGEOM *geom)
Return the memory size a GSERIALIZED will occupy for a given LWGEOM.
Definition: gserialized.c:230
void gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname)
Definition: gserialized.c:404
void gserialized_error_if_srid_mismatch_reference(const GSERIALIZED *g1, const int32_t srid2, const char *funcname)
Definition: gserialized.c:419
#define GFLAG_GEODETIC
Definition: gserialized.c:9
int gserialized_has_bbox(const GSERIALIZED *g)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: gserialized.c:163
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:126
static size_t gserialized_header_size(const GSERIALIZED *g)
Definition: gserialized.c:278
int gserialized_is_geodetic(const GSERIALIZED *g)
Check if a GSERIALIZED is a geography.
Definition: gserialized.c:196
int gserialized_ndims(const GSERIALIZED *g)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: gserialized.c:207
uint32_t gserialized_get_version(const GSERIALIZED *g)
Return the serialization version.
Definition: gserialized.c:42
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Read the box from the GSERIALIZED or calculate it if necessary.
Definition: gserialized.c:65
int gserialized_has_m(const GSERIALIZED *g)
Check if a GSERIALIZED has an M ordinate.
Definition: gserialized.c:185
int gserialized_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
Pull the first point values of a GSERIALIZED.
Definition: gserialized.c:257
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:239
static int gserialized_cmp_srid(const GSERIALIZED *g1, const GSERIALIZED *g2)
Definition: gserialized.c:303
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Definition: gserialized.c:152
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:248
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:138
#define GFLAGS_GET_VERSION(gflags)
Definition: gserialized.c:12
#define GFLAG_Z
Definition: gserialized.c:6
#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:277
#define GFLAG_BBOX
Definition: gserialized.c:8
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized.c:174
uint64_t gserialized_get_sortable_hash(const GSERIALIZED *g)
Return a sortable key based on gserialized.
Definition: gserialized.c:391
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:89
GSERIALIZED * gserialized_set_gbox(GSERIALIZED *g, GBOX *gbox)
Copy a new bounding box into an existing gserialized.
Definition: gserialized.c:31
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:101
GSERIALIZED * gserialized_drop_gbox(GSERIALIZED *g)
Remove the bounding box from a GSERIALIZED.
Definition: gserialized.c:52
#define GFLAG_M
Definition: gserialized.c:7
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
Definition: gserialized.c:222
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:77
lwflags_t gserialized_get_lwflags(const GSERIALIZED *g)
Read the flags from a GSERIALIZED and return a standard lwflag integer.
Definition: gserialized.c:18
int32_t gserialized_hash(const GSERIALIZED *g)
Returns a hash code for the srid/type/geometry information in the GSERIALIZED.
Definition: gserialized.c:114
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:313
#define LW_FAILURE
Definition: liblwgeom.h:110
uint16_t lwflags_t
Definition: liblwgeom.h:313
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
#define SIZE_GET(varsize)
Macro for reading the size from the GSERIALIZED size attribute.
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
uint8_t srid[3]
Definition: liblwgeom.h:431
uint32_t size
Definition: liblwgeom.h:430
uint8_t gflags
Definition: liblwgeom.h:432