PostGIS  3.4.0dev-r@@SVN_REVISION@@
lwgeom_union.c
Go to the documentation of this file.
1 #include <assert.h>
2 #include <stdbool.h>
3 #include <string.h>
4 
5 #include "postgres.h"
6 #include "fmgr.h"
7 #include "utils/varlena.h"
8 
9 #include "../postgis_config.h"
10 
11 #include "liblwgeom.h"
12 #include "lwgeom_log.h"
13 #include "lwgeom_pg.h"
14 #include "lwgeom_union.h"
15 
16 #define GetAggContext(aggcontext) \
17  if (!AggCheckCallContext(fcinfo, aggcontext)) \
18  elog(ERROR, "%s called in non-aggregate context", __func__)
19 
20 #define CheckAggContext() GetAggContext(NULL)
21 
22 
23 Datum pgis_geometry_union_parallel_transfn(PG_FUNCTION_ARGS);
24 Datum pgis_geometry_union_parallel_combinefn(PG_FUNCTION_ARGS);
25 Datum pgis_geometry_union_parallel_serialfn(PG_FUNCTION_ARGS);
26 Datum pgis_geometry_union_parallel_deserialfn(PG_FUNCTION_ARGS);
27 Datum pgis_geometry_union_parallel_finalfn(PG_FUNCTION_ARGS);
28 
29 static UnionState* state_create(void);
30 static void state_append(UnionState *state, const GSERIALIZED *gser);
31 static bytea* state_serialize(const UnionState *state);
32 static UnionState* state_deserialize(const bytea* serialized);
33 static void state_combine(UnionState *state1, UnionState *state2);
34 
35 static LWGEOM* gserialized_list_union(List* list, float8 gridSize);
36 
37 
39 Datum pgis_geometry_union_parallel_transfn(PG_FUNCTION_ARGS)
40 {
41  MemoryContext aggcontext, old;
42  UnionState *state;
43  Datum argType;
44  GSERIALIZED *gser = NULL;
45 
46  /* Check argument type */
47  argType = get_fn_expr_argtype(fcinfo->flinfo, 1);
48  if (argType == InvalidOid)
49  ereport(ERROR, (
50  errcode(ERRCODE_INVALID_PARAMETER_VALUE),
51  errmsg("%s: could not determine input data type", __func__)));
52 
53  /* Get memory context */
54  GetAggContext(&aggcontext);
55 
56  /* Get state */
57  if (PG_ARGISNULL(0)) {
58  old = MemoryContextSwitchTo(aggcontext);
59  state = state_create();
60  MemoryContextSwitchTo(old);
61  }
62  else
63  {
64  state = (UnionState*) PG_GETARG_POINTER(0);
65  }
66 
67  /* Get value */
68  if (!PG_ARGISNULL(1))
69  gser = PG_GETARG_GSERIALIZED_P(1);
70 
71  /* Get grid size */
72  if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
73  {
74  double gridSize = PG_GETARG_FLOAT8(2);
75  if (gridSize > 0)
76  state->gridSize = gridSize;
77  }
78 
79  /* Copy serialized geometry into state */
80  if (gser) {
81  old = MemoryContextSwitchTo(aggcontext);
82  state_append(state, gser);
83  MemoryContextSwitchTo(old);
84  }
85 
86  PG_RETURN_POINTER(state);
87 }
88 
89 
92 {
93  MemoryContext aggcontext, old;
94  UnionState *state1 = NULL;
95  UnionState *state2 = NULL;
96 
97  if (!PG_ARGISNULL(0))
98  state1 = (UnionState*) PG_GETARG_POINTER(0);
99  if (!PG_ARGISNULL(1))
100  state2 = (UnionState*) PG_GETARG_POINTER(1);
101 
102  GetAggContext(&aggcontext);
103 
104  if (state1 && state2)
105  {
106  old = MemoryContextSwitchTo(aggcontext);
107  state_combine(state1, state2);
108  lwfree(state2);
109  MemoryContextSwitchTo(old);
110  }
111  else if (state2)
112  {
113  state1 = state2;
114  }
115 
116  if (!state1)
117  PG_RETURN_NULL();
118  PG_RETURN_POINTER(state1);
119 }
120 
121 
124 {
125  UnionState *state;
126 
127  CheckAggContext();
128 
129  state = (UnionState*) PG_GETARG_POINTER(0);
130  PG_RETURN_BYTEA_P(state_serialize(state));
131 }
132 
133 
136 {
137  MemoryContext aggcontext, old;
138  UnionState *state;
139  bytea *serialized;
140 
141  GetAggContext(&aggcontext);
142 
143  serialized = PG_GETARG_BYTEA_P(0);
144 
145  old = MemoryContextSwitchTo(aggcontext);
146  state = state_deserialize(serialized);
147  MemoryContextSwitchTo(old);
148 
149  PG_RETURN_POINTER(state);
150 }
151 
152 
155 {
156  UnionState *state;
157  LWGEOM *geom = NULL;
158 
159  CheckAggContext();
160 
161  state = (UnionState*)PG_GETARG_POINTER(0);
162  geom = gserialized_list_union(state->list, state->gridSize);
163  if (!geom)
164  PG_RETURN_NULL();
165  PG_RETURN_POINTER(geometry_serialize(geom));
166 }
167 
168 
170 {
171  UnionState *state = lwalloc(sizeof(UnionState));
172  state->gridSize = -1.0;
173  state->list = NIL;
174  state->size = 0;
175  return state;
176 }
177 
178 
179 void state_append(UnionState *state, const GSERIALIZED *gser)
180 {
181  GSERIALIZED *gser_copy;
182 
183  assert(gser);
184  gser_copy = lwalloc(VARSIZE(gser));
185  memcpy(gser_copy, gser, VARSIZE(gser));
186 
187  state->list = lappend(state->list, gser_copy);
188  state->size += VARSIZE(gser);
189 }
190 
191 
192 bytea* state_serialize(const UnionState *state)
193 {
194  int32 size = VARHDRSZ + sizeof(state->gridSize) + state->size;
195  bytea *serialized = lwalloc(size);
196  uint8 *data;
197  ListCell *cell;
198 
199  SET_VARSIZE(serialized, size);
200  data = (uint8*)VARDATA(serialized);
201 
202  /* grid size */
203  memcpy(data, &state->gridSize, sizeof(state->gridSize));
204  data += sizeof(state->gridSize);
205 
206  /* items */
207  foreach (cell, state->list)
208  {
209  const GSERIALIZED *gser = (const GSERIALIZED*)lfirst(cell);
210  assert(gser);
211  memcpy(data, gser, VARSIZE(gser));
212  data += VARSIZE(gser);
213  }
214 
215  return serialized;
216 }
217 
218 
219 UnionState* state_deserialize(const bytea* serialized)
220 {
221  UnionState *state = state_create();
222  const uint8 *data = (const uint8*)VARDATA(serialized);
223  const uint8 *data_end = (const uint8*)serialized + VARSIZE(serialized);
224 
225  /* grid size */
226  memcpy(&state->gridSize, data, sizeof(state->gridSize));
227  data += sizeof(state->gridSize);
228 
229  /* items */
230  while (data < data_end)
231  {
232  const GSERIALIZED* gser = (const GSERIALIZED*)data;
233  state_append(state, gser);
234  data += VARSIZE(gser);
235  }
236 
237  return state;
238 }
239 
240 
241 void state_combine(UnionState *state1, UnionState *state2)
242 {
243  List *list1;
244  List *list2;
245 
246  assert(state1 && state2);
247 
248  list1 = state1->list;
249  list2 = state2->list;
250 
251  if (list1 != NIL && list2 != NIL)
252  {
253  state1->list = list_concat(list1, list2);
255  //list_free(list2);
256  state1->size += state2->size;
257  }
258  else if (list2 != NIL)
259  {
260  state1->gridSize = state2->gridSize;
261  state1->list = list2;
262  state1->size = state2->size;
263  }
264  state2->list = NIL;
265 }
266 
267 
268 LWGEOM* gserialized_list_union(List* list, float8 gridSize)
269 {
270  int ngeoms = 0;
271  LWGEOM **geoms;
272  int32_t srid = SRID_UNKNOWN;
273  bool first = true;
274  int empty_type = 0;
275  int has_z = LW_FALSE;
276  ListCell *cell;
277 
278  if (list_length(list) == 0)
279  return NULL;
280 
281  geoms = lwalloc(list_length(list) * sizeof(LWGEOM*));
282  foreach (cell, list)
283  {
284  GSERIALIZED *gser;
285  LWGEOM *geom;
286 
287  gser = (GSERIALIZED*)lfirst(cell);
288  assert(gser);
289  geom = lwgeom_from_gserialized(gser);
290 
291  if (!lwgeom_is_empty(geom))
292  {
293  geoms[ngeoms++] = geom; /* no cloning */
294  if (first)
295  {
296  srid = lwgeom_get_srid(geom);
297  has_z = lwgeom_has_z(geom);
298  first = false;
299  }
300  }
301  else
302  {
303  int type = lwgeom_get_type(geom);
304  if (type > empty_type)
305  empty_type = type;
306  if (srid == SRID_UNKNOWN)
307  srid = lwgeom_get_srid(geom);
308  }
309  }
310 
311  if (ngeoms > 0)
312  {
313  /*
314  * Create a collection and pass it into cascaded union
315  */
316  LWCOLLECTION *col = lwcollection_construct(COLLECTIONTYPE, srid, NULL, ngeoms, geoms);
318  if (!result)
319  lwcollection_free(col);
320  return result;
321  }
322 
323  /*
324  * Only empty geometries in the list,
325  * create geometry with largest type number or return NULL
326  */
327  return (empty_type > 0)
328  ? lwgeom_construct_empty(empty_type, srid, has_z, 0)
329  : NULL;
330 }
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:262
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:239
#define LW_FALSE
Definition: liblwgeom.h:94
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:309
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition: lwgeom.c:927
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:934
void lwfree(void *mem)
Definition: lwutil.c:242
LWGEOM * lwgeom_unaryunion_prec(const LWGEOM *geom1, double gridSize)
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:357
void * lwalloc(size_t size)
Definition: lwutil.c:227
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:42
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
LWGEOM * lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwgeom.c:2105
This library is the generic geometry handling section of PostGIS.
static UnionState * state_create(void)
Definition: lwgeom_union.c:169
Datum pgis_geometry_union_parallel_deserialfn(PG_FUNCTION_ARGS)
Definition: lwgeom_union.c:135
PG_FUNCTION_INFO_V1(pgis_geometry_union_parallel_transfn)
#define GetAggContext(aggcontext)
Definition: lwgeom_union.c:16
static void state_combine(UnionState *state1, UnionState *state2)
Definition: lwgeom_union.c:241
Datum pgis_geometry_union_parallel_serialfn(PG_FUNCTION_ARGS)
Definition: lwgeom_union.c:123
static LWGEOM * gserialized_list_union(List *list, float8 gridSize)
Definition: lwgeom_union.c:268
Datum pgis_geometry_union_parallel_transfn(PG_FUNCTION_ARGS)
Definition: lwgeom_union.c:39
static void state_append(UnionState *state, const GSERIALIZED *gser)
Definition: lwgeom_union.c:179
#define CheckAggContext()
Definition: lwgeom_union.c:20
static bytea * state_serialize(const UnionState *state)
Definition: lwgeom_union.c:192
static UnionState * state_deserialize(const bytea *serialized)
Definition: lwgeom_union.c:219
Datum pgis_geometry_union_parallel_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_union.c:154
Datum pgis_geometry_union_parallel_combinefn(PG_FUNCTION_ARGS)
Definition: lwgeom_union.c:91
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
Definition: lwinline.h:145
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwinline.h:203
type
Definition: ovdump.py:42
data
Definition: ovdump.py:104
unsigned int int32
Definition: shpopen.c:54
List * list
Definition: lwgeom_union.h:10
int32 size
Definition: lwgeom_union.h:11
float8 gridSize
Definition: lwgeom_union.h:9