예제 #1
0
int main(void) {
    int total_tuples = 23;
    int i;

    int ret;
    char *err_msg = NULL;

    int start_vertex = 4401489;
    int end_vertex   = 4401483;

    int v_min_id = LONG_MAX;
    int v_max_id = 0;

    int s_count = 0;
    int t_count = 0;

    path_element_t *path = NULL;
    int path_count = 0;

    for (i=0; i<total_tuples; i++) {
        if(edges[i].source < v_min_id) v_min_id = edges[i].source;
        if(edges[i].target < v_min_id) v_min_id = edges[i].target;
        if(edges[i].source > v_max_id) v_max_id = edges[i].source;
        if(edges[i].target > v_max_id) v_max_id = edges[i].target;
    }
    printf("%i <-> %i\n", v_min_id, v_max_id);

    for (i=0; i<total_tuples; i++) {
        if (edges[i].source == start_vertex || edges[i].target == start_vertex)
            s_count++;
        if (edges[i].source == end_vertex || edges[i].target == end_vertex)
            t_count++;
        edges[i].source -= v_min_id;
        edges[i].target -= v_min_id;
    }

    assert(s_count);
    assert(t_count);

    start_vertex -= v_min_id;
    end_vertex   -= v_min_id;

    ret = boost_dijkstra(edges, total_tuples, start_vertex, end_vertex,
                         0, 0, &path, &path_count, &err_msg);

    if (ret < 0) {
        printf("Error computing path: %s\n", err_msg);
        exit(1);
    }

    printf("   seq:  vertex_id,    edge_id,       cost\n");
    for (i=0; i<path_count; i++) {
        path[i].vertex_id += v_min_id;
        printf("%6d: %10d, %10d, %10.4f\n", i, path[i].vertex_id, path[i].edge_id, path[i].cost);
    }

    if (path) free(path);

    exit(0);
}
예제 #2
0
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);
    }
}