PostGIS  2.5.0dev-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 
53 /* External prototypes */
54 Datum pgis_union_geometry_array(PG_FUNCTION_ARGS);
55 Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS);
56 Datum polygonize_garray(PG_FUNCTION_ARGS);
57 Datum clusterintersecting_garray(PG_FUNCTION_ARGS);
58 Datum cluster_within_distance_garray(PG_FUNCTION_ARGS);
59 Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS);
60 
61 
81 typedef struct
82 {
83  ArrayBuildState *a;
84  Datum data;
85 }
86 pgis_abs;
87 
88 
95 Datum
96 pgis_geometry_accum_transfn(PG_FUNCTION_ARGS)
97 {
98  Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
99  MemoryContext aggcontext;
100  ArrayBuildState *state;
101  pgis_abs *p;
102  Datum elem;
103 
104  if (arg1_typeid == InvalidOid)
105  ereport(ERROR,
106  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
107  errmsg("could not determine input data type")));
108 
109  if ( ! AggCheckCallContext(fcinfo, &aggcontext) )
110  {
111  /* cannot be called directly because of dummy-type argument */
112  elog(ERROR, "%s called in non-aggregate context", __func__);
113  aggcontext = NULL; /* keep compiler quiet */
114  }
115 
116  if ( PG_ARGISNULL(0) )
117  {
118  MemoryContext old = MemoryContextSwitchTo(aggcontext);
119  p = (pgis_abs*) palloc(sizeof(pgis_abs));
120  p->a = NULL;
121  p->data = (Datum) NULL;
122 
123  if (PG_NARGS() == 3)
124  {
125  Datum argument = PG_GETARG_DATUM(2);
126  Oid dataOid = get_fn_expr_argtype(fcinfo->flinfo, 2);
127 
128  p->data = datumCopy(argument, get_typbyval(dataOid), get_typlen(dataOid));
129 
130  }
131  MemoryContextSwitchTo(old);
132  }
133  else
134  {
135  p = (pgis_abs*) PG_GETARG_POINTER(0);
136  }
137  state = p->a;
138  elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
139  state = accumArrayResult(state,
140  elem,
141  PG_ARGISNULL(1),
142  arg1_typeid,
143  aggcontext);
144  p->a = state;
145 
146  PG_RETURN_POINTER(p);
147 }
148 
149 
150 
151 Datum pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo);
152 
157 Datum
158 pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, __attribute__((__unused__)) FunctionCallInfo fcinfo)
159 {
160  int dims[1];
161  int lbs[1];
162  ArrayBuildState *state;
163  Datum result;
164 
165  /* cannot be called directly because of internal-type argument */
166  Assert(fcinfo->context &&
167  (IsA(fcinfo->context, AggState) ||
168  IsA(fcinfo->context, WindowAggState))
169  );
170 
171  state = p->a;
172  dims[0] = state->nelems;
173  lbs[0] = 1;
174  result = makeMdArrayResult(state, 1, dims, lbs, mctx, false);
175  return result;
176 }
177 
182 Datum
184 {
185  pgis_abs *p;
186  Datum result = 0;
187 
188  if (PG_ARGISNULL(0))
189  PG_RETURN_NULL(); /* returns null iff no input values */
190 
191  p = (pgis_abs*) PG_GETARG_POINTER(0);
192 
193  result = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
194 
195  PG_RETURN_DATUM(result);
196 
197 }
198 
204 Datum
206 {
207  pgis_abs *p;
208  Datum result = 0;
209  Datum geometry_array = 0;
210 
211  if (PG_ARGISNULL(0))
212  PG_RETURN_NULL(); /* returns null iff no input values */
213 
214  p = (pgis_abs*) PG_GETARG_POINTER(0);
215 
216  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
217  result = PGISDirectFunctionCall1( pgis_union_geometry_array, geometry_array );
218  if (!result)
219  PG_RETURN_NULL();
220 
221  PG_RETURN_DATUM(result);
222 }
223 
229 Datum
231 {
232  pgis_abs *p;
233  Datum result = 0;
234  Datum geometry_array = 0;
235 
236  if (PG_ARGISNULL(0))
237  PG_RETURN_NULL(); /* returns null iff no input values */
238 
239  p = (pgis_abs*) PG_GETARG_POINTER(0);
240 
241  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
242  result = PGISDirectFunctionCall1( LWGEOM_collect_garray, geometry_array );
243  if (!result)
244  PG_RETURN_NULL();
245 
246  PG_RETURN_DATUM(result);
247 }
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( polygonize_garray, geometry_array );
269  if (!result)
270  PG_RETURN_NULL();
271 
272  PG_RETURN_DATUM(result);
273 }
274 
280 Datum
282 {
283  pgis_abs *p;
284  Datum result = 0;
285  Datum geometry_array = 0;
286 
287  if (PG_ARGISNULL(0))
288  PG_RETURN_NULL(); /* returns null iff no input values */
289 
290  p = (pgis_abs*) PG_GETARG_POINTER(0);
291 
292  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
293  result = PGISDirectFunctionCall1( LWGEOM_makeline_garray, geometry_array );
294  if (!result)
295  PG_RETURN_NULL();
296 
297  PG_RETURN_DATUM(result);
298 }
299 
305 Datum
307 {
308  pgis_abs *p;
309  Datum result = 0;
310  Datum geometry_array = 0;
311 
312  if (PG_ARGISNULL(0))
313  PG_RETURN_NULL();
314 
315  p = (pgis_abs*) PG_GETARG_POINTER(0);
316  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
317  result = PGISDirectFunctionCall1( clusterintersecting_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 
341  if (!p->data)
342  {
343  elog(ERROR, "Tolerance not defined");
344  PG_RETURN_NULL();
345  }
346 
347  geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo);
348  result = PGISDirectFunctionCall2( cluster_within_distance_garray, geometry_array, p->data);
349  if (!result)
350  PG_RETURN_NULL();
351 
352  PG_RETURN_DATUM(result);
353 }
354 
359 Datum
360 PGISDirectFunctionCall1(PGFunction func, Datum arg1)
361 {
362  FunctionCallInfoData fcinfo;
363  Datum result;
364 
365 
366  InitFunctionCallInfoData(fcinfo, NULL, 1, InvalidOid, NULL, NULL);
367 
368 
369  fcinfo.arg[0] = arg1;
370  fcinfo.argnull[0] = false;
371 
372  result = (*func) (&fcinfo);
373 
374  /* Check for null result, returning a "NULL" Datum if indicated */
375  if (fcinfo.isnull)
376  return (Datum) 0;
377 
378  return result;
379 }
380 
385 Datum
386 PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
387 {
388  FunctionCallInfoData fcinfo;
389  Datum result;
390 
391 #if POSTGIS_PGSQL_VERSION > 90
392 
393  InitFunctionCallInfoData(fcinfo, NULL, 2, InvalidOid, NULL, NULL);
394 #else
395 
396  InitFunctionCallInfoData(fcinfo, NULL, 2, NULL, NULL);
397 #endif
398 
399  fcinfo.arg[0] = arg1;
400  fcinfo.arg[1] = arg2;
401  fcinfo.argnull[0] = false;
402  fcinfo.argnull[1] = false;
403 
404  result = (*func) (&fcinfo);
405 
406  /* Check for null result, returning a "NULL" Datum if indicated */
407  if (fcinfo.isnull)
408  return (Datum) 0;
409 
410  return result;
411 }
Datum pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo)
Datum pgis_union_geometry_array(PG_FUNCTION_ARGS)
Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:96
Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:256
ArrayBuildState * a
Definition: lwgeom_accum.c:83
#define __attribute__(x)
Definition: liblwgeom.h:200
PG_FUNCTION_INFO_V1(pgis_geometry_accum_transfn)
The transfer function hooks into the PostgreSQL accumArrayResult() function (present since 8...
Datum pgis_geometry_clusterintersecting_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:306
Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:205
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:230
Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS)
Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:281
Datum data
Definition: lwgeom_accum.c:84
Datum pgis_geometry_clusterwithin_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:330
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:360
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:386
Datum pgis_geometry_accum_finalfn(PG_FUNCTION_ARGS)
Definition: lwgeom_accum.c:183
Datum clusterintersecting_garray(PG_FUNCTION_ARGS)
To pass the internal ArrayBuildState pointer between the transfn and finalfn we need to wrap it into ...
Definition: lwgeom_accum.c:81
This library is the generic geometry handling section of PostGIS.
Datum polygonize_garray(PG_FUNCTION_ARGS)