pgRouting  2.2
pgRouting extends the PostGIS / PostgreSQL geospatial database to provide geospatial routing functionality.
 All Classes Functions Variables Pages
drivedist.c
1 /*PGR-GNU*****************************************************************
2 File: drivedist.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 #include "postgres.h"
26 #include "executor/spi.h"
27 #include "funcapi.h"
28 #include "catalog/pg_type.h"
29 #if PGSQL_VERSION > 92
30 #include "access/htup_details.h"
31 #endif
32 
33 //#define DEBUG
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 "./boost_interface_drivedist.h"
42 
43 PG_FUNCTION_INFO_V1(driving_distance);
44 #ifndef _MSC_VER
45 Datum
46 #else // _MSC_VER
47 PGDLLEXPORT Datum
48 #endif
49 driving_distance(PG_FUNCTION_ARGS);
50 
51 static
52 void compute_driving_distance(
53  char* sql,
54  int64_t start_vertex,
55  float8 distance,
56  bool directed,
57  General_path_element_t **path, size_t *path_count) {
58  pgr_SPI_connect();
59 
60  pgr_edge_t *edges = NULL;
61  size_t total_edges = 0;
62 
63 
64  char *err_msg = (char *)"";
65 
66  PGR_DBG("Load data");
67 
68  pgr_get_data_5_columns(sql, &edges, &total_edges);
69 
70  if (total_edges == 0) {
71  PGR_DBG("No edges found");
72  *path = NULL;
73  (*path_count) = 0;
74  pgr_SPI_finish();
75  return;
76  }
77  PGR_DBG("total edges read %ld\n", total_edges);
78 
79  clock_t start_t = clock();
80  do_pgr_driving_distance(edges, total_edges,
81  start_vertex, distance,
82  directed,
83  path, path_count, &err_msg);
84  time_msg(" processing Driving Distance one start", start_t, clock());
85 
86 
87  PGR_DBG("total tuples found %ld\n", *path_count);
88  PGR_DBG("Returned message = %s\n", err_msg);
89 
90  pfree(edges);
91  pgr_SPI_finish();
92 }
93 
94 
95 #ifndef _MSC_VER
96 Datum
97 #else // _MSC_VER
98 PGDLLEXPORT Datum
99 #endif
100 driving_distance(PG_FUNCTION_ARGS) {
101  FuncCallContext *funcctx;
102  uint32_t call_cntr;
103  uint32_t max_calls;
104  TupleDesc tuple_desc;
105  General_path_element_t *ret_path = 0;
106 
107  /* stuff done only on the first call of the function */
108  if (SRF_IS_FIRSTCALL()) {
109  MemoryContext oldcontext;
110  size_t path_count = 0;
111 
112  /* create a function context for cross-call persistence */
113  funcctx = SRF_FIRSTCALL_INIT();
114 
115  /* switch to memory context appropriate for multiple function calls */
116  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
117 
118  /*************************************************************************************************************
119  QUERY
120  CREATE OR REPLACE FUNCTION _pgr_drivingDistance(edges_sql text, start_vid bigint, distance float8, directed BOOLEAN,
121  OUT seq integer, OUT node bigint, OUT edge bigint, OUT cost float, OUT agg_cost float)
122  *************************************************************************************************************/
123  PGR_DBG("Sub query %s\n", pgr_text2char(PG_GETARG_TEXT_P(0)));
124 
125  compute_driving_distance(pgr_text2char(PG_GETARG_TEXT_P(0)), // edges_sql
126  PG_GETARG_INT64(1), // start_vid
127  PG_GETARG_FLOAT8(2), // distance
128  PG_GETARG_BOOL(3), // directed
129  &ret_path, &path_count);
130 
131  /* total number of tuples to be returned */
132  funcctx->max_calls = (uint32_t)path_count;
133  funcctx->user_fctx = ret_path;
134 
135  if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
136  ereport(ERROR,
137  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
138  errmsg("function returning record called in context "
139  "that cannot accept type record")));
140 
141  funcctx->tuple_desc = tuple_desc;
142 
143  MemoryContextSwitchTo(oldcontext);
144  }
145 
146  /* stuff done on every call of the function */
147  funcctx = SRF_PERCALL_SETUP();
148 
149  call_cntr = funcctx->call_cntr;
150  max_calls = funcctx->max_calls;
151  tuple_desc = funcctx->tuple_desc;
152  ret_path = (General_path_element_t*) funcctx->user_fctx;
153 
154  /* do when there is more left to send */
155  if (call_cntr < max_calls) {
156  HeapTuple tuple;
157  Datum result;
158  Datum *values;
159  char* nulls;
160 
161  values = palloc(5 * sizeof(Datum));
162  nulls = palloc(5 * sizeof(char));
163 
164  // TODO version 3.0 change to
165  // values[0] = Int64GetDatum(ret_path[call_cntr].seq + 1);
166  nulls[0] = ' ';
167  nulls[1] = ' ';
168  nulls[2] = ' ';
169  nulls[3] = ' ';
170  nulls[4] = ' ';
171  values[0] = Int32GetDatum(ret_path[call_cntr].seq + 1);
172  values[1] = Int64GetDatum(ret_path[call_cntr].node);
173  values[2] = Int64GetDatum(ret_path[call_cntr].edge);
174  values[3] = Float8GetDatum(ret_path[call_cntr].cost);
175  values[4] = Float8GetDatum(ret_path[call_cntr].agg_cost);
176 
177  tuple = heap_formtuple(tuple_desc, values, nulls);
178 
179  /* make the tuple into a datum */
180  result = HeapTupleGetDatum(tuple);
181 
182  /* clean up (this is not really necessary) */
183  pfree(values);
184  pfree(nulls);
185 
186  SRF_RETURN_NEXT(funcctx, result);
187  } else {
188  /* do when there is no more left */
189  if (ret_path) free(ret_path);
190  SRF_RETURN_DONE(funcctx);
191  }
192 }
193