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