PostGIS  2.4.9dev-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 Datum pgis_abs_in(PG_FUNCTION_ARGS);
53 Datum pgis_abs_out(PG_FUNCTION_ARGS);
54 
55 /* External prototypes */
56 Datum pgis_union_geometry_array(PG_FUNCTION_ARGS);
57 Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS);
58 Datum polygonize_garray(PG_FUNCTION_ARGS);
59 Datum clusterintersecting_garray(PG_FUNCTION_ARGS);
60 Datum cluster_within_distance_garray(PG_FUNCTION_ARGS);
61 Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS);
62 
63 
83 typedef struct
84 {
85  ArrayBuildState *a;
86  Datum data;
87 }
88 pgis_abs;
89 
90 
91 
97 Datum
98 pgis_abs_in(PG_FUNCTION_ARGS)
99 {
100  ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
101  errmsg("function %s not implemented", __func__)));
102  PG_RETURN_POINTER(NULL);
103 }
105 Datum
106 pgis_abs_out(PG_FUNCTION_ARGS)
107 {
108  ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
109  errmsg("function %s not implemented", __func__)));
110  PG_RETURN_POINTER(NULL);
111 }
112 
119 Datum
121 {
122  Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
123  MemoryContext aggcontext;
124  ArrayBuildState *state;
125  pgis_abs *p;
126  Datum elem;
127 
128  if (arg1_typeid == InvalidOid)
129  ereport(ERROR,
130  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
131  errmsg("could not determine input data type")));
132 
133  if ( ! AggCheckCallContext(fcinfo, &aggcontext) )
134  {
135  /* cannot be called directly because of dummy-type argument */
136  elog(ERROR, "%s called in non-aggregate context", __func__);
137  aggcontext = NULL; /* keep compiler quiet */
138  }
139 
140  if ( PG_ARGISNULL(0) )
141  {
142  p = (pgis_abs*) palloc(sizeof(pgis_abs));
143  p->a = NULL;
144  p->data = (Datum) NULL;
145 
146  if (PG_NARGS() == 3)
147  {
148  Datum argument = PG_GETARG_DATUM(2);
149  Oid dataOid = get_fn_expr_argtype(fcinfo->flinfo, 2);
150  MemoryContext old = MemoryContextSwitchTo(aggcontext);
151 
152  p->data = datumCopy(argument, get_typbyval(dataOid), get_typlen(dataOid));
153 
154  MemoryContextSwitchTo(old);
155  }
156  }
157  else
158  {
159  p = (pgis_abs*) PG_GETARG_POINTER(0);
160  }
161  state = p->a;
162  elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
163  state = accumArrayResult(state,
164  elem,
165  PG_ARGISNULL(1),
166  arg1_typeid,
167  aggcontext);
168  p->a = state;
169 
170  PG_RETURN_POINTER(p);
171 }
172 
173 
174 
175 Datum pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo);
176 
181 Datum
182 pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo)
183 {
184  int dims[1];
185  int lbs[1];
186  ArrayBuildState *state;
187  Datum result;
188 
189  /* cannot be called directly because of internal-type argument */
190  Assert(fcinfo->context &&
191  (IsA(fcinfo->context, AggState) ||
192  IsA(fcinfo->context, WindowAggState))
193  );
194 
195  state = p->a;
196  dims[0] = state->nelems;
197  lbs[0] = 1;
198  result = makeMdArrayResult(state, 1, dims, lbs, mctx, false);
199  return result;
200 }
201 
206 Datum
208 {
209  pgis_abs *p;
210  Datum result = 0;
211 
212  if (PG_ARGISNULL(0))
213  PG_RETURN_NULL(); /* returns null iff no input values */
214 
215  p = (pgis_abs*) PG_GETARG_POINTER(0);
216 
217  result = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
218 
219  PG_RETURN_DATUM(result);
220 
221 }
222 
228 Datum
230 {
231  pgis_abs *p;
232  Datum result = 0;
233  Datum geometry_array = 0;
234 
235  if (PG_ARGISNULL(0))
236  PG_RETURN_NULL(); /* returns null iff no input values */
237 
238  p = (pgis_abs*) PG_GETARG_POINTER(0);
239 
240  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
241  result = PGISDirectFunctionCall1( pgis_union_geometry_array, geometry_array );
242  if (!result)
243  PG_RETURN_NULL();
244 
245  PG_RETURN_DATUM(result);
246 }
247 
253 Datum
255 {
256  pgis_abs *p;
257  Datum result = 0;
258  Datum geometry_array = 0;
259 
260  if (PG_ARGISNULL(0))
261  PG_RETURN_NULL(); /* returns null iff no input values */
262 
263  p = (pgis_abs*) PG_GETARG_POINTER(0);
264 
265  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
266  result = PGISDirectFunctionCall1( LWGEOM_collect_garray, geometry_array );
267  if (!result)
268  PG_RETURN_NULL();
269 
270  PG_RETURN_DATUM(result);
271 }
272 
273 
279 Datum
281 {
282  pgis_abs *p;
283  Datum result = 0;
284  Datum geometry_array = 0;
285 
286  if (PG_ARGISNULL(0))
287  PG_RETURN_NULL(); /* returns null iff no input values */
288 
289  p = (pgis_abs*) PG_GETARG_POINTER(0);
290 
291  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
292  result = PGISDirectFunctionCall1( polygonize_garray, geometry_array );
293  if (!result)
294  PG_RETURN_NULL();
295 
296  PG_RETURN_DATUM(result);
297 }
298 
304 Datum
306 {
307  pgis_abs *p;
308  Datum result = 0;
309  Datum geometry_array = 0;
310 
311  if (PG_ARGISNULL(0))
312  PG_RETURN_NULL(); /* returns null iff no input values */
313 
314  p = (pgis_abs*) PG_GETARG_POINTER(0);
315 
316  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
317  result = PGISDirectFunctionCall1( LWGEOM_makeline_garray, geometry_array );
318  if (!result)
319  PG_RETURN_NULL();
320 
321  PG_RETURN_DATUM(result);
322 }
323 
329 Datum
331 {
332  pgis_abs *p;
333  Datum result = 0;
334  Datum geometry_array = 0;
335 
336  if (PG_ARGISNULL(0))
337  PG_RETURN_NULL();
338 
339  p = (pgis_abs*) PG_GETARG_POINTER(0);
340  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
341  result = PGISDirectFunctionCall1( clusterintersecting_garray, geometry_array );
342  if (!result)
343  PG_RETURN_NULL();
344 
345  PG_RETURN_DATUM(result);
346 }
347 
353 Datum
355 {
356  pgis_abs *p;
357  Datum result = 0;
358  Datum geometry_array = 0;
359 
360  if (PG_ARGISNULL(0))
361  PG_RETURN_NULL();
362 
363  p = (pgis_abs*) PG_GETARG_POINTER(0);
364 
365  if (!p->data)
366  {
367  elog(ERROR, "Tolerance not defined");
368  PG_RETURN_NULL();
369  }
370 
371  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
372  result = PGISDirectFunctionCall2( cluster_within_distance_garray, geometry_array, p->data);
373  if (!result)
374  PG_RETURN_NULL();
375 
376  PG_RETURN_DATUM(result);
377 }
378 
383 Datum
384 PGISDirectFunctionCall1(PGFunction func, Datum arg1)
385 {
386 #if POSTGIS_PGSQL_VERSION < 120
387  FunctionCallInfoData fcinfo;
388  Datum result;
389 
390 
391  InitFunctionCallInfoData(fcinfo, NULL, 1, InvalidOid, NULL, NULL);
392 
393 
394  fcinfo.arg[0] = arg1;
395  fcinfo.argnull[0] = false;
396 
397  result = (*func) (&fcinfo);
398 
399  /* Check for null result, returning a "NULL" Datum if indicated */
400  if (fcinfo.isnull)
401  return (Datum) 0;
402 
403  return result;
404 #else
405  LOCAL_FCINFO(fcinfo, 1);
406  Datum result;
407 
408  InitFunctionCallInfoData(*fcinfo, NULL, 1, InvalidOid, NULL, NULL);
409 
410  fcinfo->args[0].value = arg1;
411  fcinfo->args[0].isnull = false;
412 
413  result = (*func)(fcinfo);
414 
415  /* Check for null result, returning a "NULL" Datum if indicated */
416  if (fcinfo->isnull)
417  return (Datum)0;
418 
419  return result;
420 #endif /* POSTGIS_PGSQL_VERSION < 120 */
421 }
422 
427 Datum
428 PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
429 {
430 #if POSTGIS_PGSQL_VERSION < 120
431  FunctionCallInfoData fcinfo;
432  Datum result;
433 
434  InitFunctionCallInfoData(fcinfo, NULL, 2, InvalidOid, NULL, NULL);
435 
436  fcinfo.arg[0] = arg1;
437  fcinfo.arg[1] = arg2;
438  fcinfo.argnull[0] = false;
439  fcinfo.argnull[1] = false;
440 
441  result = (*func) (&fcinfo);
442 
443  /* Check for null result, returning a "NULL" Datum if indicated */
444  if (fcinfo.isnull)
445  return (Datum) 0;
446 
447  return result;
448 #else
449  LOCAL_FCINFO(fcinfo, 2);
450  Datum result;
451 
452  InitFunctionCallInfoData(*fcinfo, NULL, 2, InvalidOid, NULL, NULL);
453 
454  fcinfo->args[0].value = arg1;
455  fcinfo->args[1].value = arg2;
456  fcinfo->args[0].isnull = false;
457  fcinfo->args[1].isnull = false;
458 
459  result = (*func)(fcinfo);
460 
461  /* Check for null result, returning a "NULL" Datum if indicated */
462  if (fcinfo->isnull)
463  return (Datum)0;
464 
465  return result;
466 #endif /* POSTGIS_PGSQL_VERSION < 120 */
467 }
Datum pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo)
The final function rescues the built array from the side memory context using the PostgreSQL built-in...
Definition: lwgeom_accum.c:182
Datum pgis_union_geometry_array(PG_FUNCTION_ARGS)
Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:120
Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:280
Datum pgis_abs_in(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:98
ArrayBuildState * a
Definition: lwgeom_accum.c:85
Datum pgis_geometry_clusterintersecting_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:330
Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:229
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:254
Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:305
Datum data
Definition: lwgeom_accum.c:86
Datum pgis_abs_out(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:106
Datum pgis_geometry_clusterwithin_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:354
Datum cluster_within_distance_garray(PG_FUNCTION_ARGS)
Datum PGISDirectFunctionCall1(PGFunction func, Datum arg1)
A modified version of PostgreSQL&#39;s DirectFunctionCall1 which allows NULL results; this is required fo...
Definition: lwgeom_accum.c:384
Datum PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
A modified version of PostgreSQL&#39;s DirectFunctionCall2 which allows NULL results; this is required fo...
Definition: lwgeom_accum.c:428
Datum pgis_geometry_accum_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:207
Datum clusterintersecting_garray(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pgis_abs_in)
We&#39;re never going to use this type externally so the in/out functions are dummies.
To pass the internal ArrayBuildState pointer between the transfn and finalfn we need to wrap it into ...
Definition: lwgeom_accum.c:83
This library is the generic geometry handling section of PostGIS.
Datum polygonize_garray(PG_FUNCTION_ARGS)