static int compute_apsp_warshall(char* sql, bool directed, bool has_reverse_cost, apsp_element_t **pair, int *pair_count) { int i; int SPIcode; void *SPIplan; Portal SPIportal; bool moredata = TRUE; int ntuples; edge_t *edges = NULL; int total_tuples = 0; edge_columns_t edge_columns = {.id= -1, .source= -1, .target= -1, .cost= -1, .reverse_cost= -1}; int v_max_id=0; int v_min_id=INT_MAX; int s_count = 0; int t_count = 0; char *err_msg; int ret = -1; register int z; // set<int> vertices; DBG("start compute_apsp_warshall\n"); SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { elog(ERROR, "compute_apsp_warshall: couldn't open a connection to SPI"); return -1; } SPIplan = SPI_prepare(sql, 0, NULL); if (SPIplan == NULL) { elog(ERROR, "compute_apsp_warshall: couldn't create query plan via SPI"); return -1; } if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) { elog(ERROR, "compute_apsp_warshall: SPI_cursor_open('%s') returns NULL", sql); return -1; } while (moredata == TRUE) { SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT); if (edge_columns.id == -1) { if (fetch_edge_columns(SPI_tuptable, &edge_columns, has_reverse_cost) == -1) return finish(SPIcode, ret); } ntuples = SPI_processed; total_tuples += ntuples; if (!edges) edges = palloc(total_tuples * sizeof(edge_t)); else edges = repalloc(edges, total_tuples * sizeof(edge_t)); if (edges == NULL) { elog(ERROR, "Out of memory"); return finish(SPIcode, ret); } DBG("Number of tuples fetched: %i",ntuples); if (ntuples > 0) { int t; SPITupleTable *tuptable = SPI_tuptable; TupleDesc tupdesc = SPI_tuptable->tupdesc; for (t = 0; t < ntuples; t++) { HeapTuple tuple = tuptable->vals[t]; fetch_edge(&tuple, &tupdesc, &edge_columns, &edges[total_tuples - ntuples + t]); // vertices.insert(edges[total_tuples - ntuples + t].source); // vertices.insert(edges[total_tuples - ntuples + t].target); } SPI_freetuptable(tuptable); } else { moredata = FALSE; } } #ifdef DEBUG for (i = 0; i < total_tuples; i++) { DBG("Step %i src_vertex_id %i ", i, edges[i].source); DBG(" dest_vertex_id %i ", edges[i].target); DBG(" cost %f ", edges[i].cost); } #endif DBG("Calling boost_apsp\n"); //start_vertex -= v_min_id; //end_vertex -= v_min_id; ret = boost_apsp(edges, total_tuples, 0, //vertices.size() directed, has_reverse_cost, pair, pair_count, &err_msg); DBG("Boost message: \n%s",err_msg); DBG("SIZE %i\n",*pair_count); /* //:::::::::::::::::::::::::::::::: //:: restoring original vertex id //:::::::::::::::::::::::::::::::: for(z=0;z<*path_count;z++) { //DBG("vetex %i\n",(*path)[z].vertex_id); (*path)[z].vertex_id+=v_min_id; } DBG("ret = %i\n", ret); DBG("*path_count = %i\n", *path_count); DBG("ret = %i\n", ret); */ if (ret < 0) { //elog(ERROR, "Error computing path: %s", err_msg); ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), errmsg("Error computing path: %s", err_msg))); } return finish(SPIcode, ret); } PG_FUNCTION_INFO_V1(apsp_warshall); Datum apsp_warshall(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; TupleDesc tuple_desc; apsp_element_t *pair; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; int pair_count = 0; int ret; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); ret = compute_apsp_warshall(text2char(PG_GETARG_TEXT_P(0)), PG_GETARG_BOOL(1), PG_GETARG_BOOL(2), &pair, &pair_count); #ifdef DEBUG DBG("Ret is %i", ret); if (ret >= 0) { int i; for (i = 0; i < pair_count; i++) { DBG("Step: %i, source_id: %i, target_id: %i, cost: %f ", i, pair[i].src_vertex_id, pair[i].dest_vertex_id, pair[i].cost); } } #endif /* total number of tuples to be returned */ funcctx->max_calls = pair_count; funcctx->user_fctx = pair; funcctx->tuple_desc = BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult")); MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; tuple_desc = funcctx->tuple_desc; pair = (apsp_element_t*) funcctx->user_fctx; if (call_cntr < max_calls) /* do when there is more left to send */ { HeapTuple tuple; Datum result; Datum *values; char* nulls; /* This will work for some compilers. If it crashes with segfault, try to change the following block with this one values = palloc(4 * sizeof(Datum)); nulls = palloc(4 * sizeof(char)); values[0] = call_cntr; nulls[0] = ' '; values[1] = Int32GetDatum(path[call_cntr].vertex_id); nulls[1] = ' '; values[2] = Int32GetDatum(path[call_cntr].edge_id); nulls[2] = ' '; values[3] = Float8GetDatum(path[call_cntr].cost); nulls[3] = ' '; */ values = palloc(4 * sizeof(Datum)); nulls = palloc(4 * sizeof(char)); values[0] = Int32GetDatum(call_cntr); nulls[0] = ' '; values[1] = Int32GetDatum(pair[call_cntr].src_vertex_id); nulls[1] = ' '; values[2] = Int32GetDatum(pair[call_cntr].dest_vertex_id); nulls[2] = ' '; values[3] = Float8GetDatum(pair[call_cntr].cost); nulls[3] = ' '; tuple = heap_formtuple(tuple_desc, values, nulls); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); /* clean up (this is not really necessary) */ pfree(values); pfree(nulls); SRF_RETURN_NEXT(funcctx, result); } else /* do when there is no more left */ { SRF_RETURN_DONE(funcctx); } }
static int compute_driving_distance(char* sql, int source_vertex_id, float8 distance, bool directed, bool has_reverse_cost, path_element_t **path, int *path_count) { int SPIcode; void *SPIplan; Portal SPIportal; bool moredata = TRUE; int ntuples; edge_t *edges = NULL; int total_tuples = 0; edge_columns_t edge_columns = {.id= -1, .source= -1, .target= -1, .cost= -1, .reverse_cost= -1}; int v_max_id=0; int v_min_id=INT_MAX; char *err_msg; int ret = -1; int s_count = 0; register int z; DBG("start driving_distance\n"); SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { elog(ERROR, "driving_distance: couldn't open a connection to SPI"); return -1; } SPIplan = SPI_prepare(sql, 0, NULL); if (SPIplan == NULL) { elog(ERROR, "driving_distance: couldn't create query plan via SPI"); return -1; } if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) { elog(ERROR, "driving_distance: SPI_cursor_open('%s') returns NULL", sql); return -1; } while (moredata == TRUE) { SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT); if (edge_columns.id == -1) { if (fetch_edge_columns(SPI_tuptable, &edge_columns, has_reverse_cost) == -1) return finish(SPIcode, ret); } ntuples = SPI_processed; total_tuples += ntuples; if (!edges) edges = palloc(total_tuples * sizeof(edge_t)); else edges = repalloc(edges, total_tuples * sizeof(edge_t)); if (edges == NULL) { elog(ERROR, "Out of memory"); return finish(SPIcode, ret); } if (ntuples > 0) { int t; SPITupleTable *tuptable = SPI_tuptable; TupleDesc tupdesc = SPI_tuptable->tupdesc; for (t = 0; t < ntuples; t++) { HeapTuple tuple = tuptable->vals[t]; fetch_edge(&tuple, &tupdesc, &edge_columns, &edges[total_tuples - ntuples + t]); } SPI_freetuptable(tuptable); } else { moredata = FALSE; } } //defining min and max vertex id DBG("Total %i tuples", total_tuples); for(z=0; z<total_tuples; z++) { if(edges[z].source<v_min_id) v_min_id=edges[z].source; if(edges[z].source>v_max_id) v_max_id=edges[z].source; if(edges[z].target<v_min_id) v_min_id=edges[z].target; if(edges[z].target>v_max_id) v_max_id=edges[z].target; DBG("%i <-> %i", v_min_id, v_max_id); } //:::::::::::::::::::::::::::::::::::: //:: reducing vertex id (renumbering) //:::::::::::::::::::::::::::::::::::: for(z=0; z<total_tuples; z++) { //check if edges[] contains source if(edges[z].source == source_vertex_id || edges[z].target == source_vertex_id) ++s_count; edges[z].source-=v_min_id; edges[z].target-=v_min_id; DBG("%i - %i", edges[z].source, edges[z].target); } if(s_count == 0) { elog(ERROR, "Start vertex was not found."); return -1; } source_vertex_id -= v_min_id; profstop("extract", prof_extract); profstart(prof_dijkstra); DBG("Calling boost_dijkstra\n"); ret = boost_dijkstra_dist(edges, total_tuples, source_vertex_id, distance, directed, has_reverse_cost, path, path_count, &err_msg); DBG("Back from boost_dijkstra\n"); if (ret < 0) { elog(ERROR, "Error computing path: %s", err_msg); } profstop("dijkstra", prof_dijkstra); profstart(prof_store); //:::::::::::::::::::::::::::::::: //:: restoring original vertex id //:::::::::::::::::::::::::::::::: for(z=0; z<*path_count; z++) { //DBG("vetex %i\n",(*path)[z].vertex_id); (*path)[z].vertex_id+=v_min_id; } return finish(SPIcode, ret); } PG_FUNCTION_INFO_V1(driving_distance); Datum driving_distance(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; TupleDesc tuple_desc; path_element_t *path = 0; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; int path_count = 0; int ret; // XXX profiling messages are not thread safe profstart(prof_total); profstart(prof_extract); /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); ret = compute_driving_distance(text2char(PG_GETARG_TEXT_P(0)), // sql PG_GETARG_INT32(1), // source vertex PG_GETARG_FLOAT8(2), // distance or time PG_GETARG_BOOL(3), PG_GETARG_BOOL(4), &path, &path_count); if (ret < 0) { elog(ERROR, "Error computing path"); } #ifdef DEBUG DBG("Ret is %i", ret); int i; for (i = 0; i < path_count; i++) { DBG("Step %i vertex_id %i ", i, path[i].vertex_id); DBG(" edge_id %i ", path[i].edge_id); DBG(" cost %f ", path[i].cost); } #endif /* total number of tuples to be returned */ funcctx->max_calls = path_count; funcctx->user_fctx = path; funcctx->tuple_desc = BlessTupleDesc( RelationNameGetTupleDesc("pgr_costResult")); MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; tuple_desc = funcctx->tuple_desc; path = (path_element_t*) funcctx->user_fctx; if (call_cntr < max_calls) { /* do when there is more left to send */ HeapTuple tuple; Datum result; Datum *values; char* nulls; values = palloc(4 * sizeof(Datum)); nulls = palloc(4 * sizeof(char)); values[0] = Int32GetDatum(call_cntr); nulls[0] = ' '; values[1] = Int32GetDatum(path[call_cntr].vertex_id); nulls[1] = ' '; values[2] = Int32GetDatum(path[call_cntr].edge_id); nulls[2] = ' '; values[3] = Float8GetDatum(path[call_cntr].cost); nulls[3] = ' '; tuple = heap_formtuple(tuple_desc, values, nulls); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); /* clean up (this is not really necessary) */ pfree(values); pfree(nulls); SRF_RETURN_NEXT(funcctx, result); } else { /* do when there is no more left */ if (path) free(path); profstop("store", prof_store); profstop("total", prof_total); #ifdef PROFILE elog(NOTICE, "_________"); #endif DBG("Returning value"); SRF_RETURN_DONE(funcctx); } }
static void get_edges_flow( char *sql, pgr_edge_t **edges, size_t *totalTuples, bool ignore_id) { clock_t start_t = clock(); const int tuple_limit = 1000000; size_t ntuples; size_t total_tuples; size_t valid_edges; Column_info_t info[5]; int i; for (i = 0; i < 5; ++i) { info[i].colNumber = -1; info[i].type = 0; info[i].strict = true; info[i].eType = ANY_INTEGER; } info[0].name = strdup("id"); info[1].name = strdup("source"); info[2].name = strdup("target"); info[3].name = strdup("capacity"); info[4].name = strdup("reverse_capacity"); info[0].strict = !ignore_id; info[4].strict = false; void *SPIplan; SPIplan = pgr_SPI_prepare(sql); Portal SPIportal; SPIportal = pgr_SPI_cursor_open(SPIplan); bool moredata = TRUE; (*totalTuples) = total_tuples = valid_edges = 0; int64_t default_id = 0; while (moredata == TRUE) { SPI_cursor_fetch(SPIportal, TRUE, tuple_limit); if (total_tuples == 0) pgr_fetch_column_info(info, 5); ntuples = SPI_processed; total_tuples += ntuples; if (ntuples > 0) { if ((*edges) == NULL) (*edges) = (pgr_edge_t *)palloc0(total_tuples * sizeof(pgr_flow_t)); else (*edges) = (pgr_edge_t *)repalloc((*edges), total_tuples * sizeof(pgr_flow_t)); if ((*edges) == NULL) { elog(ERROR, "Out of memory"); } size_t t; SPITupleTable *tuptable = SPI_tuptable; TupleDesc tupdesc = SPI_tuptable->tupdesc; for (t = 0; t < ntuples; t++) { HeapTuple tuple = tuptable->vals[t]; fetch_edge(&tuple, &tupdesc, info, &default_id, -1, &(*edges)[total_tuples - ntuples + t], &valid_edges, true); } SPI_freetuptable(tuptable); } else { moredata = FALSE; } } SPI_cursor_close(SPIportal); if (total_tuples == 0 || valid_edges == 0) { PGR_DBG("No edges found"); } (*totalTuples) = total_tuples; PGR_DBG("Reading %ld edges", total_tuples); time_msg("reading edges", start_t, clock()); }
static int compute_shortest_path(char* sql, int start_vertex, int end_vertex, bool directed, bool has_reverse_cost, path_element_t **path, int *path_count) { int SPIcode; void *SPIplan; Portal SPIportal; bool moredata = TRUE; int ntuples; edge_t *edges = NULL; int total_tuples = 0; edge_columns_t edge_columns = {id: -1, source: -1, target: -1, cost: -1, reverse_cost: -1}; int v_max_id=0; int v_min_id=INT_MAX; int s_count = 0; int t_count = 0; char *err_msg; int ret = -1; register int z; DBG("start shortest_path\n"); SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { elog(ERROR, "shortest_path: couldn't open a connection to SPI"); return -1; } SPIplan = SPI_prepare(sql, 0, NULL); if (SPIplan == NULL) { elog(ERROR, "shortest_path: couldn't create query plan via SPI"); return -1; } if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) { elog(ERROR, "shortest_path: SPI_cursor_open('%s') returns NULL", sql); return -1; } while (moredata == TRUE) { SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT); if (edge_columns.id == -1) { if (fetch_edge_columns(SPI_tuptable, &edge_columns, has_reverse_cost) == -1) return finish(SPIcode, ret); } ntuples = SPI_processed; total_tuples += ntuples; if (!edges) edges = palloc(total_tuples * sizeof(edge_t)); else edges = repalloc(edges, total_tuples * sizeof(edge_t)); if (edges == NULL) { elog(ERROR, "Out of memory"); return finish(SPIcode, ret); } if (ntuples > 0) { int t; SPITupleTable *tuptable = SPI_tuptable; TupleDesc tupdesc = SPI_tuptable->tupdesc; for (t = 0; t < ntuples; t++) { HeapTuple tuple = tuptable->vals[t]; fetch_edge(&tuple, &tupdesc, &edge_columns, &edges[total_tuples - ntuples + t]); } SPI_freetuptable(tuptable); } else { moredata = FALSE; } } //defining min and max vertex id DBG("Total %i tuples", total_tuples); for(z=0; z<total_tuples; z++) { if(edges[z].source<v_min_id) v_min_id=edges[z].source; if(edges[z].source>v_max_id) v_max_id=edges[z].source; if(edges[z].target<v_min_id) v_min_id=edges[z].target; if(edges[z].target>v_max_id) v_max_id=edges[z].target; DBG("%i <-> %i", v_min_id, v_max_id); } //:::::::::::::::::::::::::::::::::::: //:: reducing vertex id (renumbering) //:::::::::::::::::::::::::::::::::::: for(z=0; z<total_tuples; z++) { //check if edges[] contains source and target if(edges[z].source == start_vertex || edges[z].target == start_vertex) ++s_count; if(edges[z].source == end_vertex || edges[z].target == end_vertex) ++t_count; edges[z].source-=v_min_id; edges[z].target-=v_min_id; DBG("%i - %i", edges[z].source, edges[z].target); } DBG("Total %i tuples", total_tuples); if(s_count == 0) { elog(ERROR, "Source vertex: %d was not found as vertex of any of the input edges.", start_vertex); return -1; } if(t_count == 0) { elog(ERROR, "Target vertex: %d was not found as vertex of any of the input edges.", end_vertex); return -1; } DBG("Calling boost_dijkstra\n"); start_vertex -= v_min_id; end_vertex -= v_min_id; ret = boost_dijkstra(edges, total_tuples, start_vertex, end_vertex, directed, has_reverse_cost, path, path_count, &err_msg); DBG("SIZE %i\n",*path_count); //:::::::::::::::::::::::::::::::: //:: restoring original vertex id //:::::::::::::::::::::::::::::::: for(z=0;z<*path_count;z++) { //DBG("vetex %i\n",(*path)[z].vertex_id); (*path)[z].vertex_id+=v_min_id; } DBG("ret = %i\n", ret); DBG("*path_count = %i\n", *path_count); DBG("ret = %i\n", ret); if (ret < 0) { //elog(ERROR, "Error computing path: %s", err_msg); ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), errmsg("Error computing path: %s", err_msg))); } if (edges) { /* clean up input egdes */ pfree (edges); } return finish(SPIcode, ret); } PG_FUNCTION_INFO_V1(shortest_path); Datum shortest_path(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; TupleDesc tuple_desc; path_element_t *path = NULL; char *sql = NULL; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; int path_count = 0; int ret; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* edge sql query */ sql = text2char(PG_GETARG_TEXT_P(0)); ret = compute_shortest_path(sql, PG_GETARG_INT32(1), PG_GETARG_INT32(2), PG_GETARG_BOOL(3), PG_GETARG_BOOL(4), &path, &path_count); /* clean up sql query string */ if (sql) { pfree (sql); } #ifdef DEBUG DBG("Ret is %i", ret); if (ret >= 0) { int i; for (i = 0; i < path_count; i++) { DBG("Step %i vertex_id %i ", i, path[i].vertex_id); DBG(" edge_id %i ", path[i].edge_id); DBG(" cost %f ", path[i].cost); } } #endif /* total number of tuples to be returned */ funcctx->max_calls = path_count; funcctx->user_fctx = path; funcctx->tuple_desc = BlessTupleDesc(RelationNameGetTupleDesc("path_result")); MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; tuple_desc = funcctx->tuple_desc; path = (path_element_t*) funcctx->user_fctx; if (call_cntr < max_calls) /* do when there is more left to send */ { HeapTuple tuple; Datum result; Datum *values; char* nulls; /* This will work for some compilers. If it crashes with segfault, try to change the following block with this one values = palloc(4 * sizeof(Datum)); nulls = palloc(4 * sizeof(char)); values[0] = call_cntr; nulls[0] = ' '; values[1] = Int32GetDatum(path[call_cntr].vertex_id); nulls[1] = ' '; values[2] = Int32GetDatum(path[call_cntr].edge_id); nulls[2] = ' '; values[3] = Float8GetDatum(path[call_cntr].cost); nulls[3] = ' '; */ values = palloc(3 * sizeof(Datum)); nulls = palloc(3 * sizeof(char)); values[0] = Int32GetDatum(path[call_cntr].vertex_id); nulls[0] = ' '; values[1] = Int32GetDatum(path[call_cntr].edge_id); nulls[1] = ' '; values[2] = Float8GetDatum(path[call_cntr].cost); nulls[2] = ' '; tuple = heap_formtuple(tuple_desc, values, nulls); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); /* clean up (this is not really necessary) */ pfree(values); pfree(nulls); SRF_RETURN_NEXT(funcctx, result); } else /* do when there is no more left */ { if (path) { /* clean up returned edge paths must be a free because it's malloc'd */ free (path); path = NULL; } SRF_RETURN_DONE(funcctx); } }
static int compute_trsp( char* sql, int dovertex, long start_id, double start_pos, long end_id, double end_pos, bool directed, bool has_reverse_cost, char* restrict_sql, path_element_t **path, uint32_t *path_count) { int SPIcode; SPIPlanPtr SPIplan; Portal SPIportal; bool moredata = TRUE; size_t ntuples; edge_t *edges = NULL; size_t total_tuples = 0; #ifndef _MSC_VER edge_columns_t edge_columns = {.id= -1, .source= -1, .target= -1, .cost= -1, .reverse_cost= -1}; #else // _MSC_VER edge_columns_t edge_columns = {-1, -1, -1, -1, -1}; #endif //_MSC_VER restrict_t *restricts = NULL; size_t total_restrict_tuples = 0; #ifndef _MSC_VER restrict_columns_t restrict_columns = {.target_id= -1, .via_path= -1, .to_cost= -1}; #else // _MSC_VER restrict_columns_t restrict_columns = {-1, -1, -1}; #endif //_MSC_VER long v_max_id=0; long v_min_id=INT_MAX; /* track if start and end are both in edge tuples */ int s_count = 0; int t_count = 0; char *err_msg; int ret = -1; uint32_t z; PGR_DBG("start turn_restrict_shortest_path\n"); SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { elog(ERROR, "turn_restrict_shortest_path: couldn't open a connection to SPI"); return -1; } SPIplan = SPI_prepare(sql, 0, NULL); if (SPIplan == NULL) { elog(ERROR, "turn_restrict_shortest_path: couldn't create query plan via SPI"); return -1; } if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) { elog(ERROR, "turn_restrict_shortest_path: SPI_cursor_open('%s') returns NULL", sql); return -1; } while (moredata == TRUE) { //PGR_DBG("calling SPI_cursor_fetch"); SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT); if (SPI_tuptable == NULL) { elog(ERROR, "SPI_tuptable is NULL"); return finish(SPIcode, -1); } if (edge_columns.id == -1) { if (fetch_edge_columns(SPI_tuptable, &edge_columns, has_reverse_cost) == -1) return finish(SPIcode, ret); } ntuples = SPI_processed; //PGR_DBG("Reading edges: %i - %i", total_tuples, total_tuples+ntuples); total_tuples += ntuples; if (ntuples > 0) { if (!edges) edges = palloc(total_tuples * sizeof(edge_t)); else edges = repalloc(edges, total_tuples * sizeof(edge_t)); if (edges == NULL) { elog(ERROR, "Out of memory"); return finish(SPIcode, ret); } uint32_t t; SPITupleTable *tuptable = SPI_tuptable; TupleDesc tupdesc = SPI_tuptable->tupdesc; for (t = 0; t < ntuples; t++) { //if (t%100 == 0) { PGR_DBG(" t: %i", t); } HeapTuple tuple = tuptable->vals[t]; fetch_edge(&tuple, &tupdesc, &edge_columns, &edges[total_tuples - ntuples + t]); } //PGR_DBG("calling SPI_freetuptable"); SPI_freetuptable(tuptable); //PGR_DBG("back from SPI_freetuptable"); } else { moredata = FALSE; } } SPI_cursor_close(SPIportal); //defining min and max vertex id //PGR_DBG("Total %i edge tuples", total_tuples); for(z=0; z<total_tuples; z++) { if(edges[z].source<v_min_id) v_min_id=edges[z].source; if(edges[z].source>v_max_id) v_max_id=edges[z].source; if(edges[z].target<v_min_id) v_min_id=edges[z].target; if(edges[z].target>v_max_id) v_max_id=edges[z].target; //PGR_DBG("%i <-> %i", v_min_id, v_max_id); } //:::::::::::::::::::::::::::::::::::: //:: reducing vertex id (renumbering) //:::::::::::::::::::::::::::::::::::: for(z=0; z<total_tuples; z++) { //check if edges[] contains source and target if (dovertex) { if(edges[z].source == start_id || edges[z].target == start_id) ++s_count; if(edges[z].source == end_id || edges[z].target == end_id) ++t_count; } else { if(edges[z].id == start_id) ++s_count; if(edges[z].id == end_id) ++t_count; } edges[z].source-=v_min_id; edges[z].target-=v_min_id; edges[z].cost = edges[z].cost; //PGR_DBG("edgeID: %i SRc:%i - %i, cost: %f", edges[z].id,edges[z].source, edges[z].target,edges[z].cost); } PGR_DBG("Min vertex id: %ld , Max vid: %ld",v_min_id,v_max_id); PGR_DBG("Total %ld edge tuples", total_tuples); if(s_count == 0) { elog(ERROR, "Start id was not found."); return -1; } if(t_count == 0) { elog(ERROR, "Target id was not found."); return -1; } if (dovertex) { start_id -= v_min_id; end_id -= v_min_id; } PGR_DBG("Fetching restriction tuples\n"); if (restrict_sql == NULL) { PGR_DBG("Sql for restrictions is null."); } else { SPIplan = SPI_prepare(restrict_sql, 0, NULL); if (SPIplan == NULL) { elog(ERROR, "turn_restrict_shortest_path: couldn't create query plan via SPI"); return -1; } if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) { elog(ERROR, "turn_restrict_shortest_path: SPI_cursor_open('%s') returns NULL", restrict_sql); return -1; } moredata = TRUE; while (moredata == TRUE) { SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT); if (restrict_columns.target_id == -1) { if (fetch_restrict_columns(SPI_tuptable, &restrict_columns) == -1) { PGR_DBG("fetch_restrict_columns failed!"); return finish(SPIcode, ret); } } ntuples = SPI_processed; total_restrict_tuples += ntuples; //PGR_DBG("Reading Restrictions: %i", total_restrict_tuples); if (ntuples > 0) { if (!restricts) restricts = palloc(total_restrict_tuples * sizeof(restrict_t)); else restricts = repalloc(restricts, total_restrict_tuples * sizeof(restrict_t)); if (restricts == NULL) { elog(ERROR, "Out of memory"); return finish(SPIcode, ret); } uint32_t t; SPITupleTable *tuptable = SPI_tuptable; TupleDesc tupdesc = SPI_tuptable->tupdesc; for (t = 0; t < ntuples; t++) { HeapTuple tuple = tuptable->vals[t]; fetch_restrict(&tuple, &tupdesc, &restrict_columns, &restricts[total_restrict_tuples - ntuples + t]); } SPI_freetuptable(tuptable); } else { moredata = FALSE; } } SPI_cursor_close(SPIportal); } #ifdef DEBUG_OFF int t; for (t=0; t<total_restrict_tuples; t++) { PGR_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]); } #endif PGR_DBG("Total %ld restriction tuples", total_restrict_tuples); if (dovertex) { PGR_DBG("Calling trsp_node_wrapper\n"); /** hack always returns 0 -1 when installed on EDB VC++ 64-bit without this **/ #if defined(__MINGW64__) // elog(NOTICE,"Calling trsp_node_wrapper\n"); #endif ret = trsp_node_wrapper(edges, (uint32_t)total_tuples, restricts, (uint32_t)total_restrict_tuples, start_id, end_id, directed, has_reverse_cost, path, path_count, &err_msg); } else { PGR_DBG("Calling trsp_edge_wrapper\n"); ret = trsp_edge_wrapper(edges, (uint32_t)total_tuples, restricts, (uint32_t)total_restrict_tuples, start_id, start_pos, end_id, end_pos, directed, has_reverse_cost, path, path_count, &err_msg); } PGR_DBG("Message received from inside:"); PGR_DBG("%s",err_msg); //PGR_DBG("SIZE %i\n",*path_count); //:::::::::::::::::::::::::::::::: //:: restoring original vertex id //:::::::::::::::::::::::::::::::: for(z=0;z<*path_count;z++) { //PGR_DBG("vetex %i\n",(*path)[z].vertex_id); if (z || (*path)[z].vertex_id != -1) (*path)[z].vertex_id+=v_min_id; } PGR_DBG("ret = %i\n", ret); PGR_DBG("*path_count = %i\n", *path_count); if (ret < 0) { //elog(ERROR, "Error computing path: %s", err_msg); ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), errmsg("Error computing path: %s", err_msg))); } return finish(SPIcode, ret); } PG_FUNCTION_INFO_V1(turn_restrict_shortest_path_vertex); PGDLLEXPORT Datum turn_restrict_shortest_path_vertex(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; uint32_t call_cntr; uint32_t max_calls; TupleDesc tuple_desc; path_element_t *path; char * sql; // stuff done only on the first call of the function if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; uint32_t path_count = 0; int ret = -1; if (ret == -1) {}; // to avoid warning set but not used int i; // create a function context for cross-call persistence funcctx = SRF_FIRSTCALL_INIT(); // switch to memory context appropriate for multiple function calls oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); // verify that the first 5 args are not NULL for (i=0; i<5; i++) if(PG_ARGISNULL(i)) { elog(ERROR, "turn_restrict_shortest_path(): Argument %i may not be NULL", i+1); } if (PG_ARGISNULL(5)) sql = NULL; else { sql = text2char(PG_GETARG_TEXT_P(5)); if (strlen(sql) == 0) sql = NULL; } PGR_DBG("Calling compute_trsp"); ret = compute_trsp(text2char(PG_GETARG_TEXT_P(0)), 1, // do vertex PG_GETARG_INT32(1), 0.5, PG_GETARG_INT32(2), 0.5, PG_GETARG_BOOL(3), PG_GETARG_BOOL(4), sql, &path, &path_count); #ifdef DEBUG double total_cost = 0; PGR_DBG("Ret is %i", ret); if (ret >= 0) { int i; for (i = 0; i < path_count; i++) { // PGR_DBG("Step %i vertex_id %i ", i, path[i].vertex_id); // PGR_DBG(" edge_id %i ", path[i].edge_id); // PGR_DBG(" cost %f ", path[i].cost); total_cost+=path[i].cost; } } PGR_DBG("Total cost is: %f",total_cost); #endif // total number of tuples to be returned funcctx->max_calls = path_count; funcctx->user_fctx = path; funcctx->tuple_desc = BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult")); MemoryContextSwitchTo(oldcontext); } // stuff done on every call of the function funcctx = SRF_PERCALL_SETUP(); call_cntr = (uint32_t)funcctx->call_cntr; max_calls = (uint32_t)funcctx->max_calls; tuple_desc = funcctx->tuple_desc; path = (path_element_t*) funcctx->user_fctx; if (call_cntr < max_calls) // do when there is more left to send { HeapTuple tuple; Datum result; Datum *values; bool* nulls; values = palloc(4 * sizeof(Datum)); nulls = palloc(4 * sizeof(bool)); values[0] = Int32GetDatum(call_cntr); nulls[0] = false; values[1] = Int32GetDatum(path[call_cntr].vertex_id); nulls[1] = false; values[2] = Int32GetDatum(path[call_cntr].edge_id); nulls[2] = false; values[3] = Float8GetDatum(path[call_cntr].cost); nulls[3] = false; tuple = heap_form_tuple(tuple_desc, values, nulls); // make the tuple into a datum result = HeapTupleGetDatum(tuple); // clean up (this is not really necessary) pfree(values); pfree(nulls); SRF_RETURN_NEXT(funcctx, result); } else // do when there is no more left { PGR_DBG("Going to free path"); if (path) free(path); SRF_RETURN_DONE(funcctx); } } PG_FUNCTION_INFO_V1(turn_restrict_shortest_path_edge); PGDLLEXPORT Datum turn_restrict_shortest_path_edge(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; uint32_t call_cntr; uint32_t max_calls; TupleDesc tuple_desc; path_element_t *path; char * sql; // stuff done only on the first call of the function if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; uint32_t path_count = 0; #ifdef DEBUG int ret = -1; #endif int i; double s_pos; double e_pos; // create a function context for cross-call persistence funcctx = SRF_FIRSTCALL_INIT(); // switch to memory context appropriate for multiple function calls oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); // verify that the first 5 args are not NULL for (i=0; i<7; i++) { if(i==2 || i==4) continue; if(PG_ARGISNULL(i)) { elog(ERROR, "turn_restrict_shortest_path(): Argument %i may not be NULL", i+1); } } if (PG_ARGISNULL(2)) s_pos = 0.5; else { s_pos = PG_GETARG_FLOAT8(2); if (s_pos < 0.0) s_pos = 0.5; if (s_pos > 1.0) s_pos = 0.5; } if (PG_ARGISNULL(4)) e_pos = 0.5; else { e_pos = PG_GETARG_FLOAT8(4); if (e_pos < 0.0) e_pos = 0.5; if (e_pos > 1.0) e_pos = 0.5; } if (PG_ARGISNULL(7)) sql = NULL; else { sql = text2char(PG_GETARG_TEXT_P(7)); if (strlen(sql) == 0) sql = NULL; } PGR_DBG("Calling compute_trsp"); #ifdef DEBUG ret = #endif compute_trsp(text2char(PG_GETARG_TEXT_P(0)), 0, //sdo edge PG_GETARG_INT32(1), s_pos, PG_GETARG_INT32(3), e_pos, PG_GETARG_BOOL(5), PG_GETARG_BOOL(6), sql, &path, &path_count); #ifdef DEBUG double total_cost = 0; PGR_DBG("Ret is %i", ret); if (ret >= 0) { int i; for (i = 0; i < path_count; i++) { // PGR_DBG("Step %i vertex_id %i ", i, path[i].vertex_id); // PGR_DBG(" edge_id %i ", path[i].edge_id); // PGR_DBG(" cost %f ", path[i].cost); total_cost+=path[i].cost; } } PGR_DBG("Total cost is: %f",total_cost); #endif // total number of tuples to be returned funcctx->max_calls = path_count; funcctx->user_fctx = path; funcctx->tuple_desc = BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult")); MemoryContextSwitchTo(oldcontext); } // stuff done on every call of the function funcctx = SRF_PERCALL_SETUP(); call_cntr = (uint32_t)funcctx->call_cntr; max_calls = (uint32_t)funcctx->max_calls; tuple_desc = funcctx->tuple_desc; path = (path_element_t*) funcctx->user_fctx; if (call_cntr < max_calls) // do when there is more left to send { HeapTuple tuple; Datum result; Datum *values; bool* nulls; values = palloc(4 * sizeof(Datum)); nulls = palloc(4 * sizeof(bool)); values[0] = Int32GetDatum(call_cntr); nulls[0] = false; values[1] = Int32GetDatum(path[call_cntr].vertex_id); nulls[1] = false; values[2] = Int32GetDatum(path[call_cntr].edge_id); nulls[2] = false; values[3] = Float8GetDatum(path[call_cntr].cost); nulls[3] = false; tuple = heap_form_tuple(tuple_desc, values, nulls); // make the tuple into a datum result = HeapTupleGetDatum(tuple); // clean up (this is not really necessary) pfree(values); pfree(nulls); SRF_RETURN_NEXT(funcctx, result); } else // do when there is no more left { PGR_DBG("Going to free path"); if (path) free(path); SRF_RETURN_DONE(funcctx); } }