PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwgeom_accum.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 2009 Paul Ramsey <pramsey@opengeo.org>
22 *
23 **********************************************************************/
24
25
26#include "postgres.h"
27#include "fmgr.h"
28#include "funcapi.h"
29#include "access/tupmacs.h"
30#include "utils/datum.h"
31#include "utils/array.h"
32#include "utils/lsyscache.h"
33
34#include "../postgis_config.h"
35
36#include "liblwgeom.h"
37#include "lwgeom_geos.h"
38#include "lwgeom_pg.h"
39#include "lwgeom_transform.h"
40#include "lwgeom_accum.h"
41
42/* Local prototypes */
43Datum PGISDirectFunctionCall1(PGFunction func, Datum arg1);
44Datum PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2);
45Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS);
46Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS);
47Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS);
48Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS);
49Datum pgis_geometry_clusterintersecting_finalfn(PG_FUNCTION_ARGS);
50Datum pgis_geometry_clusterwithin_finalfn(PG_FUNCTION_ARGS);
51
52/* External prototypes */
53Datum pgis_union_geometry_array(PG_FUNCTION_ARGS);
54Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS);
55Datum polygonize_garray(PG_FUNCTION_ARGS);
56Datum clusterintersecting_garray(PG_FUNCTION_ARGS);
57Datum cluster_within_distance_garray(PG_FUNCTION_ARGS);
58Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS);
59Datum ST_CoverageUnion(PG_FUNCTION_ARGS);
60
61
68Datum
70{
71 MemoryContext aggcontext, old;
73 LWGEOM *geom = NULL;
74 GSERIALIZED *gser = NULL;
75 Datum argType = get_fn_expr_argtype(fcinfo->flinfo, 1);
76 double gridSize = -1.0;
77
78 if (argType == InvalidOid)
79 ereport(ERROR,
80 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
81 errmsg("could not determine input data type")));
82
83 if ( ! AggCheckCallContext(fcinfo, &aggcontext) )
84 {
85 /* cannot be called directly because of dummy-type argument */
86 elog(ERROR, "%s called in non-aggregate context", __func__);
87 aggcontext = NULL; /* keep compiler quiet */
88 }
89
90 if ( PG_ARGISNULL(0) )
91 {
92 int n = ((PG_NARGS()-2) <= CollectionBuildStateDataSize) ? (PG_NARGS()-2) : CollectionBuildStateDataSize;
93
94 state = MemoryContextAlloc(aggcontext, sizeof(CollectionBuildState));
95 state->geoms = NULL;
96 state->geomOid = argType;
97 state->gridSize = gridSize;
98
99 for (int i = 0; i < n; i++)
100 {
101 Datum argument = PG_GETARG_DATUM(i+2);
102 Oid dataOid = get_fn_expr_argtype(fcinfo->flinfo, i+2);
103 old = MemoryContextSwitchTo(aggcontext);
104 state->data[i] = datumCopy(argument, get_typbyval(dataOid), get_typlen(dataOid));
105 MemoryContextSwitchTo(old);
106 }
107 }
108 else
109 {
110 state = (CollectionBuildState*) PG_GETARG_POINTER(0);
111 }
112
113 if (!PG_ARGISNULL(1))
114 gser = PG_GETARG_GSERIALIZED_P(1);
115
116 if (PG_NARGS()>2 && !PG_ARGISNULL(2))
117 {
118 gridSize = PG_GETARG_FLOAT8(2);
119 /*lwnotice("Passed gridSize %g", gridSize);*/
120 if ( gridSize > state->gridSize ) state->gridSize = gridSize;
121 }
122
123 /* Take a copy of the geometry into the aggregate context */
124 old = MemoryContextSwitchTo(aggcontext);
125 if (gser)
127
128 /* Initialize or append to list as necessary */
129 if (state->geoms)
130 state->geoms = lappend(state->geoms, geom);
131 else
132 state->geoms = list_make1(geom);
133
134 MemoryContextSwitchTo(old);
135
136 PG_RETURN_POINTER(state);
137}
138
139
140Datum pgis_accum_finalfn(CollectionBuildState *state, MemoryContext mctx, FunctionCallInfo fcinfo);
141
146Datum
147pgis_accum_finalfn(CollectionBuildState *state, MemoryContext mctx, __attribute__((__unused__)) FunctionCallInfo fcinfo)
148{
149 ListCell *l;
150 size_t nelems = 0;
151 Datum *elems;
152 bool *nulls;
153 int16 elmlen;
154 bool elmbyval;
155 char elmalign;
156 size_t i = 0;
157 ArrayType *arr;
158 int dims[1];
159 int lbs[1] = {1};
160
161 /* cannot be called directly because of internal-type argument */
162 Assert(fcinfo->context &&
163 (IsA(fcinfo->context, AggState) ||
164 IsA(fcinfo->context, WindowAggState))
165 );
166
167 /* Retrieve geometry type metadata */
168 get_typlenbyvalalign(state->geomOid, &elmlen, &elmbyval, &elmalign);
169 nelems = list_length(state->geoms);
170
171 /* Build up an array, because that's what we pass to all the */
172 /* specific final functions */
173 elems = palloc(nelems * sizeof(Datum));
174 nulls = palloc(nelems * sizeof(bool));
175
176 foreach (l, state->geoms)
177 {
178 LWGEOM *geom = (LWGEOM*)(lfirst(l));
179 Datum elem = (Datum)0;
180 bool isNull = true;
181 if (geom)
182 {
183 GSERIALIZED *gser = geometry_serialize(geom);
184 elem = PointerGetDatum(gser);
185 isNull = false;
186 }
187 elems[i] = elem;
188 nulls[i] = isNull;
189 i++;
190
191 if (i >= nelems)
192 break;
193 }
194
195 /* Turn element array into PgSQL array */
196 dims[0] = nelems;
197 arr = construct_md_array(elems, nulls, 1, dims, lbs, state->geomOid,
198 elmlen, elmbyval, elmalign);
199
200 return PointerGetDatum(arr);
201}
202
208Datum
210{
212 Datum result = 0;
213 Datum geometry_array = 0;
214
215 if (PG_ARGISNULL(0))
216 PG_RETURN_NULL(); /* returns null iff no input values */
217
218 p = (CollectionBuildState*) PG_GETARG_POINTER(0);
219
220 geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
222 if (!result)
223 PG_RETURN_NULL();
224
225 PG_RETURN_DATUM(result);
226}
227
228
234Datum
236{
238 Datum result = 0;
239 Datum geometry_array = 0;
240
241 if (PG_ARGISNULL(0))
242 PG_RETURN_NULL(); /* returns null iff no input values */
243
244 p = (CollectionBuildState*) PG_GETARG_POINTER(0);
245
246 geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
248 if (!result)
249 PG_RETURN_NULL();
250
251 PG_RETURN_DATUM(result);
252}
253
259Datum
261{
263 Datum result = 0;
264 Datum geometry_array = 0;
265
266 if (PG_ARGISNULL(0))
267 PG_RETURN_NULL(); /* returns null iff no input values */
268
269 p = (CollectionBuildState*) PG_GETARG_POINTER(0);
270
271 geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
273 if (!result)
274 PG_RETURN_NULL();
275
276 PG_RETURN_DATUM(result);
277}
278
284Datum
286{
288 Datum result = 0;
289 Datum geometry_array = 0;
290
291 if (PG_ARGISNULL(0))
292 PG_RETURN_NULL();
293
294 p = (CollectionBuildState*) PG_GETARG_POINTER(0);
295 geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
297 if (!result)
298 PG_RETURN_NULL();
299
300 PG_RETURN_DATUM(result);
301}
302
308Datum
310{
312 Datum result = 0;
313 Datum geometry_array = 0;
314
315 if (PG_ARGISNULL(0))
316 PG_RETURN_NULL();
317
318 p = (CollectionBuildState*) PG_GETARG_POINTER(0);
319
320 if (!p->data[0])
321 {
322 elog(ERROR, "Tolerance not defined");
323 PG_RETURN_NULL();
324 }
325
326 geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
328 if (!result)
329 PG_RETURN_NULL();
330
331 PG_RETURN_DATUM(result);
332}
333
334
335
341Datum
343{
345 Datum result = 0;
346 Datum geometry_array = 0;
347
348 if (PG_ARGISNULL(0))
349 PG_RETURN_NULL(); /* returns null iff no input values */
350
351 p = (CollectionBuildState*) PG_GETARG_POINTER(0);
352
353 geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
355 if (!result)
356 PG_RETURN_NULL();
357
358 PG_RETURN_DATUM(result);
359}
360
361
366Datum
367PGISDirectFunctionCall1(PGFunction func, Datum arg1)
368{
369 LOCAL_FCINFO(fcinfo, 1);
370 Datum result;
371
372 InitFunctionCallInfoData(*fcinfo, NULL, 1, InvalidOid, NULL, NULL);
373
374 fcinfo->args[0].value = arg1;
375 fcinfo->args[0].isnull = false;
376
377 result = (*func)(fcinfo);
378
379 /* Check for null result, returning a "NULL" Datum if indicated */
380 if (fcinfo->isnull)
381 return (Datum)0;
382
383 return result;
384}
385
390Datum
391PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
392{
393 LOCAL_FCINFO(fcinfo, 2);
394 Datum result;
395
396 InitFunctionCallInfoData(*fcinfo, NULL, 2, InvalidOid, NULL, NULL);
397
398 fcinfo->args[0].value = arg1;
399 fcinfo->args[1].value = arg2;
400 fcinfo->args[0].isnull = false;
401 fcinfo->args[1].isnull = false;
402
403 result = (*func)(fcinfo);
404
405 /* Check for null result, returning a "NULL" Datum if indicated */
406 if (fcinfo->isnull)
407 return (Datum)0;
408
409 return result;
410}
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.
#define __attribute__(x)
Definition liblwgeom.h:228
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
Definition lwgeom.c:557
This library is the generic geometry handling section of PostGIS.
Datum polygonize_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS)
Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS)
Datum cluster_within_distance_garray(PG_FUNCTION_ARGS)
Datum pgis_accum_finalfn(CollectionBuildState *state, MemoryContext mctx, FunctionCallInfo fcinfo)
Datum ST_CoverageUnion(PG_FUNCTION_ARGS)
Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pgis_geometry_accum_transfn)
The transfer function builds a List of LWGEOM* allocated in the aggregate memory context.
Datum PGISDirectFunctionCall1(PGFunction func, Datum arg1)
A modified version of PostgreSQL's DirectFunctionCall1 which allows NULL results; this is required fo...
Datum pgis_geometry_clusterintersecting_finalfn(PG_FUNCTION_ARGS)
Datum PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
A modified version of PostgreSQL's DirectFunctionCall2 which allows NULL results; this is required fo...
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_clusterwithin_finalfn(PG_FUNCTION_ARGS)
Datum pgis_geometry_coverageunion_finalfn(PG_FUNCTION_ARGS)
Datum clusterintersecting_garray(PG_FUNCTION_ARGS)
Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS)
Datum pgis_union_geometry_array(PG_FUNCTION_ARGS)
#define CollectionBuildStateDataSize
To pass the internal state of our collection between the transfn and finalfn we need to wrap it into ...
Datum data[CollectionBuildStateDataSize]