PostGIS  2.2.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  * Copyright 2009 Paul Ramsey <pramsey@opengeo.org>
6  *
7  * This is free software; you can redistribute and/or modify it under
8  * the terms of the GNU General Public Licence. See the COPYING file.
9  *
10  **********************************************************************/
11 
12 #include "postgres.h"
13 #include "fmgr.h"
14 #include "funcapi.h"
15 #include "access/tupmacs.h"
16 #include "utils/datum.h"
17 #include "utils/array.h"
18 #include "utils/lsyscache.h"
19 
20 #include "../postgis_config.h"
21 
22 #include "liblwgeom.h"
23 #include "lwgeom_geos.h"
24 #include "lwgeom_pg.h"
25 #include "lwgeom_transform.h"
26 
27 /* Local prototypes */
28 Datum PGISDirectFunctionCall1(PGFunction func, Datum arg1);
29 Datum PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2);
30 Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS);
31 Datum pgis_geometry_accum_finalfn(PG_FUNCTION_ARGS);
32 Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS);
33 Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS);
34 Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS);
35 Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS);
36 Datum pgis_geometry_clusterintersecting_finalfn(PG_FUNCTION_ARGS);
37 Datum pgis_geometry_clusterwithin_finalfn(PG_FUNCTION_ARGS);
38 Datum pgis_abs_in(PG_FUNCTION_ARGS);
39 Datum pgis_abs_out(PG_FUNCTION_ARGS);
40 
41 /* External prototypes */
42 Datum pgis_union_geometry_array(PG_FUNCTION_ARGS);
43 Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS);
44 Datum polygonize_garray(PG_FUNCTION_ARGS);
45 Datum clusterintersecting_garray(PG_FUNCTION_ARGS);
46 Datum cluster_within_distance_garray(PG_FUNCTION_ARGS);
47 Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS);
48 
49 
69 typedef struct
70 {
71  ArrayBuildState *a;
72  Datum data;
73 }
74 pgis_abs;
75 
76 
77 
83 Datum
84 pgis_abs_in(PG_FUNCTION_ARGS)
85 {
86  ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
87  errmsg("function %s not implemented", __func__)));
88  PG_RETURN_POINTER(NULL);
89 }
91 Datum
92 pgis_abs_out(PG_FUNCTION_ARGS)
93 {
94  ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
95  errmsg("function %s not implemented", __func__)));
96  PG_RETURN_POINTER(NULL);
97 }
98 
105 Datum
107 {
108  Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
109  MemoryContext aggcontext;
110  ArrayBuildState *state;
111  pgis_abs *p;
112  Datum elem;
113 
114  if (arg1_typeid == InvalidOid)
115  ereport(ERROR,
116  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
117  errmsg("could not determine input data type")));
118 
119  if ( ! AggCheckCallContext(fcinfo, &aggcontext) )
120  {
121  /* cannot be called directly because of dummy-type argument */
122  elog(ERROR, "%s called in non-aggregate context", __func__);
123  aggcontext = NULL; /* keep compiler quiet */
124  }
125 
126  if ( PG_ARGISNULL(0) )
127  {
128  p = (pgis_abs*) palloc(sizeof(pgis_abs));
129  p->a = NULL;
130  p->data = (Datum) NULL;
131 
132  if (PG_NARGS() == 3)
133  {
134  Datum argument = PG_GETARG_DATUM(2);
135  Oid dataOid = get_fn_expr_argtype(fcinfo->flinfo, 2);
136  MemoryContext old = MemoryContextSwitchTo(aggcontext);
137 
138  p->data = datumCopy(argument, get_typbyval(dataOid), get_typlen(dataOid));
139 
140  MemoryContextSwitchTo(old);
141  }
142  }
143  else
144  {
145  p = (pgis_abs*) PG_GETARG_POINTER(0);
146  }
147  state = p->a;
148  elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
149  state = accumArrayResult(state,
150  elem,
151  PG_ARGISNULL(1),
152  arg1_typeid,
153  aggcontext);
154  p->a = state;
155 
156  PG_RETURN_POINTER(p);
157 }
158 
159 
160 
161 Datum pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo);
162 
167 Datum
168 pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo)
169 {
170  int dims[1];
171  int lbs[1];
172  ArrayBuildState *state;
173  Datum result;
174 
175  /* cannot be called directly because of internal-type argument */
176  Assert(fcinfo->context &&
177  (IsA(fcinfo->context, AggState) ||
178  IsA(fcinfo->context, WindowAggState))
179  );
180 
181  state = p->a;
182  dims[0] = state->nelems;
183  lbs[0] = 1;
184  result = makeMdArrayResult(state, 1, dims, lbs, mctx, false);
185  return result;
186 }
187 
192 Datum
194 {
195  pgis_abs *p;
196  Datum result = 0;
197 
198  if (PG_ARGISNULL(0))
199  PG_RETURN_NULL(); /* returns null iff no input values */
200 
201  p = (pgis_abs*) PG_GETARG_POINTER(0);
202 
203  result = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
204 
205  PG_RETURN_DATUM(result);
206 
207 }
208 
214 Datum
216 {
217  pgis_abs *p;
218  Datum result = 0;
219  Datum geometry_array = 0;
220 
221  if (PG_ARGISNULL(0))
222  PG_RETURN_NULL(); /* returns null iff no input values */
223 
224  p = (pgis_abs*) PG_GETARG_POINTER(0);
225 
226  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
227  result = PGISDirectFunctionCall1( pgis_union_geometry_array, geometry_array );
228  if (!result)
229  PG_RETURN_NULL();
230 
231  PG_RETURN_DATUM(result);
232 }
233 
239 Datum
241 {
242  pgis_abs *p;
243  Datum result = 0;
244  Datum geometry_array = 0;
245 
246  if (PG_ARGISNULL(0))
247  PG_RETURN_NULL(); /* returns null iff no input values */
248 
249  p = (pgis_abs*) PG_GETARG_POINTER(0);
250 
251  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
252  result = PGISDirectFunctionCall1( LWGEOM_collect_garray, geometry_array );
253  if (!result)
254  PG_RETURN_NULL();
255 
256  PG_RETURN_DATUM(result);
257 }
258 
259 
265 Datum
267 {
268  pgis_abs *p;
269  Datum result = 0;
270  Datum geometry_array = 0;
271 
272  if (PG_ARGISNULL(0))
273  PG_RETURN_NULL(); /* returns null iff no input values */
274 
275  p = (pgis_abs*) PG_GETARG_POINTER(0);
276 
277  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
278  result = PGISDirectFunctionCall1( polygonize_garray, geometry_array );
279  if (!result)
280  PG_RETURN_NULL();
281 
282  PG_RETURN_DATUM(result);
283 }
284 
290 Datum
292 {
293  pgis_abs *p;
294  Datum result = 0;
295  Datum geometry_array = 0;
296 
297  if (PG_ARGISNULL(0))
298  PG_RETURN_NULL(); /* returns null iff no input values */
299 
300  p = (pgis_abs*) PG_GETARG_POINTER(0);
301 
302  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
303  result = PGISDirectFunctionCall1( LWGEOM_makeline_garray, geometry_array );
304  if (!result)
305  PG_RETURN_NULL();
306 
307  PG_RETURN_DATUM(result);
308 }
309 
315 Datum
317 {
318  pgis_abs *p;
319  Datum result = 0;
320  Datum geometry_array = 0;
321 
322  if (PG_ARGISNULL(0))
323  PG_RETURN_NULL();
324 
325  p = (pgis_abs*) PG_GETARG_POINTER(0);
326  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
327  result = PGISDirectFunctionCall1( clusterintersecting_garray, geometry_array );
328  if (!result)
329  PG_RETURN_NULL();
330 
331  PG_RETURN_DATUM(result);
332 }
333 
339 Datum
341 {
342  pgis_abs *p;
343  Datum result = 0;
344  Datum geometry_array = 0;
345 
346  if (PG_ARGISNULL(0))
347  PG_RETURN_NULL();
348 
349  p = (pgis_abs*) PG_GETARG_POINTER(0);
350 
351  if (!p->data)
352  {
353  elog(ERROR, "Tolerance not defined");
354  PG_RETURN_NULL();
355  }
356 
357  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
358  result = PGISDirectFunctionCall2( cluster_within_distance_garray, geometry_array, p->data);
359  if (!result)
360  PG_RETURN_NULL();
361 
362  PG_RETURN_DATUM(result);
363 }
364 
369 Datum
370 PGISDirectFunctionCall1(PGFunction func, Datum arg1)
371 {
372  FunctionCallInfoData fcinfo;
373  Datum result;
374 
375 #if POSTGIS_PGSQL_VERSION > 90
376 
377  InitFunctionCallInfoData(fcinfo, NULL, 1, InvalidOid, NULL, NULL);
378 #else
379 
380  InitFunctionCallInfoData(fcinfo, NULL, 1, NULL, NULL);
381 #endif
382 
383  fcinfo.arg[0] = arg1;
384  fcinfo.argnull[0] = false;
385 
386  result = (*func) (&fcinfo);
387 
388  /* Check for null result, returning a "NULL" Datum if indicated */
389  if (fcinfo.isnull)
390  return (Datum) 0;
391 
392  return result;
393 }
394 
399 Datum
400 PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
401 {
402  FunctionCallInfoData fcinfo;
403  Datum result;
404 
405 #if POSTGIS_PGSQL_VERSION > 90
406 
407  InitFunctionCallInfoData(fcinfo, NULL, 1, InvalidOid, NULL, NULL);
408 #else
409 
410  InitFunctionCallInfoData(fcinfo, NULL, 1, NULL, NULL);
411 #endif
412 
413  fcinfo.arg[0] = arg1;
414  fcinfo.arg[1] = arg2;
415  fcinfo.argnull[0] = false;
416  fcinfo.argnull[1] = false;
417 
418  result = (*func) (&fcinfo);
419 
420  /* Check for null result, returning a "NULL" Datum if indicated */
421  if (fcinfo.isnull)
422  return (Datum) 0;
423 
424  return result;
425 }
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:168
Datum pgis_union_geometry_array(PG_FUNCTION_ARGS)
Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:106
Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:266
Datum pgis_abs_in(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:84
ArrayBuildState * a
Definition: lwgeom_accum.c:71
Datum pgis_geometry_clusterintersecting_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:316
Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:215
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:240
Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:291
Datum data
Definition: lwgeom_accum.c:72
Datum pgis_abs_out(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:92
Datum pgis_geometry_clusterwithin_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:340
Datum cluster_within_distance_garray(PG_FUNCTION_ARGS)
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:370
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:400
Datum pgis_geometry_accum_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:193
Datum clusterintersecting_garray(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(pgis_abs_in)
We'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:69
This library is the generic geometry handling section of PostGIS.
Datum polygonize_garray(PG_FUNCTION_ARGS)