pgRouting  2.2
pgRouting extends the PostGIS / PostgreSQL geospatial database to provide geospatial routing functionality.
 All Classes Functions Variables Pages
many_to_dist_driving_distance.c
1 /*PGR-GNU*****************************************************************
2 File: many_to_dist_driving_distance.c
3 
4 Copyright (c) 2015 Celia Virginia Vergara Castillo
5 Mail: vicky_Vergara@hotmail.com
6 
7 ------
8 
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 
23  ********************************************************************PGR-GNU*/
24 
25 // #define DEBUG
26 #include "postgres.h"
27 #include "executor/spi.h"
28 #include "funcapi.h"
29 #include "utils/array.h"
30 #include "catalog/pg_type.h"
31 #if PGSQL_VERSION > 92
32 #include "access/htup_details.h"
33 #endif
34 
35 #include "fmgr.h"
36 #include "./../../common/src/debug_macro.h"
37 #include "./../../common/src/time_msg.h"
38 #include "./../../common/src/pgr_types.h"
39 #include "./../../common/src/postgres_connection.h"
40 #include "./../../common/src/edges_input.h"
41 #include "./../../common/src/arrays_input.h"
42 #include "./boost_interface_drivedist.h"
43 
44 
45 
46 static
47 void driving_many_to_dist_driver(
48  char* sql,
49  int64_t *start_vertex, size_t num,
50  float8 distance,
51  bool directed,
52  bool equicost,
53  General_path_element_t **path, size_t *path_count) {
54  pgr_SPI_connect();
55  pgr_edge_t *edges = NULL;
56  size_t total_tuples = 0;
57 
58 
59  char *err_msg = (char *)"";
60 
61 
62  pgr_get_data_5_columns(sql, &edges, &total_tuples);
63 
64  if (total_tuples == 0) {
65  PGR_DBG("No edges found");
66  (*path_count) = 0;
67  *path = NULL;
68  return;
69  }
70 
71  clock_t start_t = clock();
72  do_pgr_driving_many_to_dist(
73  edges, total_tuples,
74  start_vertex, num,
75  distance,
76  directed,
77  equicost,
78  path, path_count, &err_msg);
79  time_msg(" processing DrivingDistance many starts", start_t, clock());
80 
81  pfree(edges);
82  pgr_SPI_finish();
83 }
84 
85 
86 #ifndef _MSC_VER
87 Datum driving_many_to_dist(PG_FUNCTION_ARGS);
88 #else // _MSC_VER
89 PGDLLEXPORT Datum driving_many_to_dist(PG_FUNCTION_ARGS);
90 #endif // _MSC_VER
91 
92 
93 PG_FUNCTION_INFO_V1(driving_many_to_dist);
94 #ifndef _MSC_VER
95 Datum
96 #else // _MSC_VER
97 PGDLLEXPORT Datum
98 #endif
99 driving_many_to_dist(PG_FUNCTION_ARGS) {
100  FuncCallContext *funcctx;
101  uint32_t call_cntr;
102  uint32_t max_calls;
103  TupleDesc tuple_desc;
104  General_path_element_t *ret_path = 0;
105 
106  /* stuff done only on the first call of the function */
107  if (SRF_IS_FIRSTCALL()) {
108  MemoryContext oldcontext;
109  size_t path_count = 0;
110 
111  /* create a function context for cross-call persistence */
112  funcctx = SRF_FIRSTCALL_INIT();
113 
114  /* switch to memory context appropriate for multiple function calls */
115  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
116 
117  int64_t* sourcesArr;
118  size_t num;
119 
120  sourcesArr = (int64_t*) pgr_get_bigIntArray(&num, PG_GETARG_ARRAYTYPE_P(1));
121  PGR_DBG("sourcesArr size %d ", num);
122 
123  PGR_DBG("Calling driving_many_to_dist_driver");
124  driving_many_to_dist_driver(
125  pgr_text2char(PG_GETARG_TEXT_P(0)), // sql
126  sourcesArr, num, // array of sources
127  PG_GETARG_FLOAT8(2), // distance
128  PG_GETARG_BOOL(3), // directed
129  PG_GETARG_BOOL(4), // equicost
130  &ret_path, &path_count);
131 
132  free(sourcesArr);
133 
134  /* total number of tuples to be returned */
135  funcctx->max_calls = (uint32_t) path_count;
136  funcctx->user_fctx = ret_path;
137  if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
138  ereport(ERROR,
139  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
140  errmsg("function returning record called in context "
141  "that cannot accept type record")));
142 
143  funcctx->tuple_desc = tuple_desc;
144 
145  MemoryContextSwitchTo(oldcontext);
146  }
147 
148  /* stuff done on every call of the function */
149  funcctx = SRF_PERCALL_SETUP();
150 
151  call_cntr = funcctx->call_cntr;
152  max_calls = funcctx->max_calls;
153  tuple_desc = funcctx->tuple_desc;
154  ret_path = (General_path_element_t*) funcctx->user_fctx;
155 
156  /* do when there is more left to send */
157  if (call_cntr < max_calls) {
158  HeapTuple tuple;
159  Datum result;
160  Datum *values;
161  char* nulls;
162 
163  values = palloc(6 * sizeof(Datum));
164  nulls = palloc(6 * sizeof(char));
165  // id, start_v, node, edge, cost, tot_cost
166  nulls[0] = ' ';
167  nulls[1] = ' ';
168  nulls[2] = ' ';
169  nulls[3] = ' ';
170  nulls[4] = ' ';
171  nulls[5] = ' ';
172  values[0] = Int32GetDatum(call_cntr + 1);
173  values[1] = Int64GetDatum(ret_path[call_cntr].start_id);
174  values[2] = Int64GetDatum(ret_path[call_cntr].node);
175  values[3] = Int64GetDatum(ret_path[call_cntr].edge);
176  values[4] = Float8GetDatum(ret_path[call_cntr].cost);
177  values[5] = Float8GetDatum(ret_path[call_cntr].agg_cost);
178 
179  tuple = heap_formtuple(tuple_desc, values, nulls);
180 
181  /* make the tuple into a datum */
182  result = HeapTupleGetDatum(tuple);
183 
184  /* clean up (this is not really necessary) */
185  pfree(values);
186  pfree(nulls);
187 
188  SRF_RETURN_NEXT(funcctx, result);
189  } else {
190  /* do when there is no more left */
191  if (ret_path) free(ret_path);
192  SRF_RETURN_DONE(funcctx);
193  }
194 }
195