PGROUTING  2.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
trsp.c
Go to the documentation of this file.
1 #include "postgres.h"
2 #include "executor/spi.h"
3 #include "funcapi.h"
4 #include "catalog/pg_type.h"
5 #if PGSQL_VERSION > 92
6 #include "access/htup_details.h"
7 #endif
8 
9 #include "fmgr.h"
10 #include "trsp.h"
11 
12 PGDLLEXPORT Datum turn_restrict_shortest_path_vertex(PG_FUNCTION_ARGS);
13 PGDLLEXPORT Datum turn_restrict_shortest_path_edge(PG_FUNCTION_ARGS);
14 
15 #undef DEBUG
16 //#define DEBUG 1
17 
18 #ifdef DEBUG
19 #define DBG(format, arg...) \
20  elog(NOTICE, format , ## arg)
21 #else
22 #define DBG(format,...) do { ; } while (0)
23 #endif
24 
25 // The number of tuples to fetch from the SPI cursor at each iteration
26 #define TUPLIMIT 1000
27 
28 //#ifdef PG_MODULE_MAGIC
29 //PG_MODULE_MAGIC;
30 //#endif
31 
32 typedef struct edge_columns
33 {
34  int id;
35  int source;
36  int target;
37  int cost;
40 
41 typedef struct restrict_columns
42 {
43  int target_id;
44  int via_path;
45  int to_cost;
47 
48 
49 
50 static char *
51 text2char(text *in)
52 {
53  char *out = palloc(VARSIZE(in));
54 
55  memcpy(out, VARDATA(in), VARSIZE(in) - VARHDRSZ);
56  out[VARSIZE(in) - VARHDRSZ] = '\0';
57  return out;
58 }
59 
60 static int
61 finish(int code, int ret)
62 {
63  DBG("In finish, trying to disconnect from spi %d",ret);
64  code = SPI_finish();
65  if (code != SPI_OK_FINISH )
66  {
67  elog(ERROR,"couldn't disconnect from SPI");
68  return -1 ;
69  }
70  return ret;
71 }
72 
73 /*
74  * This function fetches the resturction columns from an SPITupleTable..
75  *
76 */
77 static int
78 fetch_restrict_columns(SPITupleTable *tuptable,
80 {
81  restrict_columns->target_id = SPI_fnumber(SPI_tuptable->tupdesc, "target_id");
82  restrict_columns->via_path = SPI_fnumber(SPI_tuptable->tupdesc, "via_path");
83  restrict_columns->to_cost = SPI_fnumber(SPI_tuptable->tupdesc, "to_cost");
84  if (restrict_columns->target_id == SPI_ERROR_NOATTRIBUTE ||
85  restrict_columns->via_path == SPI_ERROR_NOATTRIBUTE ||
86  restrict_columns->to_cost == SPI_ERROR_NOATTRIBUTE) {
87  elog(ERROR, "Error, restriction query must return columns "
88  "'target_id', 'via_path' and 'to_cost'");
89  return -1;
90  }
91 
92  if (SPI_gettypeid(SPI_tuptable->tupdesc, restrict_columns->target_id) != INT4OID ||
93  SPI_gettypeid(SPI_tuptable->tupdesc, restrict_columns->via_path) != TEXTOID ||
94  SPI_gettypeid(SPI_tuptable->tupdesc, restrict_columns->to_cost) != FLOAT8OID) {
95  elog(ERROR, "Error, restriction columns 'target_id' must be of type int4, 'via_path' must be of type text, 'to_cost' must be of type float8");
96  return -1;
97  }
98 
99  return 0;
100 }
101 
102 /*
103  * This function fetches the edge columns from the SPITupleTable.
104  *
105 */
106 static int
107 fetch_edge_columns(SPITupleTable *tuptable, edge_columns_t *edge_columns,
108  bool has_reverse_cost)
109 {
110  edge_columns->id = SPI_fnumber(SPI_tuptable->tupdesc, "id");
111  edge_columns->source = SPI_fnumber(SPI_tuptable->tupdesc, "source");
112  edge_columns->target = SPI_fnumber(SPI_tuptable->tupdesc, "target");
113  edge_columns->cost = SPI_fnumber(SPI_tuptable->tupdesc, "cost");
114  if (edge_columns->id == SPI_ERROR_NOATTRIBUTE ||
115  edge_columns->source == SPI_ERROR_NOATTRIBUTE ||
116  edge_columns->target == SPI_ERROR_NOATTRIBUTE ||
117  edge_columns->cost == SPI_ERROR_NOATTRIBUTE)
118  {
119  elog(ERROR, "Error, query must return columns "
120  "'id', 'source', 'target' and 'cost'");
121  return -1;
122  }
123 
124  if (SPI_gettypeid(SPI_tuptable->tupdesc, edge_columns->source) != INT4OID ||
125  SPI_gettypeid(SPI_tuptable->tupdesc, edge_columns->target) != INT4OID ||
126  SPI_gettypeid(SPI_tuptable->tupdesc, edge_columns->cost) != FLOAT8OID)
127  {
128  elog(ERROR, "Error, columns 'source', 'target' must be of type int4, 'cost' must be of type float8");
129  return -1;
130  }
131 
132  DBG("columns: id %i source %i target %i cost %i",
133  edge_columns->id, edge_columns->source,
134  edge_columns->target, edge_columns->cost);
135 
136  if (has_reverse_cost)
137  {
138  edge_columns->reverse_cost = SPI_fnumber(SPI_tuptable->tupdesc,
139  "reverse_cost");
140 
141  if (edge_columns->reverse_cost == SPI_ERROR_NOATTRIBUTE)
142  {
143  elog(ERROR, "Error, reverse_cost is used, but query did't return "
144  "'reverse_cost' column");
145  return -1;
146  }
147 
148  if (SPI_gettypeid(SPI_tuptable->tupdesc, edge_columns->reverse_cost)
149  != FLOAT8OID)
150  {
151  elog(ERROR, "Error, columns 'reverse_cost' must be of type float8");
152  return -1;
153  }
154 
155  DBG("columns: reverse_cost cost %i", edge_columns->reverse_cost);
156  }
157 
158  return 0;
159 }
160 
161 /*
162  * To fetch a edge from Tuple.
163  *
164  */
165 
166 static void
167 fetch_edge(HeapTuple *tuple, TupleDesc *tupdesc,
168  edge_columns_t *edge_columns, edge_t *target_edge)
169 {
170  Datum binval;
171  bool isnull;
172 
173  binval = SPI_getbinval(*tuple, *tupdesc, edge_columns->id, &isnull);
174  if (isnull)
175  elog(ERROR, "id contains a null value");
176  target_edge->id = DatumGetInt32(binval);
177 
178  binval = SPI_getbinval(*tuple, *tupdesc, edge_columns->source, &isnull);
179  if (isnull)
180  elog(ERROR, "source contains a null value");
181  target_edge->source = DatumGetInt32(binval);
182 
183  binval = SPI_getbinval(*tuple, *tupdesc, edge_columns->target, &isnull);
184  if (isnull)
185  elog(ERROR, "target contains a null value");
186  target_edge->target = DatumGetInt32(binval);
187 
188  binval = SPI_getbinval(*tuple, *tupdesc, edge_columns->cost, &isnull);
189  if (isnull)
190  elog(ERROR, "cost contains a null value");
191  target_edge->cost = DatumGetFloat8(binval);
192 
193  if (edge_columns->reverse_cost != -1)
194  {
195  binval = SPI_getbinval(*tuple, *tupdesc, edge_columns->reverse_cost,
196  &isnull);
197  if (isnull)
198  elog(ERROR, "reverse_cost contains a null value");
199  target_edge->reverse_cost = DatumGetFloat8(binval);
200  }
201 
202  /*
203  DBG("edge: %i, %i, %i, %f, %f", target_edge->id, target_edge->source,
204  target_edge->target, target_edge->cost, target_edge->reverse_cost);
205  */
206 }
207 
208 
209 /*
210  * To fetch a edge from Tuple.
211  *
212  */
213 
214 static void
215 fetch_restrict(HeapTuple *tuple, TupleDesc *tupdesc,
217 {
218  Datum binval;
219  bool isnull;
220  int t;
221 
222  for(t=0; t<MAX_RULE_LENGTH;++t)
223  rest->via[t] = -1;
224 
225  binval = SPI_getbinval(*tuple, *tupdesc, restrict_columns->target_id, &isnull);
226  if (isnull)
227  elog(ERROR, "target_id contains a null value");
228  rest->target_id = DatumGetInt32(binval);
229 
230  binval = SPI_getbinval(*tuple, *tupdesc, restrict_columns->to_cost, &isnull);
231  if (isnull)
232  elog(ERROR, "to_cost contains a null value");
233  rest->to_cost = DatumGetFloat8(binval);
234  char *str = DatumGetCString(SPI_getvalue(*tuple, *tupdesc, restrict_columns->via_path));
235 
236  //DBG("restriction: %f, %i, %s", rest->to_cost, rest->target_id, str);
237 
238  if (str != NULL) {
239  char* pch = NULL;
240  int ci = 0;
241 
242  pch = (char *)strtok (str," ,");
243 
244  while (pch != NULL && ci < MAX_RULE_LENGTH)
245  {
246  rest->via[ci] = atoi(pch);
247  //DBG(" rest->via[%i]=%i", ci, rest->via[ci]);
248  ci++;
249  pch = (char *)strtok (NULL, " ,");
250  }
251  }
252 
253 }
254 
255 
256 
257 static int compute_trsp(
258  char* sql,
259  int dovertex,
260  int start_id,
261  double start_pos,
262  int end_id,
263  double end_pos,
264  bool directed,
265  bool has_reverse_cost,
266  char* restrict_sql,
268  int *path_count)
269 {
270 
271  int SPIcode;
272  SPIPlanPtr SPIplan;
273  Portal SPIportal;
274  bool moredata = TRUE;
275  int ntuples;
276 
277  edge_t *edges = NULL;
278  int total_tuples = 0;
279 #ifndef _MSC_VER
280  edge_columns_t edge_columns = {.id= -1, .source= -1, .target= -1,
281  .cost= -1, .reverse_cost= -1};
282 #else // _MSC_VER
283  edge_columns_t edge_columns = {-1, -1, -1, -1, -1};
284 #endif //_MSC_VER
285  restrict_t *restricts = NULL;
286  int total_restrict_tuples = 0;
287  restrict_columns_t restrict_columns = {.target_id= -1, .via_path= -1,
288  .to_cost= -1};
289  int v_max_id=0;
290  int v_min_id=INT_MAX;
291 
292  /* track if start and end are both in edge tuples */
293  int s_count = 0;
294  int t_count = 0;
295 
296  char *err_msg;
297  int ret = -1;
298  register int z;
299 
300  DBG("start turn_restrict_shortest_path\n");
301 
302  SPIcode = SPI_connect();
303  if (SPIcode != SPI_OK_CONNECT) {
304  elog(ERROR, "turn_restrict_shortest_path: couldn't open a connection to SPI");
305  return -1;
306  }
307 
308  SPIplan = SPI_prepare(sql, 0, NULL);
309  if (SPIplan == NULL) {
310  elog(ERROR, "turn_restrict_shortest_path: couldn't create query plan via SPI");
311  return -1;
312  }
313 
314  if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) {
315  elog(ERROR, "turn_restrict_shortest_path: SPI_cursor_open('%s') returns NULL", sql);
316  return -1;
317  }
318 
319  while (moredata == TRUE) {
320  //DBG("calling SPI_cursor_fetch");
321  SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);
322 
323  if (SPI_tuptable == NULL) {
324  elog(ERROR, "SPI_tuptable is NULL");
325  return finish(SPIcode, -1);
326  }
327 
328  if (edge_columns.id == -1) {
329  if (fetch_edge_columns(SPI_tuptable, &edge_columns,
330  has_reverse_cost) == -1)
331  return finish(SPIcode, ret);
332  }
333 
334  ntuples = SPI_processed;
335 
336  //DBG("Reading edges: %i - %i", total_tuples, total_tuples+ntuples);
337 
338  total_tuples += ntuples;
339 
340  if (ntuples > 0) {
341  if (!edges)
342  edges = palloc(total_tuples * sizeof(edge_t));
343  else
344  edges = repalloc(edges, total_tuples * sizeof(edge_t));
345 
346  if (edges == NULL) {
347  elog(ERROR, "Out of memory");
348  return finish(SPIcode, ret);
349  }
350 
351  int t;
352  SPITupleTable *tuptable = SPI_tuptable;
353  TupleDesc tupdesc = SPI_tuptable->tupdesc;
354 
355  for (t = 0; t < ntuples; t++) {
356  //if (t%100 == 0) { DBG(" t: %i", t); }
357  HeapTuple tuple = tuptable->vals[t];
358  fetch_edge(&tuple, &tupdesc, &edge_columns,
359  &edges[total_tuples - ntuples + t]);
360  }
361  //DBG("calling SPI_freetuptable");
362  SPI_freetuptable(tuptable);
363  //DBG("back from SPI_freetuptable");
364  }
365  else {
366  moredata = FALSE;
367  }
368  }
369  SPI_cursor_close(SPIportal);
370 
371  //defining min and max vertex id
372 
373  //DBG("Total %i edge tuples", total_tuples);
374 
375  for(z=0; z<total_tuples; z++) {
376  if(edges[z].source<v_min_id)
377  v_min_id=edges[z].source;
378 
379  if(edges[z].source>v_max_id)
380  v_max_id=edges[z].source;
381 
382  if(edges[z].target<v_min_id)
383  v_min_id=edges[z].target;
384 
385  if(edges[z].target>v_max_id)
386  v_max_id=edges[z].target;
387 
388  //DBG("%i <-> %i", v_min_id, v_max_id);
389 
390  }
391 
392  //::::::::::::::::::::::::::::::::::::
393  //:: reducing vertex id (renumbering)
394  //::::::::::::::::::::::::::::::::::::
395  for(z=0; z<total_tuples; z++) {
396  //check if edges[] contains source and target
397  if (dovertex) {
398  if(edges[z].source == start_id || edges[z].target == start_id)
399  ++s_count;
400  if(edges[z].source == end_id || edges[z].target == end_id)
401  ++t_count;
402  }
403  else {
404  if(edges[z].id == start_id)
405  ++s_count;
406  if(edges[z].id == end_id)
407  ++t_count;
408  }
409 
410  edges[z].source-=v_min_id;
411  edges[z].target-=v_min_id;
412  edges[z].cost = edges[z].cost;
413  //DBG("edgeID: %i SRc:%i - %i, cost: %f", edges[z].id,edges[z].source, edges[z].target,edges[z].cost);
414 
415  }
416 
417  DBG("Min vertex id: %i , Max vid: %i",v_min_id,v_max_id);
418  DBG("Total %i edge tuples", total_tuples);
419 
420  if(s_count == 0) {
421  elog(ERROR, "Start id was not found.");
422  return -1;
423  }
424 
425  if(t_count == 0) {
426  elog(ERROR, "Target id was not found.");
427  return -1;
428  }
429 
430  if (dovertex) {
431  start_id -= v_min_id;
432  end_id -= v_min_id;
433  }
434 
435  DBG("Fetching restriction tuples\n");
436 
437  if (restrict_sql == NULL) {
438  DBG("Sql for restrictions is null.");
439  }
440  else {
441  SPIplan = SPI_prepare(restrict_sql, 0, NULL);
442  if (SPIplan == NULL) {
443  elog(ERROR, "turn_restrict_shortest_path: couldn't create query plan via SPI");
444  return -1;
445  }
446 
447  if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) {
448  elog(ERROR, "turn_restrict_shortest_path: SPI_cursor_open('%s') returns NULL", restrict_sql);
449  return -1;
450  }
451 
452  moredata = TRUE;
453  while (moredata == TRUE) {
454  SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);
455 
456  if (restrict_columns.target_id == -1) {
457  if (fetch_restrict_columns(SPI_tuptable, &restrict_columns) == -1) {
458  DBG("fetch_restrict_columns failed!");
459  return finish(SPIcode, ret);
460  }
461  }
462 
463  ntuples = SPI_processed;
464  total_restrict_tuples += ntuples;
465 
466  //DBG("Reading Restrictions: %i", total_restrict_tuples);
467 
468  if (ntuples > 0) {
469  if (!restricts)
470  restricts = palloc(total_restrict_tuples * sizeof(restrict_t));
471  else
472  restricts = repalloc(restricts, total_restrict_tuples * sizeof(restrict_t));
473 
474  if (restricts == NULL) {
475  elog(ERROR, "Out of memory");
476  return finish(SPIcode, ret);
477  }
478 
479  int t;
480  SPITupleTable *tuptable = SPI_tuptable;
481  TupleDesc tupdesc = SPI_tuptable->tupdesc;
482 
483  for (t = 0; t < ntuples; t++) {
484  HeapTuple tuple = tuptable->vals[t];
485  fetch_restrict(&tuple, &tupdesc, &restrict_columns,
486  &restricts[total_restrict_tuples - ntuples + t]);
487  }
488  SPI_freetuptable(tuptable);
489  }
490  else {
491  moredata = FALSE;
492  }
493  }
494  SPI_cursor_close(SPIportal);
495 
496  }
497 
498 #ifdef DEBUG_OFF
499  int t;
500  for (t=0; t<total_restrict_tuples; t++) {
501  DBG("restricts: %.2f, %i, %i, %i, %i, %i, %i", restricts[t].to_cost, restricts[t].target_id, restricts[t].via[0], restricts[t].via[1], restricts[t].via[2], restricts[t].via[3], restricts[t].via[4]);
502  }
503 #endif
504 
505  DBG("Total %i restriction tuples", total_restrict_tuples);
506 
507  if (dovertex) {
508  DBG("Calling trsp_node_wrapper\n");
510  #if defined(__MINGW64__)
511  // elog(NOTICE,"Calling trsp_node_wrapper\n");
512  #endif
513  ret = trsp_node_wrapper(edges, total_tuples,
514  restricts, total_restrict_tuples,
515  start_id, end_id,
516  directed, has_reverse_cost,
517  path, path_count, &err_msg);
518  }
519  else {
520  DBG("Calling trsp_edge_wrapper\n");
521  ret = trsp_edge_wrapper(edges, total_tuples,
522  restricts, total_restrict_tuples,
523  start_id, start_pos, end_id, end_pos,
524  directed, has_reverse_cost,
525  path, path_count, &err_msg);
526  }
527 
528  DBG("Message received from inside:");
529  DBG("%s",err_msg);
530 
531  //DBG("SIZE %i\n",*path_count);
532 
533  //::::::::::::::::::::::::::::::::
534  //:: restoring original vertex id
535  //::::::::::::::::::::::::::::::::
536  for(z=0;z<*path_count;z++) {
537  //DBG("vetex %i\n",(*path)[z].vertex_id);
538  if (z || (*path)[z].vertex_id != -1)
539  (*path)[z].vertex_id+=v_min_id;
540  }
541 
542  DBG("ret = %i\n", ret);
543 
544  DBG("*path_count = %i\n", *path_count);
545 
546  if (ret < 0)
547  {
548  //elog(ERROR, "Error computing path: %s", err_msg);
549  ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED),
550  errmsg("Error computing path: %s", err_msg)));
551  }
552 
553  return finish(SPIcode, ret);
554 }
555 
556 
557 
559 PGDLLEXPORT Datum
561 {
562 
563  FuncCallContext *funcctx;
564  int call_cntr;
565  int max_calls;
566  TupleDesc tuple_desc;
568  char * sql;
569 
570 
571  // stuff done only on the first call of the function
572  if (SRF_IS_FIRSTCALL()) {
573  MemoryContext oldcontext;
574  int path_count = 0;
575 
576  int ret = -1;
577  if (ret == -1) {}; // to avoid warning set but not used
578 
579  int i;
580 
581  // create a function context for cross-call persistence
582  funcctx = SRF_FIRSTCALL_INIT();
583 
584  // switch to memory context appropriate for multiple function calls
585  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
586 
587  // verify that the first 5 args are not NULL
588  for (i=0; i<5; i++)
589  if(PG_ARGISNULL(i)) {
590  elog(ERROR, "turn_restrict_shortest_path(): Argument %i may not be NULL", i+1);
591  }
592 
593  if (PG_ARGISNULL(5))
594  sql = NULL;
595  else {
596  sql = text2char(PG_GETARG_TEXT_P(5));
597  if (strlen(sql) == 0)
598  sql = NULL;
599  }
600 
601  DBG("Calling compute_trsp");
602 
603 
604  ret =
605 
606  compute_trsp(text2char(PG_GETARG_TEXT_P(0)),
607  1, // do vertex
608  PG_GETARG_INT32(1),
609  0.5,
610  PG_GETARG_INT32(2),
611  0.5,
612  PG_GETARG_BOOL(3),
613  PG_GETARG_BOOL(4),
614  sql,
615  &path, &path_count);
616 #ifdef DEBUG
617  double total_cost = 0;
618  DBG("Ret is %i", ret);
619  if (ret >= 0)
620  {
621  int i;
622  for (i = 0; i < path_count; i++)
623  {
624  // DBG("Step %i vertex_id %i ", i, path[i].vertex_id);
625  // DBG(" edge_id %i ", path[i].edge_id);
626  // DBG(" cost %f ", path[i].cost);
627  total_cost+=path[i].cost;
628  }
629  }
630  DBG("Total cost is: %f",total_cost);
631 #endif
632 
633  // total number of tuples to be returned
634  funcctx->max_calls = path_count;
635  funcctx->user_fctx = path;
636 
637  funcctx->tuple_desc =
638  BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult"));
639 
640  MemoryContextSwitchTo(oldcontext);
641  }
642 
643  // stuff done on every call of the function
644  funcctx = SRF_PERCALL_SETUP();
645 
646  call_cntr = funcctx->call_cntr;
647  max_calls = funcctx->max_calls;
648  tuple_desc = funcctx->tuple_desc;
649  path = (path_element_t*) funcctx->user_fctx;
650 
651  if (call_cntr < max_calls) // do when there is more left to send
652  {
653  HeapTuple tuple;
654  Datum result;
655  Datum *values;
656  bool* nulls;
657 
658  values = palloc(4 * sizeof(Datum));
659  nulls = palloc(4 * sizeof(char));
660 
661  values[0] = Int32GetDatum(call_cntr);
662  nulls[0] = false;
663  values[1] = Int32GetDatum(path[call_cntr].vertex_id);
664  nulls[1] = false;
665  values[2] = Int32GetDatum(path[call_cntr].edge_id);
666  nulls[2] = false;
667  values[3] = Float8GetDatum(path[call_cntr].cost);
668  nulls[3] = false;
669 
670  tuple = heap_form_tuple(tuple_desc, values, nulls);
671 
672  // make the tuple into a datum
673  result = HeapTupleGetDatum(tuple);
674 
675  // clean up (this is not really necessary)
676  pfree(values);
677  pfree(nulls);
678 
679  SRF_RETURN_NEXT(funcctx, result);
680  }
681  else // do when there is no more left
682  {
683  DBG("Going to free path");
684  if (path) free(path);
685  SRF_RETURN_DONE(funcctx);
686  }
687 }
688 
690 PGDLLEXPORT Datum
692 {
693 
694  FuncCallContext *funcctx;
695  int call_cntr;
696  int max_calls;
697  TupleDesc tuple_desc;
699  char * sql;
700 
701  // stuff done only on the first call of the function
702  if (SRF_IS_FIRSTCALL()) {
703  MemoryContext oldcontext;
704  int path_count = 0;
705 #ifdef DEBUG
706  int ret = -1;
707 #endif
708  int i;
709  double s_pos;
710  double e_pos;
711 
712  // create a function context for cross-call persistence
713  funcctx = SRF_FIRSTCALL_INIT();
714 
715  // switch to memory context appropriate for multiple function calls
716  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
717 
718  // verify that the first 5 args are not NULL
719  for (i=0; i<7; i++) {
720  if(i==2 || i==4) continue;
721  if(PG_ARGISNULL(i)) {
722  elog(ERROR, "turn_restrict_shortest_path(): Argument %i may not be NULL", i+1);
723  }
724  }
725 
726  if (PG_ARGISNULL(2))
727  s_pos = 0.5;
728  else {
729  s_pos = PG_GETARG_FLOAT8(2);
730  if (s_pos < 0.0) s_pos = 0.5;
731  if (s_pos > 1.0) s_pos = 0.5;
732  }
733 
734  if (PG_ARGISNULL(4))
735  e_pos = 0.5;
736  else {
737  e_pos = PG_GETARG_FLOAT8(4);
738  if (e_pos < 0.0) e_pos = 0.5;
739  if (e_pos > 1.0) e_pos = 0.5;
740  }
741 
742  if (PG_ARGISNULL(7))
743  sql = NULL;
744  else {
745  sql = text2char(PG_GETARG_TEXT_P(7));
746  if (strlen(sql) == 0)
747  sql = NULL;
748  }
749 
750  DBG("Calling compute_trsp");
751 
752 #ifdef DEBUG
753  ret =
754 #endif
755  compute_trsp(text2char(PG_GETARG_TEXT_P(0)),
756  0, //sdo edge
757  PG_GETARG_INT32(1),
758  s_pos,
759  PG_GETARG_INT32(3),
760  e_pos,
761  PG_GETARG_BOOL(5),
762  PG_GETARG_BOOL(6),
763  sql,
764  &path, &path_count);
765 #ifdef DEBUG
766  double total_cost = 0;
767  DBG("Ret is %i", ret);
768  if (ret >= 0)
769  {
770  int i;
771  for (i = 0; i < path_count; i++)
772  {
773  // DBG("Step %i vertex_id %i ", i, path[i].vertex_id);
774  // DBG(" edge_id %i ", path[i].edge_id);
775  // DBG(" cost %f ", path[i].cost);
776  total_cost+=path[i].cost;
777  }
778  }
779  DBG("Total cost is: %f",total_cost);
780 #endif
781 
782  // total number of tuples to be returned
783  funcctx->max_calls = path_count;
784  funcctx->user_fctx = path;
785 
786  funcctx->tuple_desc =
787  BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult"));
788 
789  MemoryContextSwitchTo(oldcontext);
790  }
791 
792  // stuff done on every call of the function
793  funcctx = SRF_PERCALL_SETUP();
794 
795  call_cntr = funcctx->call_cntr;
796  max_calls = funcctx->max_calls;
797  tuple_desc = funcctx->tuple_desc;
798  path = (path_element_t*) funcctx->user_fctx;
799 
800  if (call_cntr < max_calls) // do when there is more left to send
801  {
802  HeapTuple tuple;
803  Datum result;
804  Datum *values;
805  bool* nulls;
806 
807  values = palloc(4 * sizeof(Datum));
808  nulls = palloc(4 * sizeof(char));
809 
810  values[0] = Int32GetDatum(call_cntr);
811  nulls[0] = false;
812  values[1] = Int32GetDatum(path[call_cntr].vertex_id);
813  nulls[1] = false;
814  values[2] = Int32GetDatum(path[call_cntr].edge_id);
815  nulls[2] = false;
816  values[3] = Float8GetDatum(path[call_cntr].cost);
817  nulls[3] = false;
818 
819  tuple = heap_form_tuple(tuple_desc, values, nulls);
820 
821  // make the tuple into a datum
822  result = HeapTupleGetDatum(tuple);
823 
824  // clean up (this is not really necessary)
825  pfree(values);
826  pfree(nulls);
827 
828  SRF_RETURN_NEXT(funcctx, result);
829  }
830  else // do when there is no more left
831  {
832  DBG("Going to free path");
833  if (path) free(path);
834  SRF_RETURN_DONE(funcctx);
835  }
836 }
int reverse_cost
Definition: trsp.c:38
int to_cost
Definition: trsp.c:45
int trsp_edge_wrapper(edge_t *edges, unsigned int edge_count, restrict_t *restricts, int restrict_count, int start_edge, double start_pos, int end_edge, double end_pos, bool directed, bool has_reverse_cost, path_element_t **path, int *path_count, char **err_msg)
Definition: trsp_core.cpp:60
int path_count
Definition: BDATester.cpp:51
static void fetch_edge(HeapTuple *tuple, TupleDesc *tupdesc, edge_columns_t *edge_columns, edge_t *target_edge)
Definition: trsp.c:167
double cost
struct edge_columns edge_columns_t
int id
Definition: trsp.c:34
int via_path
Definition: trsp.c:44
int target_id
Definition: trsp.h:40
int cost
Definition: trsp.c:37
static int fetch_edge_columns(SPITupleTable *tuptable, edge_columns_t *edge_columns, bool has_reverse_cost)
Definition: trsp.c:107
static int finish(int code, int ret)
Definition: trsp.c:61
#define TUPLIMIT
Definition: trsp.c:26
static int fetch_restrict_columns(SPITupleTable *tuptable, restrict_columns_t *restrict_columns)
Definition: trsp.c:78
int source
Definition: trsp.c:35
int trsp_node_wrapper(edge_t *edges, unsigned int edge_count, restrict_t *restricts, int restrict_count, int start_vertex, int end_vertex, bool directed, bool has_reverse_cost, path_element_t **path, int *path_count, char **err_msg)
Definition: trsp_core.cpp:10
float8 to_cost
Definition: trsp.h:41
int target_id
Definition: trsp.c:43
static void fetch_restrict(HeapTuple *tuple, TupleDesc *tupdesc, restrict_columns_t *restrict_columns, restrict_t *rest)
Definition: trsp.c:215
double reverse_cost
static char * text2char(text *in)
Definition: trsp.c:51
edge_astar_t * edges
Definition: BDATester.cpp:46
static int compute_trsp(char *sql, int dovertex, int start_id, double start_pos, int end_id, double end_pos, bool directed, bool has_reverse_cost, char *restrict_sql, path_element_t **path, int *path_count)
Definition: trsp.c:257
#define DBG(format,...)
Definition: trsp.c:22
PGDLLEXPORT Datum turn_restrict_shortest_path_vertex(PG_FUNCTION_ARGS)
Definition: trsp.c:560
path_element_t * path
Definition: BDATester.cpp:49
int target
Definition: trsp.c:36
int via[5]
Definition: trsp.h:42
char * err_msg
Definition: BDATester.cpp:50
#define MAX_RULE_LENGTH
Definition: pgr_types.h:172
PG_FUNCTION_INFO_V1(turn_restrict_shortest_path_vertex)
struct restrict_columns restrict_columns_t
PGDLLEXPORT Datum turn_restrict_shortest_path_edge(PG_FUNCTION_ARGS)
Definition: trsp.c:691
double cost
Definition: pgr_types.h:90