pgRouting  2.2
pgRouting extends the PostGIS / PostgreSQL geospatial database to provide geospatial routing functionality.
 All Classes Functions Variables Pages
one_to_many_withPoints.c
1 /*PGR-GNU*****************************************************************
2 File: one_to_many_withPoints.c
3 
4 Generated with Template by:
5 Copyright (c) 2015 pgRouting developers
6 Mail: project@pgrouting.org
7 
8 Function's developer:
9 Copyright (c) 2015 Celia Virginia Vergara Castillo
10 Mail:
11 
12 ------
13 
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18 
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23 
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 
28 ********************************************************************PGR-GNU*/
29 
30 #include "postgres.h"
31 #include "executor/spi.h"
32 #include "funcapi.h"
33 #include "utils/array.h"
34 #include "catalog/pg_type.h"
35 #if PGSQL_VERSION > 92
36 #include "access/htup_details.h"
37 #endif
38 
39 // #define DEBUG
40 
41 #include "fmgr.h"
42 #include "./../../common/src/debug_macro.h"
43 #include "./../../common/src/time_msg.h"
44 #include "./../../common/src/pgr_types.h"
45 #include "./../../common/src/postgres_connection.h"
46 #include "./../../common/src/edges_input.h"
47 #include "./../../common/src/arrays_input.h"
48 #include "./../../common/src/points_input.h"
49 #include "./get_new_queries.h"
50 #include "./one_to_many_withPoints_driver.h"
51 
52 PG_FUNCTION_INFO_V1(one_to_many_withPoints);
53 #ifndef _MSC_VER
54 Datum
55 #else // _MSC_VER
56 PGDLLEXPORT Datum
57 #endif
58 one_to_many_withPoints(PG_FUNCTION_ARGS);
59 
60 
61 /*******************************************************************************/
62 /* MODIFY AS NEEDED */
63 static
64 void
65 process(
66  char* edges_sql,
67  char* points_sql,
68  int64_t start_pid,
69  int64_t *end_pidsArr,
70  size_t size_end_pidsArr,
71  bool directed,
72  char *driving_side,
73  bool details,
74  bool only_cost,
75  General_path_element_t **result_tuples,
76  size_t *result_count) {
77 
78  driving_side[0] = tolower(driving_side[0]);
79  PGR_DBG("driving side:%c",driving_side[0]);
80  if (! ((driving_side[0] == 'r')
81  || (driving_side[0] == 'l'))) {
82  driving_side[0] = 'b';
83  }
84  PGR_DBG("estimated driving side:%c",driving_side[0]);
85 
86  pgr_SPI_connect();
87 
88  PGR_DBG("load the points");
89  Point_on_edge_t *points = NULL;
90  size_t total_points = 0;
91  pgr_get_points(points_sql, &points, &total_points);
92 
93 #ifdef DEBUG
94  size_t i = 0;
95  for (i = 0; i < total_points; i ++) {
96  PGR_DBG("%ld\t%ld\t%f\t%c",points[i].pid, points[i].edge_id, points[i].fraction, points[i].side);
97  }
98 #endif
99 
100  /*
101  * TODO move this code to c++
102  */
103  PGR_DBG(" -- change the query");
104  char *edges_of_points_query = NULL;
105  char *edges_no_points_query = NULL;
106  get_new_queries(
107  edges_sql, points_sql,
108  &edges_of_points_query,
109  &edges_no_points_query);
110 
111  PGR_DBG("edges_of_points_query:\n%s", edges_of_points_query);
112  PGR_DBG("edges_no_points_query:\n%s", edges_no_points_query);
113 
114  PGR_DBG("load the edges that match the points");
115  pgr_edge_t *edges_of_points = NULL;
116  size_t total_edges_of_points = 0;
117  pgr_get_data_5_columns(edges_of_points_query, &edges_of_points, &total_edges_of_points);
118 
119  PGR_DBG("Total %ld edges in query:", total_edges_of_points);
120 #ifdef DEBUG
121  for (i = 0; i < total_edges_of_points; i ++) {
122  PGR_DBG("%ld\t%ld\t%ld\t%f\t%f",
123  edges_of_points[i].id,
124  edges_of_points[i].source,
125  edges_of_points[i].target,
126  edges_of_points[i].cost,
127  edges_of_points[i].reverse_cost);
128  }
129 #endif
130 
131 
132 
133  PGR_DBG("load the edges that dont match the points");
134  pgr_edge_t *edges = NULL;
135  size_t total_edges = 0;
136  pgr_get_data_5_columns(edges_no_points_query, &edges, &total_edges);
137 
138  PGR_DBG("Total %ld edges in query:", total_edges);
139 #ifdef DEBUG
140  for (i = 0; i < total_edges; i ++) {
141  PGR_DBG("%ld\t%ld\t%ld\t%f\t%f",
142  edges[i].id,
143  edges[i].source,
144  edges[i].target,
145  edges[i].cost,
146  edges[i].reverse_cost);
147  }
148 #endif
149 
150  PGR_DBG("freeing allocated memory not used anymore");
151  free(edges_of_points_query);
152  free(edges_no_points_query);
153 
154  if ( (total_edges + total_edges_of_points) == 0) {
155  PGR_DBG("No edges found");
156  (*result_count) = 0;
157  (*result_tuples) = NULL;
158  pgr_SPI_finish();
159  return;
160  }
161 
162  PGR_DBG("Starting processing");
163  char *err_msg = NULL;
164  clock_t start_t = clock();
165  int errcode = do_pgr_one_to_many_withPoints(
166  edges, total_edges,
167  points, total_points,
168  edges_of_points, total_edges_of_points,
169  start_pid,
170  end_pidsArr, size_end_pidsArr,
171  driving_side[0],
172  details,
173  directed,
174  only_cost,
175  result_tuples,
176  result_count,
177  &err_msg);
178  time_msg(" processing withPoints one to many", start_t, clock());
179  PGR_DBG("Returning %ld tuples\n", *result_count);
180  PGR_DBG("Returned message = %s\n", err_msg);
181  if (!err_msg) free(err_msg);
182 
183  pfree(edges);
184  pgr_SPI_finish();
185 
186 
187  if (errcode) {
188  PGR_DBG("Cleaning arrays because there was an error to avoid leak");
189  free(end_pidsArr);
190  pgr_send_error(errcode);
191  }
192 }
193 
194 /* */
195 /*******************************************************************************/
196 
197 #ifndef _MSC_VER
198 Datum
199 #else // _MSC_VER
200 PGDLLEXPORT Datum
201 #endif
202 one_to_many_withPoints(PG_FUNCTION_ARGS) {
203  FuncCallContext *funcctx;
204  uint32_t call_cntr;
205  uint32_t max_calls;
206  TupleDesc tuple_desc;
207 
208  /*******************************************************************************/
209  /* MODIFY AS NEEDED */
210  /* */
211  General_path_element_t *result_tuples = 0;
212  size_t result_count = 0;
213  /* */
214  /*******************************************************************************/
215 
216  if (SRF_IS_FIRSTCALL()) {
217  MemoryContext oldcontext;
218  funcctx = SRF_FIRSTCALL_INIT();
219  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
220 
221 
222  /*******************************************************************************/
223  /* MODIFY AS NEEDED */
224  // CREATE OR REPLACE FUNCTION pgr_withPoint(
225  // edges_sql TEXT,
226  // points_sql TEXT,
227  // start_pid BIGINT,
228  // end_pids ANYARRAY,
229  // directed BOOLEAN -- DEFAULT true,
230  // driving_side CHAR -- DEFAULT 'b',
231  // details BOOLEAN -- DEFAULT false,
232  // only_cost BOOLEAN DEFAULT false,
233 
234 
235  PGR_DBG("Initializing arrays");
236  int64_t* end_pidsArr;
237  size_t size_end_pidsArr;
238  end_pidsArr = (int64_t*)
239  pgr_get_bigIntArray(&size_end_pidsArr, PG_GETARG_ARRAYTYPE_P(3));
240  PGR_DBG("targetsArr size %ld ", size_end_pidsArr);
241 
242  PGR_DBG("Calling process");
243  PGR_DBG("initial driving side:%s", pgr_text2char(PG_GETARG_TEXT_P(4)));
244  process(
245  pgr_text2char(PG_GETARG_TEXT_P(0)),
246  pgr_text2char(PG_GETARG_TEXT_P(1)),
247  PG_GETARG_INT64(2),
248  end_pidsArr, size_end_pidsArr,
249  PG_GETARG_BOOL(4),
250  pgr_text2char(PG_GETARG_TEXT_P(5)),
251  PG_GETARG_BOOL(6),
252  PG_GETARG_BOOL(7),
253  &result_tuples,
254  &result_count);
255 
256  PGR_DBG("Cleaning arrays");
257  free(end_pidsArr);
258  /* */
259  /*******************************************************************************/
260 
261  funcctx->max_calls = (uint32_t)result_count;
262  funcctx->user_fctx = result_tuples;
263  if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
264  ereport(ERROR,
265  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
266  errmsg("function returning record called in context "
267  "that cannot accept type record")));
268 
269  funcctx->tuple_desc = tuple_desc;
270  MemoryContextSwitchTo(oldcontext);
271  }
272 
273  funcctx = SRF_PERCALL_SETUP();
274  call_cntr = funcctx->call_cntr;
275  max_calls = funcctx->max_calls;
276  tuple_desc = funcctx->tuple_desc;
277  result_tuples = (General_path_element_t*) funcctx->user_fctx;
278 
279  if (call_cntr < max_calls) {
280  HeapTuple tuple;
281  Datum result;
282  Datum *values;
283  char* nulls;
284 
285  /*******************************************************************************/
286  /* MODIFY AS NEEDED */
287  // OUT seq BIGINT,
288  // OUT path_seq,
289  // OUT node BIGINT,
290  // OUT edge BIGINT,
291  // OUT cost FLOAT,
292  // OUT agg_cost FLOAT)
293 
294 
295  values = palloc(7 * sizeof(Datum));
296  nulls = palloc(7 * sizeof(char));
297 
298  size_t i;
299  for(i = 0; i < 7; ++i) {
300  nulls[i] = ' ';
301  }
302 
303 
304  // postgres starts counting from 1
305  values[0] = Int32GetDatum(call_cntr + 1);
306  values[1] = Int32GetDatum(result_tuples[call_cntr].seq);
307  values[2] = Int64GetDatum(result_tuples[call_cntr].end_id);
308  values[3] = Int64GetDatum(result_tuples[call_cntr].node);
309  values[4] = Int64GetDatum(result_tuples[call_cntr].edge);
310  values[5] = Float8GetDatum(result_tuples[call_cntr].cost);
311  values[6] = Float8GetDatum(result_tuples[call_cntr].agg_cost);
312  /*******************************************************************************/
313 
314  tuple = heap_formtuple(tuple_desc, values, nulls);
315  result = HeapTupleGetDatum(tuple);
316  SRF_RETURN_NEXT(funcctx, result);
317  } else {
318  // cleanup
319  if (result_tuples) free(result_tuples);
320 
321  SRF_RETURN_DONE(funcctx);
322  }
323 }
324