PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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
23Datum pgis_geometry_union_parallel_transfn(PG_FUNCTION_ARGS);
24Datum pgis_geometry_union_parallel_combinefn(PG_FUNCTION_ARGS);
25Datum pgis_geometry_union_parallel_serialfn(PG_FUNCTION_ARGS);
26Datum pgis_geometry_union_parallel_deserialfn(PG_FUNCTION_ARGS);
27Datum pgis_geometry_union_parallel_finalfn(PG_FUNCTION_ARGS);
28
29static UnionState* state_create(void);
30static void state_append(UnionState *state, const GSERIALIZED *gser);
31static bytea* state_serialize(const UnionState *state);
32static UnionState* state_deserialize(const bytea* serialized);
33static void state_combine(UnionState *state1, UnionState *state2);
34
35static LWGEOM* gserialized_list_union(List* list, float8 gridSize);
36
37
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
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
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
179void 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
192bytea* 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
219UnionState* 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
241void 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
268LWGEOM* 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)
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:267
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
#define LW_FALSE
Definition liblwgeom.h:94
#define COLLECTIONTYPE
Definition liblwgeom.h:108
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition lwgeom.c:955
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition lwgeom.c:962
void * lwalloc(size_t size)
Definition lwutil.c:227
void lwfree(void *mem)
Definition lwutil.c:248
void lwcollection_free(LWCOLLECTION *col)
LWGEOM * lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition lwgeom.c:2219
LWGEOM * lwgeom_unaryunion_prec(const LWGEOM *geom1, double gridSize)
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:215
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition lwgeom.c:337
This library is the generic geometry handling section of PostGIS.
static UnionState * state_create(void)
Datum pgis_geometry_union_parallel_deserialfn(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pgis_geometry_union_parallel_transfn)
#define GetAggContext(aggcontext)
static void state_combine(UnionState *state1, UnionState *state2)
Datum pgis_geometry_union_parallel_serialfn(PG_FUNCTION_ARGS)
static LWGEOM * gserialized_list_union(List *list, float8 gridSize)
Datum pgis_geometry_union_parallel_transfn(PG_FUNCTION_ARGS)
static void state_append(UnionState *state, const GSERIALIZED *gser)
#define CheckAggContext()
static bytea * state_serialize(const UnionState *state)
static UnionState * state_deserialize(const bytea *serialized)
Datum pgis_geometry_union_parallel_finalfn(PG_FUNCTION_ARGS)
Datum pgis_geometry_union_parallel_combinefn(PG_FUNCTION_ARGS)
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
Definition lwinline.h:141
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:199
unsigned int int32
Definition shpopen.c:54
List * list
float8 gridSize
Definition lwgeom_union.h:9