PostGIS  2.5.7dev-r@@SVN_REVISION@@
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 
41 /* Local prototypes */
42 Datum PGISDirectFunctionCall1(PGFunction func, Datum arg1);
43 Datum PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2);
44 Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS);
45 Datum pgis_geometry_accum_finalfn(PG_FUNCTION_ARGS);
46 Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS);
47 Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS);
48 Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS);
49 Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS);
50 Datum pgis_geometry_clusterintersecting_finalfn(PG_FUNCTION_ARGS);
51 Datum pgis_geometry_clusterwithin_finalfn(PG_FUNCTION_ARGS);
52 
55 Datum pgis_abs_in(PG_FUNCTION_ARGS);
56 Datum pgis_abs_out(PG_FUNCTION_ARGS);
57 
63 Datum
64 pgis_abs_in(PG_FUNCTION_ARGS)
65 {
66  ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
67  errmsg("function %s not implemented", __func__)));
68  PG_RETURN_POINTER(NULL);
69 }
71 Datum
72 pgis_abs_out(PG_FUNCTION_ARGS)
73 {
74  ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
75  errmsg("function %s not implemented", __func__)));
76  PG_RETURN_POINTER(NULL);
77 }
78 
79 /* External prototypes */
80 Datum pgis_union_geometry_array(PG_FUNCTION_ARGS);
81 Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS);
82 Datum polygonize_garray(PG_FUNCTION_ARGS);
83 Datum clusterintersecting_garray(PG_FUNCTION_ARGS);
84 Datum cluster_within_distance_garray(PG_FUNCTION_ARGS);
85 Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS);
86 
87 
107 typedef struct
108 {
109  ArrayBuildState *a;
110  Datum data;
111 }
112 pgis_abs;
113 
114 
121 Datum
123 {
124  Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
125  MemoryContext aggcontext;
126  ArrayBuildState *state;
127  pgis_abs *p;
128  Datum elem;
129 
130  if (arg1_typeid == InvalidOid)
131  ereport(ERROR,
132  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
133  errmsg("could not determine input data type")));
134 
135  if ( ! AggCheckCallContext(fcinfo, &aggcontext) )
136  {
137  /* cannot be called directly because of dummy-type argument */
138  elog(ERROR, "%s called in non-aggregate context", __func__);
139  aggcontext = NULL; /* keep compiler quiet */
140  }
141 
142  if ( PG_ARGISNULL(0) )
143  {
144  MemoryContext old = MemoryContextSwitchTo(aggcontext);
145  p = (pgis_abs*) palloc(sizeof(pgis_abs));
146  p->a = NULL;
147  p->data = (Datum) NULL;
148 
149  if (PG_NARGS() == 3)
150  {
151  Datum argument = PG_GETARG_DATUM(2);
152  Oid dataOid = get_fn_expr_argtype(fcinfo->flinfo, 2);
153 
154  p->data = datumCopy(argument, get_typbyval(dataOid), get_typlen(dataOid));
155 
156  }
157  MemoryContextSwitchTo(old);
158  }
159  else
160  {
161  p = (pgis_abs*) PG_GETARG_POINTER(0);
162  }
163  state = p->a;
164  elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
165  state = accumArrayResult(state,
166  elem,
167  PG_ARGISNULL(1),
168  arg1_typeid,
169  aggcontext);
170  p->a = state;
171 
172  PG_RETURN_POINTER(p);
173 }
174 
175 
176 
177 Datum pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo);
178 
183 Datum
184 pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, __attribute__((__unused__)) FunctionCallInfo fcinfo)
185 {
186  int dims[1];
187  int lbs[1];
188  ArrayBuildState *state;
189  Datum result;
190 
191  /* cannot be called directly because of internal-type argument */
192  Assert(fcinfo->context &&
193  (IsA(fcinfo->context, AggState) ||
194  IsA(fcinfo->context, WindowAggState))
195  );
196 
197  state = p->a;
198  dims[0] = state->nelems;
199  lbs[0] = 1;
200  result = makeMdArrayResult(state, 1, dims, lbs, mctx, false);
201  return result;
202 }
203 
208 Datum
210 {
211  pgis_abs *p;
212  Datum result = 0;
213 
214  if (PG_ARGISNULL(0))
215  PG_RETURN_NULL(); /* returns null iff no input values */
216 
217  p = (pgis_abs*) PG_GETARG_POINTER(0);
218 
219  result = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
220 
221  PG_RETURN_DATUM(result);
222 
223 }
224 
230 Datum
232 {
233  pgis_abs *p;
234  Datum result = 0;
235  Datum geometry_array = 0;
236 
237  if (PG_ARGISNULL(0))
238  PG_RETURN_NULL(); /* returns null iff no input values */
239 
240  p = (pgis_abs*) PG_GETARG_POINTER(0);
241 
242  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
243  result = PGISDirectFunctionCall1( pgis_union_geometry_array, geometry_array );
244  if (!result)
245  PG_RETURN_NULL();
246 
247  PG_RETURN_DATUM(result);
248 }
249 
255 Datum
257 {
258  pgis_abs *p;
259  Datum result = 0;
260  Datum geometry_array = 0;
261 
262  if (PG_ARGISNULL(0))
263  PG_RETURN_NULL(); /* returns null iff no input values */
264 
265  p = (pgis_abs*) PG_GETARG_POINTER(0);
266 
267  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
268  result = PGISDirectFunctionCall1( LWGEOM_collect_garray, geometry_array );
269  if (!result)
270  PG_RETURN_NULL();
271 
272  PG_RETURN_DATUM(result);
273 }
274 
275 
281 Datum
283 {
284  pgis_abs *p;
285  Datum result = 0;
286  Datum geometry_array = 0;
287 
288  if (PG_ARGISNULL(0))
289  PG_RETURN_NULL(); /* returns null iff no input values */
290 
291  p = (pgis_abs*) PG_GETARG_POINTER(0);
292 
293  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
294  result = PGISDirectFunctionCall1( polygonize_garray, geometry_array );
295  if (!result)
296  PG_RETURN_NULL();
297 
298  PG_RETURN_DATUM(result);
299 }
300 
306 Datum
308 {
309  pgis_abs *p;
310  Datum result = 0;
311  Datum geometry_array = 0;
312 
313  if (PG_ARGISNULL(0))
314  PG_RETURN_NULL(); /* returns null iff no input values */
315 
316  p = (pgis_abs*) PG_GETARG_POINTER(0);
317 
318  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
319  result = PGISDirectFunctionCall1( LWGEOM_makeline_garray, geometry_array );
320  if (!result)
321  PG_RETURN_NULL();
322 
323  PG_RETURN_DATUM(result);
324 }
325 
331 Datum
333 {
334  pgis_abs *p;
335  Datum result = 0;
336  Datum geometry_array = 0;
337 
338  if (PG_ARGISNULL(0))
339  PG_RETURN_NULL();
340 
341  p = (pgis_abs*) PG_GETARG_POINTER(0);
342  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
343  result = PGISDirectFunctionCall1( clusterintersecting_garray, geometry_array );
344  if (!result)
345  PG_RETURN_NULL();
346 
347  PG_RETURN_DATUM(result);
348 }
349 
355 Datum
357 {
358  pgis_abs *p;
359  Datum result = 0;
360  Datum geometry_array = 0;
361 
362  if (PG_ARGISNULL(0))
363  PG_RETURN_NULL();
364 
365  p = (pgis_abs*) PG_GETARG_POINTER(0);
366 
367  if (!p->data)
368  {
369  elog(ERROR, "Tolerance not defined");
370  PG_RETURN_NULL();
371  }
372 
373  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
374  result = PGISDirectFunctionCall2( cluster_within_distance_garray, geometry_array, p->data);
375  if (!result)
376  PG_RETURN_NULL();
377 
378  PG_RETURN_DATUM(result);
379 }
380 
385 Datum
386 PGISDirectFunctionCall1(PGFunction func, Datum arg1)
387 {
388 #if POSTGIS_PGSQL_VERSION < 120
389  FunctionCallInfoData fcinfo;
390  Datum result;
391 
392 
393  InitFunctionCallInfoData(fcinfo, NULL, 1, InvalidOid, NULL, NULL);
394 
395 
396  fcinfo.arg[0] = arg1;
397  fcinfo.argnull[0] = false;
398 
399  result = (*func) (&fcinfo);
400 
401  /* Check for null result, returning a "NULL" Datum if indicated */
402  if (fcinfo.isnull)
403  return (Datum) 0;
404 
405  return result;
406 #else
407  LOCAL_FCINFO(fcinfo, 1);
408  Datum result;
409 
410  InitFunctionCallInfoData(*fcinfo, NULL, 1, InvalidOid, NULL, NULL);
411 
412  fcinfo->args[0].value = arg1;
413  fcinfo->args[0].isnull = false;
414 
415  result = (*func)(fcinfo);
416 
417  /* Check for null result, returning a "NULL" Datum if indicated */
418  if (fcinfo->isnull)
419  return (Datum)0;
420 
421  return result;
422 #endif /* POSTGIS_PGSQL_VERSION < 120 */
423 }
424 
429 Datum
430 PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
431 {
432 #if POSTGIS_PGSQL_VERSION < 120
433  FunctionCallInfoData fcinfo;
434  Datum result;
435 
436  InitFunctionCallInfoData(fcinfo, NULL, 2, InvalidOid, NULL, NULL);
437 
438  fcinfo.arg[0] = arg1;
439  fcinfo.arg[1] = arg2;
440  fcinfo.argnull[0] = false;
441  fcinfo.argnull[1] = false;
442 
443  result = (*func) (&fcinfo);
444 
445  /* Check for null result, returning a "NULL" Datum if indicated */
446  if (fcinfo.isnull)
447  return (Datum) 0;
448 
449  return result;
450 #else
451  LOCAL_FCINFO(fcinfo, 2);
452  Datum result;
453 
454  InitFunctionCallInfoData(*fcinfo, NULL, 2, InvalidOid, NULL, NULL);
455 
456  fcinfo->args[0].value = arg1;
457  fcinfo->args[1].value = arg2;
458  fcinfo->args[0].isnull = false;
459  fcinfo->args[1].isnull = false;
460 
461  result = (*func)(fcinfo);
462 
463  /* Check for null result, returning a "NULL" Datum if indicated */
464  if (fcinfo->isnull)
465  return (Datum)0;
466 
467  return result;
468 #endif /* POSTGIS_PGSQL_VERSION < 120 */
469 }
#define __attribute__(x)
Definition: liblwgeom.h:201
This library is the generic geometry handling section of PostGIS.
Datum polygonize_garray(PG_FUNCTION_ARGS)
Datum pgis_abs_in(PG_FUNCTION_ARGS)
Putting pgis_abs back for ABI compatibility with 2.4 and below TODO: Drop when 3.0 rolls around.
Definition: lwgeom_accum.c:64
Datum pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo)
Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:307
Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:282
Datum cluster_within_distance_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_accum_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:209
Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:256
Datum pgis_abs_out(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:72
Datum PGISDirectFunctionCall1(PGFunction func, Datum arg1)
A modified version of PostgreSQL's DirectFunctionCall1 which allows NULL results; this is required fo...
Definition: lwgeom_accum.c:386
Datum pgis_geometry_clusterintersecting_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:332
Datum PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
A modified version of PostgreSQL's DirectFunctionCall2 which allows NULL results; this is required fo...
Definition: lwgeom_accum.c:430
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_clusterwithin_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:356
Datum clusterintersecting_garray(PG_FUNCTION_ARGS)
Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:231
Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:122
Datum pgis_union_geometry_array(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pgis_abs_in)
Putting back pgis_* for ABI compatibility to smooth pg_upgrade TODO: Drop when 3.0 rolls around.
Datum data
Definition: lwgeom_accum.c:110
ArrayBuildState * a
Definition: lwgeom_accum.c:109
To pass the internal ArrayBuildState pointer between the transfn and finalfn we need to wrap it into ...
Definition: lwgeom_accum.c:108