pgRouting  2.2
pgRouting extends the PostGIS / PostgreSQL geospatial database to provide geospatial routing functionality.
 All Classes Functions Variables Pages
VRP.c
1 /*PGR-GNU*****************************************************************
2 
3 Copyright (c) 2013 Khondoker Md. Razequl Islam
4 ziboncsedu@gmail.com
5 
6 ------
7 
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 
22 ********************************************************************PGR-GNU*/
23 
24 #include "VRP.h"
25 
26 #include "postgres.h"
27 #include "executor/spi.h"
28 #include "funcapi.h"
29 #include "catalog/pg_type.h"
30 #if PGSQL_VERSION > 92
31 #include "access/htup_details.h"
32 #endif
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <search.h>
37 
38 #include "string.h"
39 #include "math.h"
40 
41 #include "fmgr.h"
42 
43 
44 
45 #undef qsort
46 
47 //-------------------------------------------------------------------------
48 
49 /*
50  * Define this to have profiling enabled
51  */
52 //#define PROFILE
53 
54 #ifdef PROFILE
55 #include <sys/time.h>
56 
57 struct timeval prof_astar, prof_store, prof_extract, prof_total;
58 long proftime[5];
59 long profipts1, profipts2, profopts;
60 
61 #define profstart(x) do { gettimeofday(&x, NULL); } while (0);
62 #define profstop(n, x) do { struct timeval _profstop; \
63  long _proftime; \
64  gettimeofday(&_profstop, NULL); \
65  _proftime = ( _profstop.tv_sec*1000000+_profstop.tv_usec) - \
66  ( x.tv_sec*1000000+x.tv_usec); \
67  elog(NOTICE, \
68  "PRF(%s) %lu (%f ms)", \
69  (n), \
70  _proftime, _proftime / 1000.0); \
71  } while (0);
72 
73 #else
74 
75 #define profstart(x) do { } while (0);
76 #define profstop(n, x) do { } while (0);
77 
78 #endif // PROFILE
79 
80 
81 // ------------------------------------------------------------------------
82 
83 Datum vrp(PG_FUNCTION_ARGS);
84 
85 #undef DEBUG
86 //#define DEBUG 1
87 #include "../../common/src/debug_macro.h"
88 
89 
90 // The number of tuples to fetch from the SPI cursor at each iteration
91 #define TUPLIMIT 1000
92 
93 #ifndef PG_MODULE_MAGIC
94 PG_MODULE_MAGIC;
95 #endif
96 
97 typedef struct vehicle_columns
98 {
99  int vehicle_id;
100  int capacity;
101 
103 
104 typedef struct order_columns
105 {
106  int id;
107  int order_unit;
108  int open_time;
109  int close_time;
110  int service_time;
111 
112  int x;
113  int y;
115 
116 typedef struct distance_columns
117 {
118  int src_id;
119  int dest_id;
120  int cost;
121  int distance;
122  int traveltime;
124 
125 
126 //float DISTANCE[MAX_TOWNS][MAX_TOWNS];
127 //float x[MAX_TOWNS],y[MAX_TOWNS];
128 
129 static char *
130 text2char(text *in)
131 {
132  char *out = (char*)palloc(VARSIZE(in));
133 
134  memcpy(out, VARDATA(in), VARSIZE(in) - VARHDRSZ);
135  out[VARSIZE(in) - VARHDRSZ] = '\0';
136  return out;
137 }
138 
139 static int
140 finish(int *code)
141 {
142  *code = SPI_finish();
143  if (*code != SPI_OK_FINISH )
144  {
145  elog(ERROR,"couldn't disconnect from SPI");
146  return -1 ;
147  }
148  return 0;
149 }
150 
151 
152 
153 static int
154 fetch_distance_columns(SPITupleTable *tuptable, distance_columns_t *distance_columns)
155 {
156  PGR_DBG("Fetching distance");
157 
158  distance_columns->src_id = SPI_fnumber(SPI_tuptable->tupdesc, "src_id");
159  distance_columns->dest_id = SPI_fnumber(SPI_tuptable->tupdesc, "dest_id");
160  distance_columns->cost = SPI_fnumber(SPI_tuptable->tupdesc, "cost");
161  distance_columns->distance = SPI_fnumber(SPI_tuptable->tupdesc, "distance");
162  distance_columns->traveltime = SPI_fnumber(SPI_tuptable->tupdesc, "traveltime");
163  if (distance_columns->src_id == SPI_ERROR_NOATTRIBUTE ||
164  distance_columns->dest_id == SPI_ERROR_NOATTRIBUTE ||
165  distance_columns->cost == SPI_ERROR_NOATTRIBUTE ||
166  distance_columns->distance == SPI_ERROR_NOATTRIBUTE ||
167  distance_columns->traveltime == SPI_ERROR_NOATTRIBUTE)
168  {
169  elog(ERROR, "Error, query must return columns "
170  "'src_id', 'dest_id', 'cost', 'distance' and 'traveltime'");
171  return -1;
172  }
173 
174  return 0;
175 }
176 
177 
178 static void
179 fetch_distance(HeapTuple *tuple, TupleDesc *tupdesc,
180  distance_columns_t *distance_columns, vrp_cost_element_t *dist, size_t t)
181 {
182  Datum binval;
183  bool isnull;
184 
185  PGR_DBG("fetch_distance: src_id col:%i", distance_columns->src_id);
186 
187  binval = SPI_getbinval(*tuple, *tupdesc, distance_columns->src_id, &isnull);
188 
189  PGR_DBG("back from SPI_getbinval for src_id");
190  PGR_DBG("binval=%i", binval);
191 
192  if (isnull)
193  elog(ERROR, "src_id contains a null value");
194 
195  dist->src_id = DatumGetInt32(binval);
196 
197  PGR_DBG("back from DatumGetInt32");
198  PGR_DBG("src_id=%i", dist->src_id);
199 
200  binval = SPI_getbinval(*tuple, *tupdesc, distance_columns->dest_id, &isnull);
201  if (isnull)
202  elog(ERROR, "dest_id contains a null value");
203 
204  dist->dest_id = DatumGetInt32(binval);
205 
206  PGR_DBG("dest_id=%i", dist->dest_id);
207 
208  binval = SPI_getbinval(*tuple, *tupdesc, distance_columns->cost, &isnull);
209 
210  if (isnull)
211  elog(ERROR, "cost contains a null value");
212 
213  dist->cost = DatumGetFloat8(binval);
214 
215  PGR_DBG("cost=%lf", dist->cost);
216 
217  binval = SPI_getbinval(*tuple, *tupdesc, distance_columns->distance, &isnull);
218  if (isnull)
219  elog(ERROR, "distance contains a null value");
220 
221  dist->distance = DatumGetFloat8(binval);
222 
223  PGR_DBG("distance=%lf", dist->distance);
224 
225  binval = SPI_getbinval(*tuple, *tupdesc, distance_columns->traveltime, &isnull);
226 
227  if (isnull)
228  elog(ERROR, "traveltime contains a null value");
229 
230  dist->traveltime = DatumGetFloat8(binval);
231 
232  PGR_DBG("traveltime=%lf", dist->traveltime);
233 
234  //PGR_DBG("dist[%i][%i] = %f\n", from_point, to_point, value);
235 
236 
237  //PGR_DBG("dist[%i(%i:%i)][%i(%i:%i)] = %f\n", from, from_order, from_point, to, to_order, to_point, *(dist + (num_rows * from) + to));
238 
239 }
240 
241 static int
242 fetch_order_columns(SPITupleTable *tuptable, order_columns_t *order_columns)
243 {
244  PGR_DBG("Fetching order");
245 
246  //order_columns->id = SPI_fnumber(SPI_tuptable->tupdesc, "id");
247  order_columns->id = SPI_fnumber(SPI_tuptable->tupdesc, "id");
248  order_columns->order_unit = SPI_fnumber(SPI_tuptable->tupdesc, "order_unit");
249  order_columns->open_time = SPI_fnumber(SPI_tuptable->tupdesc, "open_time");
250  order_columns->close_time = SPI_fnumber(SPI_tuptable->tupdesc, "close_time");
251  order_columns->service_time = SPI_fnumber(SPI_tuptable->tupdesc, "service_time");
252  order_columns->x = SPI_fnumber(SPI_tuptable->tupdesc, "x");
253  order_columns->y = SPI_fnumber(SPI_tuptable->tupdesc, "y");
254  if (//order_columns->id == SPI_ERROR_NOATTRIBUTE ||
255  order_columns->id == SPI_ERROR_NOATTRIBUTE ||
256  order_columns->open_time == SPI_ERROR_NOATTRIBUTE ||
257  order_columns->order_unit == SPI_ERROR_NOATTRIBUTE ||
258  order_columns->close_time == SPI_ERROR_NOATTRIBUTE ||
259  order_columns->service_time == SPI_ERROR_NOATTRIBUTE ||
260  order_columns->x == SPI_ERROR_NOATTRIBUTE ||
261  order_columns->y == SPI_ERROR_NOATTRIBUTE
262  )
263  {
264  // elog(ERROR, "Error, query must return columns "
265  // "'id', 'order_id', 'pu_time', 'do_time', 'pu_time_window', 'do_time_window', 'from_x', 'to_x', 'from_y', 'to_y' and 'size'");
266  elog(ERROR, "Error, query must return columns "
267  //"'id',
268  "'id', 'order_unit', 'open_time', 'close_time', 'service_time', 'x', 'y'");
269  return -1;
270  }
271 
272  return 0;
273 }
274 
275 static void
276 fetch_order(HeapTuple *tuple, TupleDesc *tupdesc,
277  order_columns_t *order_columns, vrp_orders_t *order, size_t t)
278 {
279  Datum binval;
280  bool isnull;
281 
282  PGR_DBG("inside fetch_order\n");
283 
284  //binval = SPI_getbinval(*tuple, *tupdesc, order_columns->id, &isnull);
285  //
286  // PGR_DBG("got binval\n");
287  //
288  //if (isnull)
289  // elog(ERROR, "id contains a null value");
290  //
291  //order->id = DatumGetInt32(binval);
292  order->id = (int)t + 1;
293 
294  PGR_DBG("id = %i\n", order->id);
295 
296  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->id, &isnull);
297  if (isnull)
298  elog(ERROR, "order_id contains a null value");
299 
300  order->id = DatumGetInt32(binval);
301 
302  PGR_DBG("order_id = %i\n", order->id);
303 
304 
305  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->order_unit, &isnull);
306  if (isnull)
307  elog(ERROR, "order_unit contains a null value");
308 
309  order->order_unit = DatumGetInt32(binval);
310 
311  PGR_DBG("order_unit = %i\n", order->order_unit);
312 
313  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->open_time, &isnull);
314  if (isnull)
315  elog(ERROR, "open_time contains a null value");
316 
317  order->open_time = DatumGetInt32(binval);
318 
319  PGR_DBG("open_time = %i\n", order->open_time);
320 
321  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->close_time, &isnull);
322  if (isnull)
323  elog(ERROR, "close_time contains a null value");
324 
325  order->close_time = DatumGetInt32(binval);
326 
327  PGR_DBG("close_time = %d\n", order->close_time);
328 
329  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->service_time, &isnull);
330  if (isnull)
331  elog(ERROR, "service_time contains a null value");
332 
333  order->service_time = DatumGetInt32(binval);
334 
335  PGR_DBG("service_time = %d\n", order->service_time);
336 
337  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->x, &isnull);
338  if (isnull)
339  elog(ERROR, "x contains a null value");
340 
341  order->x = DatumGetFloat8(binval);
342 
343  PGR_DBG("x = %f\n", order->x);
344 
345  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->y, &isnull);
346  if (isnull)
347  elog(ERROR, "y contains a null value");
348 
349  order->y = DatumGetFloat8(binval);
350 
351  PGR_DBG("doUT = %f\n", order->y);
352 
353 }
354 
355 static int
356 fetch_vehicle_columns(SPITupleTable *tuptable, vehicle_columns_t *vehicle_columns)
357 {
358  PGR_DBG("Fetching order");
359 
360  vehicle_columns->vehicle_id = SPI_fnumber(SPI_tuptable->tupdesc, "vehicle_id");
361  vehicle_columns->capacity = SPI_fnumber(SPI_tuptable->tupdesc, "capacity");
362 
363  if (vehicle_columns->vehicle_id == SPI_ERROR_NOATTRIBUTE ||
364  vehicle_columns->capacity == SPI_ERROR_NOATTRIBUTE
365  )
366  {
367  elog(ERROR, "Error, query must return columns "
368  "'id' and 'capacity'");
369  return -1;
370  }
371 
372  return 0;
373 }
374 
375 static void
376 fetch_vehicle(HeapTuple *tuple, TupleDesc *tupdesc,
377  vehicle_columns_t *vehicle_columns, vrp_vehicles_t *vehicle, size_t t)
378 {
379  Datum binval;
380  bool isnull;
381 
382  PGR_DBG("inside fetch_vehicle\n");
383 
384  //binval = SPI_getbinval(*tuple, *tupdesc, vehicle_columns->id, &isnull);
385  //PGR_DBG("Got id\n");
386  //
387  //if (isnull)
388  // elog(ERROR, "id contains a null value");
389  //
390  //vehicle->id = DatumGetInt32(binval);
391 
392 
393  binval = SPI_getbinval(*tuple, *tupdesc, vehicle_columns->vehicle_id, &isnull);
394  PGR_DBG("Got vehicle_id\n");
395 
396  if (isnull)
397  elog(ERROR, "vehicle_id contains a null value");
398 
399  vehicle->id = DatumGetInt32(binval);
400 
401  PGR_DBG("vehicle_id = %i\n", vehicle->id);
402 
403  binval = SPI_getbinval(*tuple, *tupdesc, vehicle_columns->capacity, &isnull);
404  if (isnull)
405  elog(ERROR, "capacity contains a null value");
406 
407  vehicle->capacity = DatumGetInt32(binval);
408 
409  PGR_DBG("capacity = %f\n", vehicle->capacity);
410 
411 }
412 
413 static int conn(int *SPIcode)
414 {
415  int res = 0;
416 
417  *SPIcode = SPI_connect();
418 
419  if (*SPIcode != SPI_OK_CONNECT)
420  {
421  elog(ERROR, "vrp: couldn't open a connection to SPI");
422  res = -1;
423  }
424 
425  return res;
426 }
427 
428 static int prepare_query(Portal *SPIportal, char* sql)
429 {
430  int res = 0;
431 
432  void* SPIplan = SPI_prepare(sql, 0, NULL);
433 
434  if (SPIplan == NULL)
435  {
436  elog(ERROR, "vrp: couldn't create query plan via SPI");
437  res = -1;
438  }
439 
440  if ((*SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL)
441  {
442  elog(ERROR, "vrp: SPI_cursor_open('%s') returns NULL", sql);
443  res = -1;
444  }
445 
446  return res;
447 }
448 
449 static int solve_vrp(char* orders_sql, char* vehicles_sql,
450  char* dist_sql,
451  int depot,
452  vrp_result_element_t** path, size_t *path_count)
453 {
454  int SPIcode;
455 
456  Portal SPIportal_o;
457  Portal SPIportal_v;
458  Portal SPIportal_d;
459  // Portal SPIportal_p;
460 
461  bool moredata = TRUE;
462  size_t ntuples;
463 
464  size_t order_num;
465  size_t vehicle_num;
466  size_t dist_num;
467 
468  vrp_vehicles_t *vehicles=NULL;
469  vehicle_columns_t vehicle_columns = {.vehicle_id = -1, .capacity = -1};
470 
471  vrp_orders_t *orders=NULL;
472  order_columns_t order_columns = {.id = -1, .order_unit = -1, .open_time = -1, .close_time = -1, .service_time = -1, .x = -1, .y = -1};
473 
474  vrp_cost_element_t *costs=NULL;
475  distance_columns_t distance_columns = {.src_id = -1, .dest_id = -1, .cost = -1, .distance = -1, .traveltime = -1};
476 
477  char *err_msg = NULL;
478  int ret = -1;
479 
480  // int z = 0;
481 
482  // int tt, cc;
483  // double dx, dy;
484  // float fit=0.0;
485 
486  int prep = -1, con = -1;
487 
488  //int total_tuples = 0;
489  order_num = 0;
490  vehicle_num = 0;
491 
492  PGR_DBG("start solve_vrp\n");
493 
494  //vrp_orders_t depot_ord = {id:0, order_id:depot, from:depot_point, to:depot_point};
495  //orders = palloc(1 * sizeof(vrp_orders_t));
496  //orders[0] = depot_ord;
497 
498  con = conn(&SPIcode);
499 
500  if (con < 0)
501  return ret;
502 
503 
504  // Fetching orders
505 
506  PGR_DBG("calling prepare_query for orders_sql");
507 
508  prep = prepare_query(&SPIportal_o, orders_sql);
509 
510  if (prep < 0)
511  return ret;
512 
513  PGR_DBG("Query: %s\n",orders_sql);
514  PGR_DBG("Query executed\n");
515 
516  PGR_DBG("Orders before: %i\n", order_num);
517 
518  while (moredata == TRUE)
519  {
520  SPI_cursor_fetch(SPIportal_o, TRUE, TUPLIMIT);
521 
522  PGR_DBG("cursor fetched\n");
523 
524  if (order_columns.id == -1)
525  {
526  if (fetch_order_columns(SPI_tuptable, &order_columns) == -1)
527  return finish(&SPIcode);
528  }
529 
530  ntuples = SPI_processed;
531 
532  order_num += ntuples;
533 
534  PGR_DBG("Tuples: %i\n", order_num);
535 
536  if (!orders)
537  orders = palloc(order_num * sizeof(vrp_orders_t));
538  else
539  orders = repalloc(orders, (order_num + 1) * sizeof(vrp_orders_t));
540 
541  if (orders == NULL)
542  {
543  elog(ERROR, "Out of memory");
544  return finish(&SPIcode);
545  }
546 
547  if (ntuples > 0)
548  {
549  SPITupleTable *tuptable = SPI_tuptable;
550  TupleDesc tupdesc = SPI_tuptable->tupdesc;
551 
552  PGR_DBG("Got tuple desc\n");
553  size_t t;
554  for (t = 0; t < ntuples; t++)
555  {
556  HeapTuple tuple = tuptable->vals[t];
557  //PGR_DBG("Before order fetched [%i]\n", order_num - ntuples + t);
558  fetch_order(&tuple, &tupdesc, &order_columns,
559  &orders[order_num - ntuples + t], t);
560 
561  //&orders[t+1], t);
562  PGR_DBG("Order fetched\n");
563  }
564 
565  SPI_freetuptable(tuptable);
566  }
567  else
568  {
569  moredata = FALSE;
570  }
571  }// end of fetching orders
572  //finish(&SPIcode_o);
573 /*
574  int o;
575  for(o=0; o<order_num+1;++o)
576  {
577  elog(NOTICE, "ORDERS[%i] = {id=%i, open=%i, close=%i, service=%i}", o, orders[o].id, orders[o].open_time, orders[o].close_time, orders[o].service_time);
578  }
579 */
580  PGR_DBG ("order_num = %i", order_num);
581 
582  //qsort (orders, order_num+1, sizeof (vrp_orders_t), order_cmp);
583 
584 
585  // Fetching vehicles
586 
587  moredata = TRUE;
588  prep = prepare_query(&SPIportal_v, vehicles_sql);
589 
590  if (prep < 0)
591  return ret;
592 
593  PGR_DBG("Query: %s\n",vehicles_sql);
594  PGR_DBG("Query executed\n");
595 
596 
597  while (moredata == TRUE)
598  {
599  SPI_cursor_fetch(SPIportal_v, TRUE, TUPLIMIT);
600 
601  if (vehicle_columns.vehicle_id == -1)
602  {
603  if (fetch_vehicle_columns(SPI_tuptable, &vehicle_columns) == -1)
604  return finish(&SPIcode);
605  }
606 
607 
608  ntuples = SPI_processed;
609 
610  vehicle_num += ntuples;
611 
612  PGR_DBG("Tuples: %i\n", vehicle_num);
613 
614  if (!vehicles)
615  vehicles = palloc(vehicle_num * sizeof(vrp_vehicles_t));
616  else
617  vehicles = repalloc(vehicles, vehicle_num * sizeof(vrp_vehicles_t));
618 
619  if (vehicles == NULL)
620  {
621  elog(ERROR, "Out of memory");
622  return finish(&SPIcode);
623  }
624 
625  if (ntuples > 0)
626  {
627  SPITupleTable *tuptable = SPI_tuptable;
628  TupleDesc tupdesc = SPI_tuptable->tupdesc;
629 
630  PGR_DBG("Got tuple desc\n");
631 
632  size_t t;
633  for (t = 0; t < ntuples; t++)
634  {
635  HeapTuple tuple = tuptable->vals[t];
636  PGR_DBG("Before vehicle fetched\n");
637  fetch_vehicle(&tuple, &tupdesc, &vehicle_columns,
638  &vehicles[vehicle_num - ntuples + t], t);
639  PGR_DBG("Vehicle fetched\n");
640  }
641 
642  SPI_freetuptable(tuptable);
643  }
644  else
645  {
646  moredata = FALSE;
647  }
648  }// end of fetching vehicles
649  //finish(&SPIcode_v);
650 
651  //double dist[order_num*2+1][order_num*2+1];
652 
653  // Fetching distances
654 
655  dist_num = 0;
656  moredata = TRUE;
657  prep = prepare_query(&SPIportal_d, dist_sql);
658 
659  if (prep < 0)
660  return ret;
661 
662  PGR_DBG("Query: %s\n",dist_sql);
663  PGR_DBG("Query executed\n");
664 
665  while (moredata == TRUE)
666  {
667  SPI_cursor_fetch(SPIportal_d, TRUE, TUPLIMIT);
668 
669  if (distance_columns.src_id == -1)
670  {
671  if (fetch_distance_columns(SPI_tuptable, &distance_columns) == -1)
672  return finish(&SPIcode);
673  }
674 
675  ntuples = SPI_processed;
676  dist_num += ntuples;
677 
678  PGR_DBG("Tuples: %i\n", vehicle_num);
679 
680  if (!costs)
681  costs = palloc(dist_num * sizeof(vrp_cost_element_t));
682  else
683  costs = repalloc(costs, dist_num * sizeof(vrp_cost_element_t));
684 
685  if (costs == NULL)
686  {
687  elog(ERROR, "Out of memory");
688  return finish(&SPIcode);
689  }
690 
691  if (ntuples > 0)
692  {
693  SPITupleTable *tuptable = SPI_tuptable;
694  TupleDesc tupdesc = SPI_tuptable->tupdesc;
695 
696  PGR_DBG("Got tuple desc\n");
697  size_t t;
698  for (t = 0; t < ntuples; t++)
699  {
700  HeapTuple tuple = tuptable->vals[t];
701  PGR_DBG("Before distance fetched\n");
702  fetch_distance(&tuple, &tupdesc, &distance_columns,
703  &costs[dist_num - ntuples + t], t);
704  PGR_DBG("Distance fetched\n");
705  }
706 
707  SPI_freetuptable(tuptable);
708  }
709  else
710  {
711  moredata = FALSE;
712  }
713  }// end of fetching distances
714 
715 
716  PGR_DBG("Calling vrp\n");
717 
718  profstop("extract", prof_extract);
719  profstart(prof_vrp);
720 
721  PGR_DBG("Total orders: %i\n", order_num);
722  PGR_DBG("Total vehicles: %i\n", vehicle_num);
723 
724 
725  //qsort (orders, order_num+1, sizeof (vrp_orders_t), order_cmp_asc);
726 
727 
728 #ifdef DEBUG
729  int o;
730  for(o=0; o<order_num+1;++o)
731  {
732  PGR_DBG("ORDERS[%i] = {id=%i, open=%i, close=%i, service=%i}", o, orders[o].id, orders[o].open_time, orders[o].close_time, orders[o].service_time);
733  }
734 #endif
735 
736 
737 
738  //itinerary = (vrp_result_element_t *)palloc(sizeof(vrp_result_element_t)*(order_num*2-1)*vehicle_num);
739 
740  PGR_DBG("Calling vrp solver\n");
741  //elog(NOTICE, "Calling find_vrp_solution: vehicles: %i, orders: %i, dists: %i, depot: %i", vehicle_num, order_num, dist_num, depot);
742 
743  ret = find_vrp_solution(vehicles, vehicle_num,
744  orders, order_num,
745  costs, dist_num,
746  depot,
747  path, path_count, &err_msg);
748 
749  //ret = -1;
750  //elog(NOTICE, "vrp solved! ret: %d, path_count: %d", ret, *path_count);
751  // int pp;
752 /*
753  for(pp = 0; pp < *path_count; pp++)
754  {
755  elog(NOTICE, "Row: %d: %d %d %d %d %d", pp, (*path)[pp].order_id, (*path)[pp].order_pos, (*path)[pp].vehicle_id, (*path)[pp].arrival_time, (*path)[pp].depart_time);
756  }
757 */
758  PGR_DBG("vrp solved! ret: %d, path_count: %d", ret, path_count);
759  //PGR_DBG("Score: %f\n", fit);
760 
761  profstop("vrp", prof_vrp);
762  profstart(prof_store);
763 
764  PGR_DBG("Profile changed and ret is %i", ret);
765 
766  if (ret < 0)
767  {
768  //elog(ERROR, "Error computing path: %s", err_msg);
769  ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), errmsg("Error computing path: %s", err_msg)));
770  }
771 
772  //pfree(vehicles);
773  //pfree(orders);
774  return finish(&SPIcode);
775 }
776 
777 PG_FUNCTION_INFO_V1(vrp);
778 Datum
779 vrp(PG_FUNCTION_ARGS)
780 {
781  FuncCallContext *funcctx;
782  uint32_t call_cntr;
783  uint32_t max_calls;
784  TupleDesc tuple_desc;
785  vrp_result_element_t *path;
786 
787  /* stuff done only on the first call of the function */
788  if (SRF_IS_FIRSTCALL())
789  {
790  MemoryContext oldcontext;
791  //int path_count;
792  // int ret=-1;
793  size_t path_count = 0;
794 
795  // XXX profiling messages are not thread safe
796  profstart(prof_total);
797  profstart(prof_extract);
798 
799  /* create a function context for cross-call persistence */
800  funcctx = SRF_FIRSTCALL_INIT();
801 
802  /* switch to memory context appropriate for multiple function calls */
803  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
804 
805 
806  //path = (vrp_result_element_t *)palloc(sizeof(vrp_result_element_t)*(MAX_ORDERS-1)*2*MAX_VEHICLES);
807 
808 
809  PGR_DBG("Calling solve_vrp ...");
810 
811  // ret =
812  solve_vrp(//text2char(PG_GETARG_TEXT_P(0)), // points sql
813  text2char(PG_GETARG_TEXT_P(0)), // orders sql
814  text2char(PG_GETARG_TEXT_P(1)), // vehicles sql
815  text2char(PG_GETARG_TEXT_P(2)), // distances query
816  PG_GETARG_INT32(3), // depot id
817  &path, &path_count);
818 
819  PGR_DBG("Back from solve_vrp, path_count:%d", path_count);
820  //elog(NOTICE, "Back from solve_vrp, path_count:%d", path_count);
821 
822  /* total number of tuples to be returned */
823  //PGR_DBG("Counting tuples number\n");
824 
825  funcctx->max_calls = (uint32_t)path_count;
826 
827  funcctx->user_fctx = path;
828 
829  /* Build a tuple descriptor for our result type */
830  if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
831  ereport(ERROR,
832  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
833  errmsg("function returning record called in context "
834  "that cannot accept type record")));
835 
836  funcctx->tuple_desc = BlessTupleDesc(tuple_desc);
837 
838  /*
839  * generate attribute metadata needed later to produce tuples from raw
840  * C strings
841  */
842  //attinmeta = TupleDescGetAttInMetadata(tuple_desc);
843  //funcctx->attinmeta = attinmeta;
844 
845  MemoryContextSwitchTo(oldcontext);
846  //elog(NOTICE, "table formed");
847  }
848 
849  /* stuff done on every call of the function */
850  funcctx = SRF_PERCALL_SETUP();
851 
852  call_cntr = funcctx->call_cntr;
853  max_calls = funcctx->max_calls;
854  tuple_desc = funcctx->tuple_desc;
855 
856  path = (vrp_result_element_t *)funcctx->user_fctx;
857 
858  //elog(NOTICE, "Point 1");
859  //PGR_DBG("Trying to allocate some memory\n");
860  //PGR_DBG("call_cntr = %i, max_calls = %i\n", call_cntr, max_calls);
861 
862  if (call_cntr < max_calls) /* do when there is more left to send */
863  {
864  HeapTuple tuple;
865  Datum result;
866  Datum *values;
867  char* nulls;
868 
869  values = palloc(5 * sizeof(Datum));
870  nulls = palloc(5 * sizeof(char));
871 
872  values[0] = Int32GetDatum(path[call_cntr].order_id); // order id
873  nulls[0] = ' ';
874  values[1] = Int32GetDatum(path[call_cntr].order_pos); // order pos
875  nulls[1] = ' ';
876  values[2] = Int32GetDatum(path[call_cntr].vehicle_id); // vehicle id
877  nulls[2] = ' ';
878  values[3] = Int32GetDatum(path[call_cntr].arrival_time); // arrival time
879  nulls[3] = ' ';
880  //values[4] = TimeTzADTPGetDatum(&path[call_cntr].time);
881  values[4] = Int32GetDatum(path[call_cntr].depart_time); // departure time
882  nulls[4] = ' ';
883 
884  // PGR_DBG("Heap making\n");
885  //elog(NOTICE,"Result %d %d %d", call_cntr, path[call_cntr].order_id, max_calls);
886  tuple = heap_formtuple(tuple_desc, values, nulls);
887 
888  //PGR_DBG("Datum making\n");
889 
890  /* make the tuple into a datum */
891  result = HeapTupleGetDatum(tuple);
892 
893  //PGR_DBG("Trying to free some memory\n");
894 
895  /* clean up */
896  pfree(values);
897  pfree(nulls);
898 
899 
900  SRF_RETURN_NEXT(funcctx, result);
901  }
902  else /* do when there is no more left */
903  {
904 
905  PGR_DBG("Ending function\n");
906  profstop("store", prof_store);
907  profstop("total", prof_total);
908  PGR_DBG("Profiles stopped\n");
909 
910  free(path);
911 
912  PGR_DBG("Itinerary cleared\n");
913 
914  SRF_RETURN_DONE(funcctx);
915  }
916 }
Definition: VRP.h:38
Definition: pdp.hpp:31