pgRouting  2.2
pgRouting extends the PostGIS / PostgreSQL geospatial database to provide geospatial routing functionality.
 All Classes Functions Variables Pages
vrppdtw/src/pdp.c
1 /*PGR
2 
3 Copyright (c) 2014 Manikata Kondeti
4 mani.iiit123@gmail.com
5 
6 This program 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 This program 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 this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20 */
21 
22 #include "./postgres.h"
23 #include "executor/spi.h"
24 #include "funcapi.h"
25 #include "catalog/pg_type.h"
26 #if PGSQL_VERSION > 92
27 #include "access/htup_details.h"
28 #endif
29 
30 #include "fmgr.h"
31 #include "./pdp.h"
32 
33 
34 Datum vrppdtw(PG_FUNCTION_ARGS);
35 
36 
37 #undef DEBUG
38 //#define DEBUG 1
39 
40 #ifdef DEBUG
41 #define DBG(format, arg...) \
42  elog(NOTICE, format , ## arg)
43 #else
44 #define DBG(format, arg...) do { ; } while (0)
45 #endif
46 
47 // The number of tuples to fetch from the SPI cursor at each iteration
48 #define TUPLIMIT 1000
49 
50 #ifndef PG_MODULE_MAGIC
51 PG_MODULE_MAGIC;
52 #endif
53 
54 
55 
56 static char *text2char(text *in)
57 {
58  char *out = (char*)palloc(VARSIZE(in));
59 
60  memcpy(out, VARDATA(in), VARSIZE(in) - VARHDRSZ);
61  out[VARSIZE(in) - VARHDRSZ] = '\0';
62  return out;
63 }
64 
65  static int
66  finish(int code, int ret)
67  {
68  code = SPI_finish();
69  if (code != SPI_OK_FINISH ) {
70  elog(ERROR,"couldn't disconnect from SPI");
71  return -1 ;
72  }
73  return ret;
74  }
75 
76 
77 typedef struct Customer_type{
78  int id;
79  int x;
80  int y;
81  int demand;
82  int Etime;
83  int Ltime;
84  int Stime;
85  int Pindex;
86  int Dindex;
87 }customer_t;
88 
89 
90 
91 #if 0
92 static int conn(int *SPIcode)
93 {
94  int res = 0;
95 
96  *SPIcode = SPI_connect();
97 
98  if (*SPIcode != SPI_OK_CONNECT)
99  {
100  elog(ERROR, "vrppdtw: couldn't open a connection to SPI");
101  res = -1;
102  }
103 
104  return res;
105 }
106 
107 static int prepare_query(Portal *SPIportal, char* sql)
108 {
109  int res = 0;
110 
111  void* SPIplan = SPI_prepare(sql, 0, NULL);
112 
113  if (SPIplan == NULL)
114  {
115  elog(ERROR, "vrppdtw: couldn't create query plan via SPI");
116  res = -1;
117  }
118 
119  if ((*SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL)
120  {
121  elog(ERROR, "vrppdtw: SPI_cursor_open('%s') returns NULL", sql);
122  res = -1;
123  }
124 
125  return res;
126 }
127 #endif
128 
129 static int fetch_customer_columns(SPITupleTable *tuptable, customer_t *c , int vehicle_count , int capacity)
130 {
131  DBG("Customer Data");
132 
133  c->id = SPI_fnumber(SPI_tuptable->tupdesc, "id");
134  DBG(" id done ");
135  c->x = SPI_fnumber(SPI_tuptable->tupdesc, "x");
136  DBG("x done");
137  c->y = SPI_fnumber(SPI_tuptable->tupdesc, "y");
138  DBG("y done");
139  c->demand = SPI_fnumber(SPI_tuptable->tupdesc, "demand");
140  DBG("demand done");
141  c->Etime = SPI_fnumber(SPI_tuptable->tupdesc, "etime");
142  DBG("etime done");
143  c->Ltime = SPI_fnumber(SPI_tuptable->tupdesc, "ltime");
144  DBG("ltime done");
145  c->Stime = SPI_fnumber(SPI_tuptable->tupdesc, "stime");
146  DBG("stime done");
147  c->Pindex = SPI_fnumber(SPI_tuptable->tupdesc, "pindex");
148  DBG("pindex done");
149  c->Dindex = SPI_fnumber(SPI_tuptable->tupdesc, "dindex");
150  DBG("dindex done");
151  if (c->id == SPI_ERROR_NOATTRIBUTE ||
152  c->x == SPI_ERROR_NOATTRIBUTE ||
153  c->y == SPI_ERROR_NOATTRIBUTE ||
154  c->demand == SPI_ERROR_NOATTRIBUTE ||
155  c->Ltime == SPI_ERROR_NOATTRIBUTE ||
156  c->Stime == SPI_ERROR_NOATTRIBUTE ||
157  c->Pindex == SPI_ERROR_NOATTRIBUTE ||
158  c->Dindex == SPI_ERROR_NOATTRIBUTE ||
159  c->Etime == SPI_ERROR_NOATTRIBUTE)
160  {
161  elog(ERROR, "Error, query must return columns "
162  "'id', 'x','y','demand', 'Etime', 'Ltime', 'Stime', 'Pindex', and 'Dindex'");
163  return -1;
164  }
165 
166  DBG("Returned from here ");
167  return 0;
168 }
169 
170 
171 static void fetch_customer(HeapTuple *tuple, TupleDesc *tupdesc, customer_t *c_all, customer *c_single)
172 {
173  Datum binval;
174  bool isnull;
175  DBG("Hey baby in fetch_customer");
176 
177  binval = SPI_getbinval(*tuple, *tupdesc, c_all->id, &isnull);
178  DBG("fetching first thing");
179  if (isnull) elog(ERROR, "id contains a null value");
180  c_single->id = DatumGetInt32(binval);
181  DBG("id = %d", c_single->id);
182 
183 
184  DBG("fetching second thing");
185  binval = SPI_getbinval(*tuple, *tupdesc, c_all->x, &isnull);
186  if (isnull)
187  elog(ERROR, "x contains a null value");
188  c_single->x = DatumGetInt32(binval);
189 
190  binval = SPI_getbinval(*tuple, *tupdesc, c_all->y, &isnull);
191  if (isnull) elog(ERROR, "y contains a null value");
192  c_single->y = DatumGetInt32(binval);
193 
194 
195  binval = SPI_getbinval(*tuple, *tupdesc, c_all->demand, &isnull);
196  if (isnull) elog(ERROR, "demand contains a null value");
197  c_single->demand = DatumGetInt32(binval);
198 
199 
200  binval = SPI_getbinval(*tuple, *tupdesc, c_all->Etime, &isnull);
201  if (isnull) elog(ERROR, "Etime contains a null value");
202  c_single->Etime = DatumGetInt32(binval);
203 
204 
205  binval = SPI_getbinval(*tuple, *tupdesc, c_all->Ltime, &isnull);
206  if (isnull) elog(ERROR, "Ltime contains a null value");
207  c_single->Ltime = DatumGetInt32(binval);
208 
209 
210  binval = SPI_getbinval(*tuple, *tupdesc, c_all->Stime, &isnull);
211  if (isnull) elog(ERROR, "Stime contains a null value");
212  c_single->Stime = DatumGetInt32(binval);
213 
214 
215  binval = SPI_getbinval(*tuple, *tupdesc, c_all->Pindex, &isnull);
216  if (isnull) elog(ERROR, "pindex contains a null value");
217  c_single->Pindex = DatumGetInt32(binval);
218 
219  binval = SPI_getbinval(*tuple, *tupdesc, c_all->Dindex, &isnull);
220  if (isnull) elog(ERROR, "dindex contains a null value");
221  c_single->Dindex = DatumGetInt32(binval);
222 
223  return;
224 }
225 
226 
227 
228 
229 //Note:: edge_colums = total , //ly customer_t = total ....
230 
231 static int compute_shortest_path(char* sql, int vehicle_count, int capacity , path_element **results, int *length_results_struct)
232 {
233 
234  int SPIcode;
235  void *SPIplan;
236  Portal SPIportal;
237  bool moredata = TRUE;
238  int ntuples;
239  customer *customer_single=NULL;
240  int total_tuples = 0;
241  customer_t customer_all = {.id= -1, .x=-1, .y=-1 , .demand=-1 , .Etime=-1, .Ltime=-1 , .Stime=-1 , .Pindex=-1 , .Dindex=-1 }; // write this
242 
243  char *err_msg;
244  int ret = -1;
245  // register int z;
246 
247  DBG("start shortest_path\n");
248 
249  SPIcode = SPI_connect();
250  if (SPIcode != SPI_OK_CONNECT) {
251  elog(ERROR, "shortest_path: couldn't open a connection to SPI");
252  return -1;
253  }
254 
255  SPIplan = SPI_prepare(sql, 0, NULL);
256  if (SPIplan == NULL) {
257  elog(ERROR, "shortest_path: couldn't create query plan via SPI");
258  return -1;
259  }
260 
261  if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) {
262  elog(ERROR, "shortest_path: SPI_cursor_open('%s') returns NULL", sql);
263  return -1;
264  }
265 
266  while (moredata == TRUE) {
267  SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);
268 
269  DBG("Checking ");
270 
271  if (customer_all.id == -1) {
272  if (fetch_customer_columns(SPI_tuptable, &customer_all,vehicle_count, capacity) == -1)
273  {
274  return finish(SPIcode, ret);
275  }
276  DBG("Here I am ");
277  }
278 
279  ntuples = SPI_processed;
280  total_tuples += ntuples;
281  DBG("Calculated total_tuples ntuples=%d total_tuples =%d ", ntuples, total_tuples);
282 
283  if (customer_single==NULL)
284  customer_single = palloc(total_tuples * sizeof(customer));
285  else
286  customer_single = repalloc(customer_single, total_tuples * sizeof(customer));
287 
288 
289  DBG("Error here ");
290  if (customer_single == NULL) {
291  elog(ERROR, "Out of memory");
292  return finish(SPIcode, ret);
293  }
294 
295 
296 
297  if (ntuples > 0) {
298  DBG("Check here ");
299  int t;
300  SPITupleTable *tuptable = SPI_tuptable;
301  TupleDesc tupdesc = SPI_tuptable->tupdesc;
302 
303  for (t = 0; t < ntuples; t++) {
304  DBG("In for loop ");
305  HeapTuple tuple = tuptable->vals[t];
306  DBG("Manikanta ");
307  fetch_customer(&tuple, &tupdesc, &customer_all , &customer_single[total_tuples - ntuples + t]);
308  DBG("After Function call");
309  }
310  SPI_freetuptable(tuptable);
311  }
312  else {
313  moredata = FALSE;
314  }
315  }
316 
317  int k;
318  for(k=0;k<total_tuples;k++)
319  {
320  DBG("%d %d %d %d %d %d %d %d %d" , customer_single[k].id, customer_single[k].x , customer_single[k].y , customer_single[k].demand , customer_single[k].Etime ,customer_single[k].Ltime ,customer_single[k].Stime, customer_single[k].Pindex, customer_single[k].Dindex);
321  }
322 
323  DBG("Calling Solver Instance\n");
324 
325 
326  ret = Solver(customer_single, total_tuples, vehicle_count, capacity , &err_msg,results, length_results_struct);
327 
328  if (ret < -2) {
329  //elog(ERROR, "Error computing path: %s", err_msg);
330  ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED),
331  errmsg("Error computing path: %s", err_msg)));
332  }
333 
334 
335  DBG("*length_results_count = %i\n", *length_results_struct);
336 
337  DBG("ret = %i\n", ret);
338 
339 
340 
341 
342  int vb;
343  for(vb=1;vb<*length_results_struct;vb++)
344  {
345  DBG("results[%d].seq=%d ",vb, (*results)[vb].seq);
346  DBG("results[%d].rid=%d ",vb, (*results)[vb].rid);
347  DBG("results[%d].nid=%d \n",vb, (*results)[vb].nid);
348  }
349 
350  pfree(customer_single);
351  DBG("Working till here ");
352  return finish(SPIcode, ret);
353 
354 }
355 
356 
357 
358 PG_FUNCTION_INFO_V1(vrppdtw);
359  Datum
360 vrppdtw(PG_FUNCTION_ARGS)
361 {
362  FuncCallContext *funcctx;
363  int call_cntr;
364  int max_calls;
365  TupleDesc tuple_desc;
366  path_element *results = 0;
367 
368 
369  /* stuff done only on the first call of the function */
370 
371  if (SRF_IS_FIRSTCALL())
372 
373  {
374  MemoryContext oldcontext;
375  // int ret;
376  int length_results_struct = 0;
377 
378 
379 
380 
381  /* create a function context for cross-call persistence */
382 
383  funcctx = SRF_FIRSTCALL_INIT();
384 
385 
386 
387  /* switch to memory context appropriate for multiple function calls */
388 
389  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
390 
391 
392  results = (path_element *)palloc(sizeof(path_element)*((length_results_struct)+1));
393 
394  DBG("Calling compute_shortes_path");
395 
396 
397 
398  // ret =
399  compute_shortest_path(
400 
401  text2char(PG_GETARG_TEXT_P(0)), // customers sql
402 
403  PG_GETARG_INT32(1), // vehicles count
404 
405  PG_GETARG_INT32(2), // capacity count
406 
407  &results, &length_results_struct
408  );
409 
410  DBG("Back from solve_vrp, length_results: %d", length_results_struct);
411 
412  /* total number of tuples to be returned */
413  funcctx->max_calls = length_results_struct;
414  funcctx->user_fctx = results;
415 
416  /* Build a tuple descriptor for our result type */
417  if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
418  ereport(ERROR,
419  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
420  errmsg("function returning record called in context "
421  "that cannot accept type record")));
422 
423  funcctx->tuple_desc = BlessTupleDesc(tuple_desc);
424 
425  MemoryContextSwitchTo(oldcontext);
426  }
427 
428  /* stuff done on every call of the function */
429  funcctx = SRF_PERCALL_SETUP();
430 
431  call_cntr = funcctx->call_cntr;
432  max_calls = funcctx->max_calls;
433  tuple_desc = funcctx->tuple_desc;
434  results = (path_element *) funcctx->user_fctx;
435 
436  /* do when there is more left to send */
437  if (call_cntr < max_calls) {
438  HeapTuple tuple;
439  Datum result;
440  Datum *values;
441  char* nulls;
442 
443  DBG("Till hereee ");
444  values = palloc(4 * sizeof(Datum));
445  nulls = palloc(4 * sizeof(char));
446 
447  values[0] = Int32GetDatum(results[call_cntr].seq);
448  nulls[0] = ' ';
449  values[1] = Int32GetDatum(results[call_cntr].rid);
450  nulls[1] = ' ';
451  values[2] = Int32GetDatum(results[call_cntr].nid);
452  nulls[2] = ' ';
453  values[3] = Int32GetDatum(results[call_cntr].cost);
454  nulls[3] = ' ';
455  tuple = heap_formtuple(tuple_desc, values, nulls);
456 
457  /* make the tuple into a datum */
458  result = HeapTupleGetDatum(tuple);
459 
460  /* clean up (this is not really necessary) */
461  pfree(values);
462  pfree(nulls);
463 
464  SRF_RETURN_NEXT(funcctx, result);
465  }
466  /* do when there is no more left */
467  else {
468  DBG("Ending function\n");
469 
470  free(results);
471  DBG("Itinerary cleared\n");
472 
473 
474  SRF_RETURN_DONE(funcctx);
475  }
476 
477 
478 }