Datum make_new_order_info(PG_FUNCTION_ARGS) { /* result Datum */ Datum result; char** cstr_values; HeapTuple result_tuple; /* tuple manipulating variables */ TupleDesc tupdesc; TupleTableSlot *slot; AttInMetadata *attinmeta; /* loop variables. */ int i; /* get tupdesc from the type name */ tupdesc = RelationNameGetTupleDesc("new_order_info"); /* allocate a slot for a tuple with this tupdesc */ slot = TupleDescGetSlot(tupdesc); /* * generate attribute metadata needed later to produce tuples * from raw C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); cstr_values = (char **) palloc(3 * sizeof(char *)); for(i = 0; i < 3; i++) { cstr_values[i] = (char*) palloc(16 * sizeof(char)); /* 16 bytes */ snprintf(cstr_values[i], 16, "%d", PG_GETARG_INT32(i)); } /* build a tuple */ result_tuple = BuildTupleFromCStrings(attinmeta, cstr_values); /* make the tuple into a datum */ result = TupleGetDatum(slot, result_tuple); return result; }
Datum bt_page_items(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_P(0); uint32 blkno = PG_GETARG_UINT32(1); RangeVar *relrv; Datum result; char *values[BTPAGEITEMS_NCOLUMNS]; BTPageOpaque opaque; HeapTuple tuple; ItemId id; FuncCallContext *fctx; MemoryContext mctx; struct user_args *uargs = NULL; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pgstattuple functions")))); if (blkno == 0) elog(ERROR, "Block 0 is a meta page."); if (SRF_IS_FIRSTCALL()) { fctx = SRF_FIRSTCALL_INIT(); mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); uargs = palloc(sizeof(struct user_args)); uargs->tupd = RelationNameGetTupleDesc(BTPAGEITEMS_TYPE); uargs->offset = FirstOffsetNumber; relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); uargs->rel = relation_openrv(relrv, AccessShareLock); CHECK_RELATION_BLOCK_RANGE(uargs->rel, blkno); uargs->buffer = ReadBuffer(uargs->rel, blkno); if (!IS_INDEX(uargs->rel) || !IS_BTREE(uargs->rel)) elog(ERROR, "bt_page_items() can be used only on b-tree index."); uargs->page = BufferGetPage(uargs->buffer); opaque = (BTPageOpaque) PageGetSpecialPointer(uargs->page); if (P_ISDELETED(opaque)) elog(NOTICE, "bt_page_items(): this page is deleted."); fctx->max_calls = PageGetMaxOffsetNumber(uargs->page); fctx->user_fctx = uargs; MemoryContextSwitchTo(mctx); } fctx = SRF_PERCALL_SETUP(); uargs = fctx->user_fctx; if (fctx->call_cntr < fctx->max_calls) { IndexTuple itup; id = PageGetItemId(uargs->page, uargs->offset); if (!ItemIdIsValid(id)) elog(ERROR, "Invalid ItemId."); itup = (IndexTuple) PageGetItem(uargs->page, id); { int j = 0; BlockNumber blkno = BlockIdGetBlockNumber(&(itup->t_tid.ip_blkid)); values[j] = palloc(32); snprintf(values[j++], 32, "%d", uargs->offset); values[j] = palloc(32); snprintf(values[j++], 32, "(%u,%u)", blkno, itup->t_tid.ip_posid); values[j] = palloc(32); snprintf(values[j++], 32, "%d", (int) IndexTupleSize(itup)); values[j] = palloc(32); snprintf(values[j++], 32, "%c", IndexTupleHasNulls(itup) ? 't' : 'f'); values[j] = palloc(32); snprintf(values[j++], 32, "%c", IndexTupleHasVarwidths(itup) ? 't' : 'f'); { int off; char *dump; char *ptr = (char *) itup + IndexInfoFindDataOffset(itup->t_info); dump = palloc(IndexTupleSize(itup) * 3); memset(dump, 0, IndexTupleSize(itup) * 3); for (off = 0; off < IndexTupleSize(itup) - IndexInfoFindDataOffset(itup->t_info); off++) { if (dump[0] == '\0') sprintf(dump, "%02x", *(ptr + off) & 0xff); else { char buf[4]; sprintf(buf, " %02x", *(ptr + off) & 0xff); strcat(dump, buf); } } values[j] = dump; } tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(uargs->tupd), values); result = TupleGetDatum(TupleDescGetSlot(uargs->tupd), tuple); } uargs->offset = uargs->offset + 1; SRF_RETURN_NEXT(fctx, result); } else { ReleaseBuffer(uargs->buffer); relation_close(uargs->rel, AccessShareLock); SRF_RETURN_DONE(fctx); } }
/* ----------------------------------------------- * bt_page() * * Usage: SELECT * FROM bt_page('t1_pkey', 0); * ----------------------------------------------- */ Datum bt_page_stats(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_P(0); uint32 blkno = PG_GETARG_UINT32(1); Buffer buffer; Relation rel; RangeVar *relrv; Datum result; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pgstattuple functions")))); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = relation_openrv(relrv, AccessShareLock); CHECK_RELATION_BLOCK_RANGE(rel, blkno); buffer = ReadBuffer(rel, blkno); if (!IS_INDEX(rel) || !IS_BTREE(rel)) elog(ERROR, "bt_page_stats() can be used only on b-tree index."); if (blkno == 0) elog(ERROR, "Block 0 is a meta page."); { HeapTuple tuple; TupleDesc tupleDesc; int j; char *values[BTPAGESTATS_NCOLUMNS]; BTPageStat stat; GetBTPageStatistics(blkno, buffer, &stat); tupleDesc = RelationNameGetTupleDesc(BTPAGESTATS_TYPE); j = 0; values[j] = palloc(32); snprintf(values[j++], 32, "%d", stat.blkno); values[j] = palloc(32); snprintf(values[j++], 32, "%c", stat.type); values[j] = palloc(32); snprintf(values[j++], 32, "%d", stat.live_items); values[j] = palloc(32); snprintf(values[j++], 32, "%d", stat.dead_items); values[j] = palloc(32); snprintf(values[j++], 32, "%d", stat.avg_item_size); values[j] = palloc(32); snprintf(values[j++], 32, "%d", stat.page_size); values[j] = palloc(32); snprintf(values[j++], 32, "%d", stat.free_size); values[j] = palloc(32); snprintf(values[j++], 32, "%d", stat.btpo_prev); values[j] = palloc(32); snprintf(values[j++], 32, "%d", stat.btpo_next); values[j] = palloc(32); if (stat.type == 'd') snprintf(values[j++], 32, "%d", stat.btpo.xact); else snprintf(values[j++], 32, "%d", stat.btpo.level); values[j] = palloc(32); snprintf(values[j++], 32, "%d", stat.btpo_flags); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); result = TupleGetDatum(TupleDescGetSlot(tupleDesc), tuple); } ReleaseBuffer(buffer); relation_close(rel, AccessShareLock); PG_RETURN_DATUM(result); }
/* ------------------------------------------------------ * pgstatindex() * * Usage: SELECT * FROM pgstatindex('t1_pkey'); * ------------------------------------------------------ */ Datum pgstatindex(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_P(0); Relation rel; RangeVar *relrv; Datum result; uint32 nblocks; uint32 blkno; BTIndexStat indexStat; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pgstattuple functions")))); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = relation_openrv(relrv, AccessShareLock); if (!IS_INDEX(rel) || !IS_BTREE(rel)) elog(ERROR, "pgstatindex() can be used only on b-tree index."); /*------------------- * Read a metapage *------------------- */ { Buffer buffer = ReadBuffer(rel, 0); Page page = BufferGetPage(buffer); BTMetaPageData *metad = BTPageGetMeta(page); indexStat.magic = metad->btm_magic; indexStat.version = metad->btm_version; indexStat.root_blkno = metad->btm_root; indexStat.level = metad->btm_level; indexStat.fastroot = metad->btm_fastroot; indexStat.fastlevel = metad->btm_fastlevel; ReleaseBuffer(buffer); } nblocks = RelationGetNumberOfBlocks(rel); /* -- init stat -- */ indexStat.fragments = 0; indexStat.root_pages = 0; indexStat.leaf_pages = 0; indexStat.internal_pages = 0; indexStat.empty_pages = 0; indexStat.deleted_pages = 0; indexStat.max_avail = 0; indexStat.free_space = 0; /*----------------------- * Scan all blocks *----------------------- */ for (blkno = 1; blkno < nblocks; blkno++) { Buffer buffer = ReadBuffer(rel, blkno); BTPageStat stat; /* scan one page */ stat.blkno = blkno; GetBTPageStatistics(blkno, buffer, &stat); /*--------------------- * page status (type) *--------------------- */ switch (stat.type) { case 'd': indexStat.deleted_pages++; break; case 'l': indexStat.leaf_pages++; break; case 'i': indexStat.internal_pages++; break; case 'e': indexStat.empty_pages++; break; case 'r': indexStat.root_pages++; break; default: elog(ERROR, "unknown page status."); } /* -- leaf fragmentation -- */ indexStat.fragments += stat.fragments; if (stat.type == 'l') { indexStat.max_avail += stat.max_avail; indexStat.free_space += stat.free_size; } ReleaseBuffer(buffer); } relation_close(rel, AccessShareLock); /*---------------------------- * Build a result tuple *---------------------------- */ { TupleDesc tupleDesc; int j; char *values[PGSTATINDEX_NCOLUMNS]; HeapTupleData tupleData; HeapTuple tuple = &tupleData; tupleDesc = RelationNameGetTupleDesc(PGSTATINDEX_TYPE); j = 0; values[j] = palloc(32); snprintf(values[j++], 32, "%d", indexStat.version); values[j] = palloc(32); snprintf(values[j++], 32, "%d", indexStat.level); values[j] = palloc(32); snprintf(values[j++], 32, "%d", (indexStat.root_pages + indexStat.leaf_pages + indexStat.internal_pages + indexStat.deleted_pages + indexStat.empty_pages) * BLCKSZ); values[j] = palloc(32); snprintf(values[j++], 32, "%d", indexStat.root_blkno); values[j] = palloc(32); snprintf(values[j++], 32, "%d", indexStat.internal_pages); values[j] = palloc(32); snprintf(values[j++], 32, "%d", indexStat.leaf_pages); values[j] = palloc(32); snprintf(values[j++], 32, "%d", indexStat.empty_pages); values[j] = palloc(32); snprintf(values[j++], 32, "%d", indexStat.deleted_pages); values[j] = palloc(32); snprintf(values[j++], 32, "%.2f", 100.0 - (float) indexStat.free_space / (float) indexStat.max_avail * 100.0); values[j] = palloc(32); snprintf(values[j++], 32, "%.2f", (float) indexStat.fragments / (float) indexStat.leaf_pages * 100.0); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); result = TupleGetDatum(TupleDescGetSlot(tupleDesc), tuple); } PG_RETURN_DATUM(result); }
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); } }
/* * pgstattuple_real * * The real work occurs here */ static Datum pgstattuple_real(Relation rel) { HeapScanDesc scan; HeapTuple tuple; BlockNumber nblocks; BlockNumber block = 0; /* next block to count free space in */ BlockNumber tupblock; Buffer buffer; uint64 table_len; uint64 tuple_len = 0; uint64 dead_tuple_len = 0; uint64 tuple_count = 0; uint64 dead_tuple_count = 0; double tuple_percent; double dead_tuple_percent; uint64 free_space = 0; /* free/reusable space in bytes */ double free_percent; /* free/reusable space in % */ TupleDesc tupdesc; TupleTableSlot *slot; AttInMetadata *attinmeta; char **values; int i; Datum result; /* * Build a tuple description for a pgstattupe_type tuple */ tupdesc = RelationNameGetTupleDesc(DUMMY_TUPLE); /* allocate a slot for a tuple with this tupdesc */ slot = TupleDescGetSlot(tupdesc); /* * Generate attribute metadata needed later to produce tuples from raw * C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); nblocks = RelationGetNumberOfBlocks(rel); scan = heap_beginscan(rel, SnapshotAny, 0, NULL); /* scan the relation */ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { uint16 sv_infomask; sv_infomask = tuple->t_data->t_infomask; if (HeapTupleSatisfiesNow(tuple->t_data)) { tuple_len += tuple->t_len; tuple_count++; } else { dead_tuple_len += tuple->t_len; dead_tuple_count++; } if (sv_infomask != tuple->t_data->t_infomask) SetBufferCommitInfoNeedsSave(scan->rs_cbuf); /* * To avoid physically reading the table twice, try to do the * free-space scan in parallel with the heap scan. However, * heap_getnext may find no tuples on a given page, so we cannot * simply examine the pages returned by the heap scan. */ tupblock = BlockIdGetBlockNumber(&tuple->t_self.ip_blkid); while (block <= tupblock) { buffer = ReadBuffer(rel, block); free_space += PageGetFreeSpace((Page) BufferGetPage(buffer)); ReleaseBuffer(buffer); block++; } } heap_endscan(scan); while (block < nblocks) { buffer = ReadBuffer(rel, block); free_space += PageGetFreeSpace((Page) BufferGetPage(buffer)); ReleaseBuffer(buffer); block++; } heap_close(rel, AccessShareLock); table_len = (uint64) nblocks *BLCKSZ; if (nblocks == 0) { tuple_percent = 0.0; dead_tuple_percent = 0.0; free_percent = 0.0; } else { tuple_percent = (double) tuple_len *100.0 / table_len; dead_tuple_percent = (double) dead_tuple_len *100.0 / table_len; free_percent = (double) free_space *100.0 / table_len; } /* * Prepare a values array for storage in our slot. This should be an * array of C strings which will be processed later by the appropriate * "in" functions. */ values = (char **) palloc(NCOLUMNS * sizeof(char *)); for (i = 0; i < NCOLUMNS; i++) values[i] = (char *) palloc(NCHARS * sizeof(char)); i = 0; snprintf(values[i++], NCHARS, INT64_FORMAT, table_len); snprintf(values[i++], NCHARS, INT64_FORMAT, tuple_count); snprintf(values[i++], NCHARS, INT64_FORMAT, tuple_len); snprintf(values[i++], NCHARS, "%.2f", tuple_percent); snprintf(values[i++], NCHARS, INT64_FORMAT, dead_tuple_count); snprintf(values[i++], NCHARS, INT64_FORMAT, dead_tuple_len); snprintf(values[i++], NCHARS, "%.2f", dead_tuple_percent); snprintf(values[i++], NCHARS, INT64_FORMAT, free_space); snprintf(values[i++], NCHARS, "%.2f", free_percent); /* build a tuple */ tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ result = TupleGetDatum(slot, tuple); /* Clean up */ for (i = 0; i < NCOLUMNS; i++) pfree(values[i]); pfree(values); return (result); }
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; size_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 = pgr_text2char(PG_GETARG_TEXT_P(7)); if (strlen(sql) == 0) sql = NULL; } PGR_DBG("Calling compute_trsp"); #ifdef DEBUG ret = #endif compute_trsp(pgr_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 = (uint32_t)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; 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); } }
/* ------------------------------------------------ * bt_metap() * * Get a btree meta-page information * * Usage: SELECT * FROM bt_metap('t1_pkey') * ------------------------------------------------ */ Datum bt_metap(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_P(0); Buffer buffer; Relation rel; RangeVar *relrv; Datum result; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pgstattuple functions")))); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = relation_openrv(relrv, AccessShareLock); if (!IS_INDEX(rel) || !IS_BTREE(rel)) elog(ERROR, "bt_metap() can be used only on b-tree index."); /* * Reject attempts to read non-local temporary relations; we would * be likely to get wrong data since we have no visibility into the * owning session's local buffers. */ if (isOtherTempNamespace(RelationGetNamespace(rel))) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); buffer = ReadBuffer(rel, 0); { BTMetaPageData *metad; TupleDesc tupleDesc; int j; char *values[BTMETAP_NCOLUMNS]; HeapTuple tuple; Page page = BufferGetPage(buffer); metad = BTPageGetMeta(page); tupleDesc = RelationNameGetTupleDesc(BTMETAP_TYPE); j = 0; values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_magic); values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_version); values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_root); values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_level); values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_fastroot); values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_fastlevel); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); result = TupleGetDatum(TupleDescGetSlot(tupleDesc), tuple); } ReleaseBuffer(buffer); relation_close(rel, AccessShareLock); PG_RETURN_DATUM(result); }
static int compute_shortest_path_shooting_star(char* sql, int source_edge_id, int target_edge_id, 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_shooting_star_t *edges = NULL; int total_tuples = 0; // int v_max_id=0; // int v_min_id=INT_MAX; int e_max_id=0; int e_min_id=INT_MAX; edge_shooting_star_columns_t edge_columns = {id: -1, source: -1, target: -1, cost: -1, reverse_cost: -1, s_x: -1, s_y: -1, t_x: -1, t_y: -1, to_cost: -1, rule: -1}; char *err_msg; int ret = -1; register int z, t; int s_count=0; int t_count=0; DBG("start shortest_path_shooting_star\n"); SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { elog(ERROR, "shortest_path_shooting_star: couldn't open a connection to SPI"); return -1; } SPIplan = SPI_prepare(sql, 0, NULL); if (SPIplan == NULL) { elog(ERROR, "shortest_path_shooting_star: couldn't create query plan via SPI"); return -1; } if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) { elog(ERROR, "shortest_path_shooting_star: 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_shooting_star_columns(SPI_tuptable, &edge_columns, has_reverse_cost) == -1) return finish(SPIcode, ret); } //DBG("***%i***", ret); ntuples = SPI_processed; total_tuples += ntuples; if (!edges) edges = palloc(total_tuples * sizeof(edge_shooting_star_t)); else edges = repalloc(edges, total_tuples * sizeof(edge_shooting_star_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_shooting_star(&tuple, &tupdesc, &edge_columns, &edges[total_tuples - ntuples + t]); } SPI_freetuptable(tuptable); } else { moredata = FALSE; } } DBG("Total %i tuples", total_tuples); for(z=0; z<total_tuples; z++) { if(edges[z].id<e_min_id) e_min_id=edges[z].id; if(edges[z].id>e_max_id) e_max_id=edges[z].id; } DBG("E : %i <-> %i", e_min_id, e_max_id); for(z=0; z<total_tuples; ++z) { //check if edges[] contains source and target if(edges[z].id == source_edge_id) ++s_count; if(edges[z].id == target_edge_id) ++t_count; //edges[z].source-=v_min_id; //edges[z].target-=v_min_id; } DBG("Total %i tuples", total_tuples); if(s_count == 0) { elog(ERROR, "Start edge was not found."); return -1; } if(t_count == 0) { elog(ERROR, "Target edge was not found."); return -1; } DBG("Total %i tuples", total_tuples); DBG("Calling boost_shooting_star <%i>\n", total_tuples); //time_t stime = time(NULL); ret = boost_shooting_star(edges, total_tuples, source_edge_id, target_edge_id, directed, has_reverse_cost, path, path_count, &err_msg, e_max_id); //time_t etime = time(NULL); //DBG("Path was calculated in %f seconds. \n", difftime(etime, stime)); DBG("SIZE %i\n",*path_count); DBG("ret = %i\n",ret); if (ret < 0) { 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(shortest_path_shooting_star); Datum shortest_path_shooting_star(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; /* 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_shortest_path_shooting_star(text2char(PG_GETARG_TEXT_P(0)), PG_GETARG_INT32(1), PG_GETARG_INT32(2), PG_GETARG_BOOL(3), PG_GETARG_BOOL(4), &path, &path_count); #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 */ DBG("Conting tuples number\n"); funcctx->max_calls = path_count; funcctx->user_fctx = path; DBG("Path count %i", path_count); 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; DBG("Trying to allocate some memory\n"); 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); SRF_RETURN_DONE(funcctx); } }
//Mandar: //This is where we return tuple according to it's offset in the file. HeapTuple csvindex_fetch_heap(IndexScanDesc scan) { //HeapTuple tuple; ItemPointer tid = &scan->xs_ctup.t_self; char *filename = (char *) palloc0(FILENAME_MAX); //This is shaky.. we are putting while path in sprintf(filename,"%s/csvinput/%s",getenv("HOME"),RelationGetRelationName(scan->heapRelation)); FILE *file = fopen(filename,"r"); int64 offset=0; char *chartuple = NULL; int iNumofAttr = scan->heapRelation->rd_rel->relnatts; int iAttr_size = 500+1; int32 size = iNumofAttr*iAttr_size + iNumofAttr + 10; char *linearr[iNumofAttr]; offset = tid->ip_blkid.bi_hi * 65535 * 65535; offset += tid->ip_blkid.bi_lo * 65535; offset += (tid->ip_posid-1); //substracting 1 as it was added to make tuplepointer valid assertion work //Allocate memory int i1=0; for(i1=0; i1<iNumofAttr; i1++) linearr[i1]=(char *)palloc0(iAttr_size); chartuple = (char *)palloc0(size); if(fseek(file,offset, SEEK_SET) != -1) { //First read row. if(fgets(chartuple,size,file)==NULL) { //No data in the file..return null tuple scan->xs_cbuf = InvalidBuffer; scan->xs_ctup.t_data = NULL; //scan->xs_ctup->t_len= newTuple->t_len; } else { //Parse and store in the array. if(!strlen(chartuple) && chartuple[0]!='\n') { //Return null tuple.. scan->xs_cbuf = InvalidBuffer; scan->xs_ctup.t_data = NULL; //scan->xs_ctup->t_len= newTuple->t_len; } else { //Form tuple. int attr=0; int i=0; while(attr < iNumofAttr && chartuple[i]!='\n') { int j=0; //printf("readme-%s---%c\n",record,record[i]); while(chartuple[i]!=',' && chartuple[i]!='\n') { linearr[attr][j++]=chartuple[i++]; } i++; linearr[attr][j]='\0'; attr++; } TupleDesc td = RelationNameGetTupleDesc(RelationGetRelationName(scan->heapRelation)); AttInMetadata *md = TupleDescGetAttInMetadata(td); HeapTuple newTuple = BuildTupleFromCStrings(md,linearr); scan->xs_cbuf = InvalidBuffer; scan->xs_ctup.t_data = newTuple->t_data; scan->xs_ctup.t_len= newTuple->t_len; //tuple->t_data = newTuple->t_data; //tuple->t_len = newTuple->t_len; //tuple->t_csvoffset = offset; //check if tuple is correct as per index definition. //if correct tuple then return the tuple else return null tuple. } } } else //Seek failed return null tuple.. { scan->xs_cbuf = InvalidBuffer; scan->xs_ctup.t_data = NULL; //scan->xs_ctup->t_len= newTuple->t_len; } if(file) fclose(file); return &scan->xs_ctup; }
Datum #else // _MSC_VER PGDLLEXPORT Datum #endif // _MSC_VER kshortest_path(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; TupleDesc tuple_desc; ksp_path_element_t *path; void * toDel; /* 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); ret = compute_kshortest_path(text2char(PG_GETARG_TEXT_P(0)), /* SQL string */ PG_GETARG_INT32(1), /* source id */ PG_GETARG_INT32(2), /* target_id */ PG_GETARG_INT32(3), /* number of paths */ PG_GETARG_BOOL(4), /* has reverse_cost */ &path, &path_count); toDel=path; #ifdef DEBUG if (ret >= 0) { int i; for (i = 0; i < path_count; i++) { DBG("Step %i route_id %d ", i, path[i].route_id); DBG(" vertex_id %d ", path[i].vertex_id); DBG(" edge_id %d ", path[i].edge_id); DBG(" cost %f ", path[i].cost); } } #endif DBG("Path-Cnt %i ", path_count); /* total number of tuples to be returned */ funcctx->max_calls = path_count; funcctx->user_fctx = path; funcctx->tuple_desc = BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult3")); 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 = (ksp_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[4]; //bool nulls[4]; */ Datum *values; bool* nulls; values = (Datum *)palloc(5 * sizeof(Datum)); nulls =(bool *) palloc(5 * sizeof(bool)); values[0] = Int32GetDatum(call_cntr); nulls[0] = false; values[1] = Int32GetDatum(path[call_cntr].route_id); nulls[1] = false; values[2] = Int32GetDatum(path[call_cntr].vertex_id); nulls[2] = false; values[3] = Int32GetDatum(path[call_cntr].edge_id); nulls[3] = false; values[4] = Float8GetDatum(path[call_cntr].cost); nulls[4] = 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 */ { free(path); SRF_RETURN_DONE(funcctx); } }
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); } }
/* ------------------------------------------------ * bt_metap() * * Get a btree meta-page information * * Usage: SELECT * FROM bt_metap('t1_pkey') * ------------------------------------------------ */ Datum bt_metap(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_P(0); Buffer buffer; Relation rel; RangeVar *relrv; Datum result; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pgstattuple functions")))); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = relation_openrv(relrv, AccessShareLock); if (!IS_INDEX(rel) || !IS_BTREE(rel)) elog(ERROR, "bt_metap() can be used only on b-tree index."); buffer = ReadBuffer(rel, 0); { BTMetaPageData *metad; TupleDesc tupleDesc; int j; char *values[BTMETAP_NCOLUMNS]; HeapTuple tuple; Page page = BufferGetPage(buffer); metad = BTPageGetMeta(page); tupleDesc = RelationNameGetTupleDesc(BTMETAP_TYPE); j = 0; values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_magic); values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_version); values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_root); values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_level); values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_fastroot); values[j] = palloc(32); snprintf(values[j++], 32, "%d", metad->btm_fastlevel); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); result = TupleGetDatum(TupleDescGetSlot(tupleDesc), tuple); } ReleaseBuffer(buffer); relation_close(rel, AccessShareLock); PG_RETURN_DATUM(result); }
/* table_log() trigger function for logging table changes parameter: - log table name (optional) return: - trigger data (for Pg) */ Datum table_log(PG_FUNCTION_ARGS) { TriggerData *trigdata = (TriggerData *) fcinfo->context; int ret; char query[250 + NAMEDATALEN]; /* for getting table infos (250 chars (+ one times the length of all names) should be enough) */ int number_columns = 0; /* counts the number columns in the table */ int number_columns_log = 0; /* counts the number columns in the table */ char *orig_schema; char *log_schema; char *log_table; int use_session_user = 0; /* should we write the current (session) user to the log table? */ /* * Some checks first... */ #ifdef TABLE_LOG_DEBUG elog(NOTICE, "start table_log()"); #endif /* TABLE_LOG_DEBUG */ /* called by trigger manager? */ if (!CALLED_AS_TRIGGER(fcinfo)) { elog(ERROR, "table_log: not fired by trigger manager"); } /* must only be called for ROW trigger */ if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event)) { elog(ERROR, "table_log: can't process STATEMENT events"); } /* must only be called AFTER */ if (TRIGGER_FIRED_BEFORE(trigdata->tg_event)) { elog(ERROR, "table_log: must be fired after event"); } /* now connect to SPI manager */ ret = SPI_connect(); if (ret != SPI_OK_CONNECT) { elog(ERROR, "table_log: SPI_connect returned %d", ret); } /* get schema name for the table, in case we need it later */ orig_schema = get_namespace_name(RelationGetNamespace(trigdata->tg_relation)); #ifdef TABLE_LOG_DEBUG elog(NOTICE, "prechecks done, now getting original table attributes"); #endif /* TABLE_LOG_DEBUG */ number_columns = count_columns(trigdata->tg_relation->rd_att); if (number_columns < 1) { elog(ERROR, "table_log: number of columns in table is < 1, can this happen?"); } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "number columns in orig table: %i", number_columns); #endif /* TABLE_LOG_DEBUG */ if (trigdata->tg_trigger->tgnargs > 3) { elog(ERROR, "table_log: too many arguments to trigger"); } /* name of the log schema */ if (trigdata->tg_trigger->tgnargs > 2) { /* check if a log schema argument is given, if yes, use it */ log_schema = trigdata->tg_trigger->tgargs[2]; } else { /* if no, use orig_schema */ log_schema = orig_schema; } /* should we write the current user? */ if (trigdata->tg_trigger->tgnargs > 1) { /* check if a second argument is given */ /* if yes, use it, if it is true */ if (atoi(trigdata->tg_trigger->tgargs[1]) == 1) { use_session_user = 1; #ifdef TABLE_LOG_DEBUG elog(NOTICE, "will write session user to 'trigger_user'"); #endif /* TABLE_LOG_DEBUG */ } } /* name of the log table */ if (trigdata->tg_trigger->tgnargs > 0) { /* check if a logtable argument is given */ /* if yes, use it */ log_table = (char *) palloc((strlen(trigdata->tg_trigger->tgargs[0]) + 2) * sizeof(char)); sprintf(log_table, "%s", trigdata->tg_trigger->tgargs[0]); } else { /* if no, use 'table name' + '_log' */ log_table = (char *) palloc((strlen(do_quote_ident(SPI_getrelname(trigdata->tg_relation))) + 5) * sizeof(char)); sprintf(log_table, "%s_log", SPI_getrelname(trigdata->tg_relation)); } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "log table: %s", log_table); #endif /* TABLE_LOG_DEBUG */ #ifdef TABLE_LOG_DEBUG elog(NOTICE, "now check, if log table exists"); #endif /* TABLE_LOG_DEBUG */ /* get the number columns in the table */ snprintf(query, 249, "%s.%s", do_quote_ident(log_schema), do_quote_ident(log_table)); number_columns_log = count_columns(RelationNameGetTupleDesc(query)); if (number_columns_log < 1) { elog(ERROR, "could not get number columns in relation %s", log_table); } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "number columns in log table: %i", number_columns_log); #endif /* TABLE_LOG_DEBUG */ /* check if the logtable has 3 (or now 4) columns more than our table */ /* +1 if we should write the session user */ if (use_session_user == 0) { /* without session user */ if (number_columns_log != number_columns + 3 && number_columns_log != number_columns + 4) { elog(ERROR, "number colums in relation %s(%d) does not match columns in %s(%d)", SPI_getrelname(trigdata->tg_relation), number_columns, log_table, number_columns_log); } } else { /* with session user */ if (number_columns_log != number_columns + 3 + 1 && number_columns_log != number_columns + 4 + 1) { elog(ERROR, "number colums in relation %s does not match columns in %s", SPI_getrelname(trigdata->tg_relation), log_table); } } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "log table OK"); #endif /* TABLE_LOG_DEBUG */ /* For each column in key ... */ #ifdef TABLE_LOG_DEBUG elog(NOTICE, "copy data ..."); #endif /* TABLE_LOG_DEBUG */ if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) { /* trigger called from INSERT */ #ifdef TABLE_LOG_DEBUG elog(NOTICE, "mode: INSERT -> new"); #endif /* TABLE_LOG_DEBUG */ __table_log(trigdata, "INSERT", "new", trigdata->tg_trigtuple, number_columns, log_table, use_session_user, log_schema); } else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) { /* trigger called from UPDATE */ #ifdef TABLE_LOG_DEBUG elog(NOTICE, "mode: UPDATE -> old"); #endif /* TABLE_LOG_DEBUG */ __table_log(trigdata, "UPDATE", "old", trigdata->tg_trigtuple, number_columns, log_table, use_session_user, log_schema); #ifdef TABLE_LOG_DEBUG elog(NOTICE, "mode: UPDATE -> new"); #endif /* TABLE_LOG_DEBUG */ __table_log(trigdata, "UPDATE", "new", trigdata->tg_newtuple, number_columns, log_table, use_session_user, log_schema); } else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) { /* trigger called from DELETE */ #ifdef TABLE_LOG_DEBUG elog(NOTICE, "mode: DELETE -> old"); #endif /* TABLE_LOG_DEBUG */ __table_log(trigdata, "DELETE", "old", trigdata->tg_trigtuple, number_columns, log_table, use_session_user, log_schema); } else { elog(ERROR, "trigger fired by unknown event"); } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "cleanup, trigger done"); #endif /* TABLE_LOG_DEBUG */ /* clean up */ pfree(log_table); /* close SPI connection */ SPI_finish(); /* return trigger data */ return PointerGetDatum(trigdata->tg_trigtuple); }
static int compute_sql_asm_tsp(char* sql, int sourceVertexId, bool reverseCost, tspPathElementType **path, int *pathCount) { int SPIcode; void *SPIplan; Portal SPIportal; bool moredata = TRUE; int ntuples; tspEdgeType *edges = NULL; int totalTuples = 0; DBG("Sql %s source %d reverse %s",sql,sourceVertexId,reverseCost==true?"true":"false"); tspEdgeType edgeColumns = {.id= -1, .source= -1, .target= -1, .cost= -1 }; char *errMesg; int ret = -1; errMesg=palloc(sizeof(char) * 300); DBG("start compute_sql_asm_tsp %i",*pathCount); SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { elog(ERROR, "compute_sql_asm_tsp: couldn't open a connection to SPI"); return -1; } SPIplan = SPI_prepare(sql, 0, NULL); if (SPIplan == NULL) { elog(ERROR, "compute_sql_asm_tsp: couldn't create query plan via SPI"); return -1; } if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) { elog(ERROR, "compute_sql_asm_tsp: SPI_cursor_open('%s') returns NULL", sql); return -1; } while (moredata == TRUE) { SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT); if (edgeColumns.id == -1) { if (!fetchEdgeTspColumns(SPI_tuptable, &edgeColumns,reverseCost)) return finish(SPIcode, ret); } ntuples = SPI_processed; totalTuples += ntuples; if (!edges){ edges = palloc(totalTuples * sizeof(tspEdgeType)); } else { edges = repalloc(edges, totalTuples * sizeof(tspEdgeType)); } 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]; fetchEdgeTsp(&tuple, &tupdesc, &edgeColumns, &edges[totalTuples - ntuples + t],reverseCost); } SPI_freetuptable(tuptable); } else { moredata = FALSE; } } DBG("Total %i tuples", totalTuples); DBG("Calling tsp functions total tuples <%i> initial path count <%i>", totalTuples,*pathCount); ret=processATSPData(edges,totalTuples,sourceVertexId,reverseCost, path, pathCount,errMesg); DBG("SIZE %i elements to process",*pathCount); if (!ret ) { elog(ERROR, "Error computing path: %s", errMesg); } return finish(SPIcode, ret); } PG_FUNCTION_INFO_V1(sql_asm_tsp); Datum sql_asm_tsp(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int callCntr; int maxCalls; TupleDesc tupleDesc; tspPathElementType *path; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; int pathCount = 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_sql_asm_tsp(text2char(PG_GETARG_TEXT_P(0)), PG_GETARG_INT32(1), PG_GETARG_BOOL(2), &path, &pathCount); #ifdef DEBUG if (ret >= 0) { int i; for (i = 0; i < pathCount; i++) { DBG("Step # %i vertexId %i cost %.4f", i, path[i].vertexId,path[i].cost); } } #endif /* total number of tuples to be returned */ funcctx->max_calls = pathCount; funcctx->user_fctx = path; DBG("Path count %i", pathCount); funcctx->tuple_desc = BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult")); MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); callCntr = funcctx->call_cntr; maxCalls = funcctx->max_calls; tupleDesc = funcctx->tuple_desc; path = (tspPathElementType*) funcctx->user_fctx; if (callCntr < maxCalls) { /* 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(callCntr); nulls[0] = ' '; values[1] = Int32GetDatum(path[callCntr].vertexId); nulls[1] = ' '; values[2] = Float8GetDatum(0); // edge id not supplied by this method nulls[2] = ' '; values[3] = Float8GetDatum(path[callCntr].cost); nulls[3] = ' '; tuple = heap_formtuple(tupleDesc, 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_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); } }