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); } }
static void grab_ExecutorEnd(QueryDesc * queryDesc) { Datum values[10]; bool nulls[10] = {false, false, false, false, false, false, false, false, false, false}; Relation dump_heap; RangeVar *dump_table_rv; HeapTuple tuple; Oid namespaceId; /* lookup schema */ namespaceId = GetSysCacheOid1(NAMESPACENAME, CStringGetDatum(EXTENSION_SCHEMA)); if (OidIsValid(namespaceId)) { /* lookup table */ if (OidIsValid(get_relname_relid(EXTENSION_LOG_TABLE, namespaceId))) { /* get table heap */ dump_table_rv = makeRangeVar(EXTENSION_SCHEMA, EXTENSION_LOG_TABLE, -1); dump_heap = heap_openrv(dump_table_rv, RowExclusiveLock); /* transaction info */ values[0] = Int32GetDatum(GetCurrentTransactionId()); values[1] = Int32GetDatum(GetCurrentCommandId(false)); values[2] = Int32GetDatum(MyProcPid); values[3] = Int32GetDatum(GetUserId()); /* query timing */ if (queryDesc->totaltime != NULL) { InstrEndLoop(queryDesc->totaltime); values[4] = TimestampGetDatum( TimestampTzPlusMilliseconds(GetCurrentTimestamp(), (queryDesc->totaltime->total * -1000.0))); values[5] = Float8GetDatum(queryDesc->totaltime->total); } else { nulls[4] = true; nulls[5] = true; } /* query command type */ values[6] = Int32GetDatum(queryDesc->operation); /* query text */ values[7] = CStringGetDatum( cstring_to_text(queryDesc->sourceText)); /* query params */ if (queryDesc->params != NULL) { int numParams = queryDesc->params->numParams; Oid out_func_oid, ptype; Datum pvalue; bool isvarlena; FmgrInfo *out_functions; bool arr_nulls[numParams]; size_t arr_nelems = (size_t) numParams; Datum *arr_val_elems = palloc(sizeof(Datum) * arr_nelems); Datum *arr_typ_elems = palloc(sizeof(Datum) * arr_nelems); char elem_val_byval, elem_val_align, elem_typ_byval, elem_typ_align; int16 elem_val_len, elem_typ_len; int elem_dims[1], elem_lbs[1]; int paramno; /* init */ out_functions = (FmgrInfo *) palloc( (numParams) * sizeof(FmgrInfo)); get_typlenbyvalalign(TEXTOID, &elem_val_len, &elem_val_byval, &elem_val_align); get_typlenbyvalalign(REGTYPEOID, &elem_typ_len, &elem_typ_byval, &elem_typ_align); elem_dims[0] = arr_nelems; elem_lbs[0] = 1; for (paramno = 0; paramno < numParams; paramno++) { pvalue = queryDesc->params->params[paramno].value; ptype = queryDesc->params->params[paramno].ptype; getTypeOutputInfo(ptype, &out_func_oid, &isvarlena); fmgr_info(out_func_oid, &out_functions[paramno]); arr_typ_elems[paramno] = ptype; arr_nulls[paramno] = true; if (!queryDesc->params->params[paramno].isnull) { arr_nulls[paramno] = false; arr_val_elems[paramno] = PointerGetDatum( cstring_to_text( OutputFunctionCall(&out_functions[paramno], pvalue))); } } values[8] = PointerGetDatum( construct_md_array( arr_val_elems, arr_nulls, 1, elem_dims, elem_lbs, TEXTOID, elem_val_len, elem_val_byval, elem_val_align)); values[9] = PointerGetDatum( construct_array( arr_typ_elems, arr_nelems, REGTYPEOID, elem_typ_len, elem_typ_byval, elem_typ_align)); pfree(out_functions); pfree(arr_val_elems); } else { nulls[8] = true; nulls[9] = true; } /* insert */ tuple = heap_form_tuple(dump_heap->rd_att, values, nulls); simple_heap_insert(dump_heap, tuple); heap_close(dump_heap, RowExclusiveLock); } } if (prev_ExecutorEnd) prev_ExecutorEnd(queryDesc); else standard_ExecutorEnd(queryDesc); }
static Datum leftmostvalue_float8(void) { return Float8GetDatum(-get_float8_infinity()); }
PGDLLEXPORT Datum kshortest_path(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; General_path_element_t *path = NULL; size_t result_count = 0; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* CREATE OR REPLACE FUNCTION _pgr_ksp( sql text, start_vid bigint, end_vid bigint, k integer, directed boolean, heap_paths boolean */ PGR_DBG("Calling process"); compute( text_to_cstring(PG_GETARG_TEXT_P(0)), /* SQL */ PG_GETARG_INT64(1), /* start_vid */ PG_GETARG_INT64(2), /* end_vid */ PG_GETARG_INT32(3), /* k */ PG_GETARG_BOOL(4), /* directed */ PG_GETARG_BOOL(5), /* heap_paths */ &path, &result_count); PGR_DBG("Total number of tuples to be returned %ld \n", result_count); /* */ /**********************************************************************/ #if PGSQL_VERSION > 95 funcctx->max_calls = result_count; #else funcctx->max_calls = (uint32_t)result_count; #endif funcctx->user_fctx = path; if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record\n"))); funcctx->tuple_desc = tuple_desc; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); tuple_desc = funcctx->tuple_desc; path = (General_path_element_t*) funcctx->user_fctx; if (funcctx->call_cntr < funcctx->max_calls) { /* do when there is more left to send */ HeapTuple tuple; Datum result; Datum *values; bool* nulls; values = palloc(7 * sizeof(Datum)); nulls = palloc(7 * sizeof(bool)); size_t i; for (i = 0; i < 7; ++i) { nulls[i] = false; } values[0] = Int32GetDatum(funcctx->call_cntr + 1); values[1] = Int32GetDatum(path[funcctx->call_cntr].start_id + 1); values[2] = Int32GetDatum(path[funcctx->call_cntr].seq); values[3] = Int64GetDatum(path[funcctx->call_cntr].node); values[4] = Int64GetDatum(path[funcctx->call_cntr].edge); values[5] = Float8GetDatum(path[funcctx->call_cntr].cost); values[6] = Float8GetDatum(path[funcctx->call_cntr].agg_cost); tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { /* do when there is no more left */ SRF_RETURN_DONE(funcctx); } }
Datum #else // _MSC_VER PGDLLEXPORT Datum #endif dijkstra_1_to_many(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; TupleDesc tuple_desc; pgr_path_element3_t *ret_path = 0; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; int path_count = 0; /* 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); int64_t* targetsArr; int num; targetsArr = (int64_t*) pgr_get_bigIntArray(&num, PG_GETARG_ARRAYTYPE_P(2)); PGR_DBG("targetsArr size %d ", num); #ifdef DEBUG int i; for (i = 0; i < num; ++i) { PGR_DBG("targetsArr[%d]=%li", i, targetsArr[i]); } #endif PGR_DBG("Calling dijkstra_1_to_many_driver"); dijkstra_1_to_many_driver( pgr_text2char(PG_GETARG_TEXT_P(0)), PG_GETARG_INT64(1), targetsArr, num, PG_GETARG_BOOL(3), PG_GETARG_BOOL(4), &ret_path, &path_count); free(targetsArr); /* total number of tuples to be returned */ funcctx->max_calls = path_count; funcctx->user_fctx = ret_path; if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); funcctx->tuple_desc = tuple_desc; 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; ret_path = (pgr_path_element3_t*) funcctx->user_fctx; /* do when there is more left to send */ if (call_cntr < max_calls) { HeapTuple tuple; Datum result; Datum *values; char* nulls; values = palloc(7 * sizeof(Datum)); nulls = palloc(7 * sizeof(char)); // id, start_v, node, edge, cost, tot_cost values[0] = Int32GetDatum(call_cntr + 1); nulls[0] = ' '; values[1] = Int32GetDatum(ret_path[call_cntr].seq); nulls[1] = ' '; values[2] = Int64GetDatum(ret_path[call_cntr].to); nulls[2] = ' '; values[3] = Int64GetDatum(ret_path[call_cntr].vertex); nulls[3] = ' '; values[4] = Int64GetDatum(ret_path[call_cntr].edge); nulls[4] = ' '; values[5] = Float8GetDatum(ret_path[call_cntr].cost); nulls[5] = ' '; values[6] = Float8GetDatum(ret_path[call_cntr].tot_cost); nulls[6] = ' '; 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 (ret_path) free(ret_path); SRF_RETURN_DONE(funcctx); } }
/** * @brief Sets the current state of the engine * * All this function does is calling the backend's seed functions. */ inline void NativeRandomNumberGenerator::seed(result_type inSeed) { DirectFunctionCall1(setseed, Float8GetDatum(inSeed)); }
PGDLLEXPORT Datum one_to_many_withPoints(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; /**********************************************************************/ General_path_element_t *result_tuples = NULL; size_t result_count = 0; /**********************************************************************/ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /**********************************************************************/ // CREATE OR REPLACE FUNCTION pgr_withPoint( // edges_sql TEXT, // points_sql TEXT, // start_pid BIGINT, // end_pids ANYARRAY, // directed BOOLEAN -- DEFAULT true, // driving_side CHAR -- DEFAULT 'b', // details BOOLEAN -- DEFAULT false, // only_cost BOOLEAN DEFAULT false, process( text_to_cstring(PG_GETARG_TEXT_P(0)), text_to_cstring(PG_GETARG_TEXT_P(1)), PG_GETARG_INT64(2), PG_GETARG_ARRAYTYPE_P(3), PG_GETARG_BOOL(4), text_to_cstring(PG_GETARG_TEXT_P(5)), PG_GETARG_BOOL(6), PG_GETARG_BOOL(7), &result_tuples, &result_count); /**********************************************************************/ #if PGSQL_VERSION > 95 funcctx->max_calls = result_count; #else funcctx->max_calls = (uint32_t)result_count; #endif funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); funcctx->tuple_desc = tuple_desc; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); tuple_desc = funcctx->tuple_desc; result_tuples = (General_path_element_t*) funcctx->user_fctx; if (funcctx->call_cntr < funcctx->max_calls) { HeapTuple tuple; Datum result; Datum *values; bool* nulls; /**********************************************************************/ // OUT seq BIGINT, // OUT path_seq, // OUT node BIGINT, // OUT edge BIGINT, // OUT cost FLOAT, // OUT agg_cost FLOAT) values = palloc(7 * sizeof(Datum)); nulls = palloc(7 * sizeof(bool)); size_t i; for (i = 0; i < 7; ++i) { nulls[i] = false; } // postgres starts counting from 1 values[0] = Int32GetDatum(funcctx->call_cntr + 1); values[1] = Int32GetDatum(result_tuples[funcctx->call_cntr].seq); values[2] = Int64GetDatum(result_tuples[funcctx->call_cntr].end_id); values[3] = Int64GetDatum(result_tuples[funcctx->call_cntr].node); values[4] = Int64GetDatum(result_tuples[funcctx->call_cntr].edge); values[5] = Float8GetDatum(result_tuples[funcctx->call_cntr].cost); values[6] = Float8GetDatum(result_tuples[funcctx->call_cntr].agg_cost); /**********************************************************************/ tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { SRF_RETURN_DONE(funcctx); } }
/* ------------------------------------------------ * hash_metapage_info() * * Get the meta-page information for a hash index * * Usage: SELECT * FROM hash_metapage_info(get_raw_page('con_hash_index', 0)) * ------------------------------------------------ */ Datum hash_metapage_info(PG_FUNCTION_ARGS) { bytea *raw_page = PG_GETARG_BYTEA_P(0); Page page; HashMetaPageData *metad; TupleDesc tupleDesc; HeapTuple tuple; int i, j; Datum values[16]; bool nulls[16]; Datum spares[HASH_MAX_SPLITPOINTS]; Datum mapp[HASH_MAX_BITMAPS]; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw page functions")))); page = verify_hash_page(raw_page, LH_META_PAGE); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); tupleDesc = BlessTupleDesc(tupleDesc); metad = HashPageGetMeta(page); MemSet(nulls, 0, sizeof(nulls)); j = 0; values[j++] = Int64GetDatum((int64) metad->hashm_magic); values[j++] = Int64GetDatum((int64) metad->hashm_version); values[j++] = Float8GetDatum(metad->hashm_ntuples); values[j++] = Int32GetDatum((int32) metad->hashm_ffactor); values[j++] = Int32GetDatum((int32) metad->hashm_bsize); values[j++] = Int32GetDatum((int32) metad->hashm_bmsize); values[j++] = Int32GetDatum((int32) metad->hashm_bmshift); values[j++] = Int64GetDatum((int64) metad->hashm_maxbucket); values[j++] = Int64GetDatum((int64) metad->hashm_highmask); values[j++] = Int64GetDatum((int64) metad->hashm_lowmask); values[j++] = Int64GetDatum((int64) metad->hashm_ovflpoint); values[j++] = Int64GetDatum((int64) metad->hashm_firstfree); values[j++] = Int64GetDatum((int64) metad->hashm_nmaps); values[j++] = ObjectIdGetDatum((Oid) metad->hashm_procid); for (i = 0; i < HASH_MAX_SPLITPOINTS; i++) spares[i] = Int64GetDatum((int64) metad->hashm_spares[i]); values[j++] = PointerGetDatum(construct_array(spares, HASH_MAX_SPLITPOINTS, INT8OID, 8, FLOAT8PASSBYVAL, 'd')); for (i = 0; i < HASH_MAX_BITMAPS; i++) mapp[i] = Int64GetDatum((int64) metad->hashm_mapp[i]); values[j++] = PointerGetDatum(construct_array(mapp, HASH_MAX_BITMAPS, INT8OID, 8, FLOAT8PASSBYVAL, 'd')); tuple = heap_form_tuple(tupleDesc, values, nulls); PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); }
/* * Update the eof and filetupcount of a parquet table. */ void UpdateParquetFileSegInfo(Relation parentrel, AppendOnlyEntry *aoEntry, int segno, int64 eof, int64 eof_uncompressed, int64 tuples_added) { LockAcquireResult acquireResult; Relation pg_parquetseg_rel; TupleDesc pg_parquetseg_dsc; ScanKeyData key[1]; SysScanDesc parquetscan; HeapTuple tuple, new_tuple; Datum filetupcount; Datum new_tuple_count; Datum *new_record; bool *new_record_nulls; bool *new_record_repl; bool isNull; /* overflow sanity checks. don't check the same for tuples_added, * it may be coming as a negative diff from gp_update_ao_master_stats */ Assert(eof >= 0); Insist(Gp_role != GP_ROLE_EXECUTE); elog(DEBUG3, "UpdateParquetFileSegInfo called. segno = %d", segno); if (Gp_role != GP_ROLE_DISPATCH) { /* * Verify we already have the write-lock! */ acquireResult = LockRelationAppendOnlySegmentFile( &parentrel->rd_node, segno, AccessExclusiveLock, /* dontWait */ false); if (acquireResult != LOCKACQUIRE_ALREADY_HELD) { elog(ERROR, "Should already have the (transaction-scope) write-lock on Parquet segment file #%d, " "relation %s", segno, RelationGetRelationName(parentrel)); } } /* * Open the aoseg relation and its index. */ pg_parquetseg_rel = heap_open(aoEntry->segrelid, RowExclusiveLock); pg_parquetseg_dsc = pg_parquetseg_rel->rd_att; /* * Setup a scan key to fetch from the index by segno. */ ScanKeyInit(&key[0], (AttrNumber) Anum_pg_parquetseg_segno, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(segno)); parquetscan = systable_beginscan(pg_parquetseg_rel, aoEntry->segidxid, TRUE, SnapshotNow, 1, &key[0]); tuple = systable_getnext(parquetscan); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("parquet table \"%s\" file segment \"%d\" entry " "does not exist", RelationGetRelationName(parentrel), segno))); new_record = palloc0(sizeof(Datum) * pg_parquetseg_dsc->natts); new_record_nulls = palloc0(sizeof(bool) * pg_parquetseg_dsc->natts); new_record_repl = palloc0(sizeof(bool) * pg_parquetseg_dsc->natts); /* get the current tuple count so we can add to it */ filetupcount = fastgetattr(tuple, Anum_pg_parquetseg_tupcount, pg_parquetseg_dsc, &isNull); if(isNull) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("got invalid pg_aoseg filetupcount value: NULL"))); /* calculate the new tuple count */ new_tuple_count = DirectFunctionCall2(float8pl, filetupcount, Float8GetDatum((float8)tuples_added)); /* * Build a tuple to update */ new_record[Anum_pg_parquetseg_eof - 1] = Float8GetDatum((float8)eof); new_record_repl[Anum_pg_parquetseg_eof - 1] = true; new_record[Anum_pg_parquetseg_tupcount - 1] = new_tuple_count; new_record_repl[Anum_pg_parquetseg_tupcount - 1] = true; new_record[Anum_pg_parquetseg_eofuncompressed - 1] = Float8GetDatum((float8)eof_uncompressed); new_record_repl[Anum_pg_parquetseg_eofuncompressed - 1] = true; /* * update the tuple in the pg_aoseg table */ new_tuple = heap_modify_tuple(tuple, pg_parquetseg_dsc, new_record, new_record_nulls, new_record_repl); simple_heap_update(pg_parquetseg_rel, &tuple->t_self, new_tuple); CatalogUpdateIndexes(pg_parquetseg_rel, new_tuple); heap_freetuple(new_tuple); /* Finish up scan */ systable_endscan(parquetscan); heap_close(pg_parquetseg_rel, RowExclusiveLock); pfree(new_record); pfree(new_record_nulls); pfree(new_record_repl); }
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_alpha_shape(char* sql, vertex_t **res, int *res_count) { int SPIcode; void *SPIplan; Portal SPIportal; bool moredata = TRUE; int ntuples; vertex_t *vertices = NULL; int total_tuples = 0; vertex_columns_t vertex_columns = {.id= -1, .x= -1, .y= -1}; char *err_msg; int ret = -1; DBG("start alpha_shape\n"); SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { elog(ERROR, "alpha_shape: couldn't open a connection to SPI"); return -1; } SPIplan = SPI_prepare(sql, 0, NULL); if (SPIplan == NULL) { elog(ERROR, "alpha_shape: couldn't create query plan via SPI"); return -1; } if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) { elog(ERROR, "alpha_shape: SPI_cursor_open('%s') returns NULL", sql); return -1; } while (moredata == TRUE) { SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT); if (vertex_columns.id == -1) { if (fetch_vertices_columns(SPI_tuptable, &vertex_columns) == -1) return finish(SPIcode, ret); } ntuples = SPI_processed; total_tuples += ntuples; if (!vertices) vertices = palloc(total_tuples * sizeof(vertex_t)); else vertices = repalloc(vertices, total_tuples * sizeof(vertex_t)); if (vertices == 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_vertex(&tuple, &tupdesc, &vertex_columns, &vertices[total_tuples - ntuples + t]); } SPI_freetuptable(tuptable); } else { moredata = FALSE; } } // if (total_tuples < 2) //this was the buggy code of the pgrouting project. // TODO: report this as a bug to the pgrouting project // the CGAL alpha-shape function crashes if called with less than three points!!! if (total_tuples == 0) { elog(ERROR, "Distance is too short. no vertex for alpha shape calculation. alpha shape calculation needs at least 3 vertices."); } if (total_tuples == 1) { elog(ERROR, "Distance is too short. only 1 vertex for alpha shape calculation. alpha shape calculation needs at least 3 vertices."); } if (total_tuples == 2) { elog(ERROR, "Distance is too short. only 2 vertices for alpha shape calculation. alpha shape calculation needs at least 3 vertices."); } if (total_tuples < 3) { // elog(ERROR, "Distance is too short ...."); return finish(SPIcode, ret); } DBG("Calling CGAL alpha-shape\n"); profstop("extract", prof_extract); profstart(prof_alpha); ret = alpha_shape(vertices, total_tuples, res, res_count, &err_msg); profstop("alpha", prof_alpha); profstart(prof_store); if (ret < 0) { //elog(ERROR, "Error computing shape: %s", err_msg); ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), errmsg("Error computing shape: %s", err_msg))); } return finish(SPIcode, ret); } PG_FUNCTION_INFO_V1(alphashape); Datum alphashape(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; TupleDesc tuple_desc; vertex_t *res = 0; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; int res_count; 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_alpha_shape(text2char(PG_GETARG_TEXT_P(0)), &res, &res_count); /* total number of tuples to be returned */ DBG("Conting tuples number\n"); funcctx->max_calls = res_count; funcctx->user_fctx = res; DBG("Total count %i", res_count); if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); funcctx->tuple_desc = BlessTupleDesc(tuple_desc); MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ DBG("Strange stuff doing\n"); funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; tuple_desc = funcctx->tuple_desc; res = (vertex_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; /* This will work for some compilers. If it crashes with segfault, try to change the following block with this one values = palloc(3 * sizeof(Datum)); nulls = palloc(3 * sizeof(char)); values[0] = call_cntr; nulls[0] = ' '; values[1] = Float8GetDatum(res[call_cntr].x); nulls[1] = ' '; values[2] = Float8GetDatum(res[call_cntr].y); nulls[2] = ' '; */ values = palloc(2 * sizeof(Datum)); nulls = palloc(2 * sizeof(char)); values[0] = Float8GetDatum(res[call_cntr].x); nulls[0] = ' '; values[1] = Float8GetDatum(res[call_cntr].y); nulls[1] = ' '; DBG("Heap making\n"); tuple = heap_formtuple(tuple_desc, values, nulls); DBG("Datum making\n"); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); DBG("Trying to free some memory\n"); /* 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 (res) free(res); profstop("store", prof_store); profstop("total", prof_total); #ifdef PROFILE elog(NOTICE, "_________"); #endif 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); } }
Datum shortest_path(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; TupleDesc tuple_desc; pgr_path_element3_t *ret_path = 0; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; int path_count = 0; /* 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); compute_shortest_path(pgr_text2char(PG_GETARG_TEXT_P(0)), PG_GETARG_INT64(1), PG_GETARG_INT64(2), PG_GETARG_BOOL(3), PG_GETARG_BOOL(4), &ret_path, &path_count); /* total number of tuples to be returned */ funcctx->max_calls = path_count; funcctx->user_fctx = ret_path; if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); funcctx->tuple_desc = tuple_desc; 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; ret_path = (pgr_path_element3_t*) funcctx->user_fctx; /* do when there is more left to send */ if (call_cntr < max_calls) { HeapTuple tuple; Datum result; Datum *values; char* nulls; values = palloc(6 * sizeof(Datum)); nulls = palloc(6 * sizeof(char)); values[0] = Int32GetDatum(ret_path[call_cntr].seq); nulls[0] = ' '; values[1] = Int32GetDatum(ret_path[call_cntr].seq); nulls[1] = ' '; values[2] = Int64GetDatum(ret_path[call_cntr].vertex); nulls[2] = ' '; values[3] = Int64GetDatum(ret_path[call_cntr].edge); nulls[3] = ' '; values[4] = Float8GetDatum(ret_path[call_cntr].cost); nulls[4] = ' '; values[5] = Float8GetDatum(ret_path[call_cntr].tot_cost); nulls[5] = ' '; 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 (ret_path) free(ret_path); SRF_RETURN_DONE(funcctx); } }
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); } }
Datum ta_f( PG_FUNCTION_ARGS) { // Declare for TA TA_RetCode retCode; TA_Real *closePrice = NULL; TA_Real *out; TA_Integer outBeg; TA_Integer outNbElement; // Declare for postgres FuncCallContext *funcctx; int call_cntr; int max_calls; Datum *result = NULL; int dim; int z; ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0); if (array_contains_nulls(ur)) { ereport(ERROR, ( errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("cannot work with arrays containing NULLs") )); } dim = ARRNELEMS(ur); closePrice = ARRPTR(ur); if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* One-time setup code appears here: */ retCode = TA_Initialize(); if (retCode != TA_SUCCESS) { ereport(ERROR, ( errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Cannot initialize TA-Lib (%d)!\n", retCode) )); } out = palloc(dim * sizeof(TA_Real)); retCode = TA_MA(0, dim - 1, &closePrice[0], 5, TA_MAType_SMA, &outBeg, &outNbElement, &out[0]); result = palloc(outNbElement * sizeof(Datum)); // Error log for debugging /* ereport(NOTICE, (errmsg("dims %d, outBeg: %d, outNbElement %d\n", dim, outBeg, outNbElement))); */ for (z = 0; z < dim; z++) { // Error log for debugging //ereport(NOTICE, (errmsg("z: %d, out[z]: %5.1f", z, out[z]))); if(z > outBeg-1) { result[z] = Float8GetDatum(out[z-outBeg]); continue; } result[z] = NULL; } TA_Shutdown(); funcctx->max_calls = dim; funcctx->user_fctx = 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; if (call_cntr < max_calls) { if(((Datum *) funcctx->user_fctx)[call_cntr]) { SRF_RETURN_NEXT(funcctx, ((Datum *) funcctx->user_fctx)[call_cntr]); } SRF_RETURN_NEXT_NULL(funcctx); } SRF_RETURN_DONE(funcctx); }
PGDLLEXPORT Datum newTSP(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; /**************************************************************************/ /* MODIFY AS NEEDED */ /* */ General_path_element_t *result_tuples = NULL; size_t result_count = 0; /* */ /**************************************************************************/ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /**********************************************************************/ /* MODIFY AS NEEDED */ /* CREATE OR REPLACE FUNCTION pgr_newTSP( matrix_row_sql TEXT, start_id BIGINT DEFAULT 0, end_id BIGINT DEFAULT 0, max_processing_time FLOAT DEFAULT '+infinity'::FLOAT, tries_per_temperature INTEGER DEFAULT 500, max_changes_per_temperature INTEGER DEFAULT 60, max_consecutive_non_changes INTEGER DEFAULT 200, initial_temperature FLOAT DEFAULT 100, final_temperature FLOAT DEFAULT 0.1, cooling_factor FLOAT DEFAULT 0.9, randomize BOOLEAN DEFAULT true, */ process( text_to_cstring(PG_GETARG_TEXT_P(0)), PG_GETARG_INT64(1), PG_GETARG_INT64(2), PG_GETARG_FLOAT8(3), PG_GETARG_INT32(4), PG_GETARG_INT32(5), PG_GETARG_INT32(6), PG_GETARG_FLOAT8(7), PG_GETARG_FLOAT8(8), PG_GETARG_FLOAT8(9), PG_GETARG_BOOL(10), &result_tuples, &result_count); /* */ /**********************************************************************/ #if PGSQL_VERSION > 95 funcctx->max_calls = result_count; #else funcctx->max_calls = (uint32_t)result_count; #endif funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); } funcctx->tuple_desc = tuple_desc; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); tuple_desc = funcctx->tuple_desc; result_tuples = (General_path_element_t*) funcctx->user_fctx; if (funcctx->call_cntr < funcctx->max_calls) { HeapTuple tuple; Datum result; Datum *values; bool* nulls; /**********************************************************************/ /* MODIFY AS NEEDED */ // OUT seq INTEGER, // OUT node BIGINT, // OUT cost FLOAT, // OUT agg_cost FLOAT values = palloc(4 * sizeof(Datum)); nulls = palloc(4 * sizeof(bool)); size_t i; for (i = 0; i < 4; ++i) { nulls[i] = false; } // postgres starts counting from 1 values[0] = Int32GetDatum(funcctx->call_cntr + 1); values[1] = Int64GetDatum(result_tuples[funcctx->call_cntr].node); values[2] = Float8GetDatum(result_tuples[funcctx->call_cntr].cost); values[3] = Float8GetDatum(result_tuples[funcctx->call_cntr].agg_cost); /**********************************************************************/ tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { SRF_RETURN_DONE(funcctx); } }
static int compute_shortest_path_astar(char* sql, int source_vertex_id, int target_vertex_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_astar_t *edges = NULL; int total_tuples = 0; int v_max_id=0; int v_min_id=INT_MAX; edge_astar_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}; char *err_msg; int ret = -1; register int z; int s_count=0; int t_count=0; struct vItem { int id; int key; }; DBG("start shortest_path_astar\n"); SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { elog(ERROR, "shortest_path_astar: couldn't open a connection to SPI"); return -1; } SPIplan = SPI_prepare(sql, 0, NULL); if (SPIplan == NULL) { elog(ERROR, "shortest_path_astar: couldn't create query plan via SPI"); return -1; } if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) { elog(ERROR, "shortest_path_astar: 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_astar_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_astar_t)); else edges = repalloc(edges, total_tuples * sizeof(edge_astar_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_astar(&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 == source_vertex_id || edges[z].target == source_vertex_id) ++s_count; if(edges[z].source == target_vertex_id || edges[z].target == target_vertex_id) ++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, "Start vertex was not found."); return -1; } if(t_count == 0) { elog(ERROR, "Target vertex was not found."); return -1; } DBG("Total %i tuples", total_tuples); profstop("extract", prof_extract); profstart(prof_astar); DBG("Calling boost_astar <%i>\n", total_tuples); // calling C++ A* function ret = boost_astar(edges, total_tuples, source_vertex_id-v_min_id, target_vertex_id-v_min_id, directed, has_reverse_cost, path, path_count, &err_msg); if (ret < 0) { elog(ERROR, "Error computing path: %s", err_msg); } DBG("SIZE %i\n",*path_count); DBG("ret = %i\n",ret); //:::::::::::::::::::::::::::::::: //:: 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; } profstop("astar", prof_astar); profstart(prof_store); return finish(SPIcode, ret); } PG_FUNCTION_INFO_V1(shortest_path_astar); Datum shortest_path_astar(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_shortest_path_astar(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); 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 */ DBG("Strange stuff doing\n"); 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] = ' '; DBG("Heap making\n"); tuple = heap_formtuple(tuple_desc, values, nulls); DBG("Datum making\n"); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); DBG("Trying to free some memory\n"); /* 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 SRF_RETURN_DONE(funcctx); } }
/* Clause 3.3.1.3 */ Datum MarketWatchFrame1(PG_FUNCTION_ARGS) { int i; int status = 0; double old_mkt_cap = 0.0; double new_mkt_cap = 0.0; double pct_change = 0.0; struct pg_tm tt, *tm = &tt; int64 acct_id = PG_GETARG_INT64(0); int64 cust_id = PG_GETARG_INT64(1); int64 ending_co_id = PG_GETARG_INT64(2); char *industry_name_p = (char *) PG_GETARG_TEXT_P(3); DateADT start_date_p = PG_GETARG_DATEADT(4); int64 starting_co_id = PG_GETARG_INT64(5); int ret; TupleDesc tupdesc; SPITupleTable *tuptable = NULL; HeapTuple tuple = NULL; Datum result; char buf[MAXDATELEN + 1]; char industry_name[IN_NAME_LEN + 1]; char sql[2048] = ""; j2date(start_date_p + POSTGRES_EPOCH_JDATE, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); EncodeDateOnly(tm, DateStyle, buf); strcpy(industry_name, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(industry_name_p)))); #ifdef DEBUG dump_mwf1_inputs(acct_id, cust_id, ending_co_id, industry_name, buf, starting_co_id); #endif SPI_connect(); if (cust_id != 0) { sprintf(sql, MWF1_1, cust_id); } else if (industry_name[0] != '\0') { sprintf(sql, MWF1_2, industry_name, starting_co_id, ending_co_id); } else if (acct_id != 0) { sprintf(sql, MWF1_3, acct_id); } else { status = BAD_INPUT_DATA; } #ifdef DEBUG elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_exec(sql, 0); if (ret != SPI_OK_SELECT) { dump_mwf1_inputs(acct_id, cust_id, ending_co_id, industry_name, buf, starting_co_id); FAIL_FRAME(sql); } if (status != BAD_INPUT_DATA) { int count = SPI_processed; TupleDesc tupdesc4; SPITupleTable *tuptable4 = NULL; HeapTuple tuple4 = NULL; char *symbol; char *new_price; char *old_price; char *s_num_out; tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; for (i = 0; i < count; i++) { tuple = tuptable->vals[i]; symbol = SPI_getvalue(tuple, tupdesc, 1); #ifdef DEBUG elog(NOTICE, " symbol = '%s'", symbol); #endif /* DEBUG */ sprintf(sql, MWF1_4, symbol); #ifdef DEBUG elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_exec(sql, 0); if (ret != SPI_OK_SELECT || SPI_processed == 0) { dump_mwf1_inputs(acct_id, cust_id, ending_co_id, industry_name, buf, starting_co_id); FAIL_FRAME(sql); continue; } tupdesc4 = SPI_tuptable->tupdesc; tuptable4 = SPI_tuptable; tuple4 = tuptable4->vals[0]; new_price = SPI_getvalue(tuple4, tupdesc4, 1); #ifdef DEBUG elog(NOTICE, " new_price = %s", new_price); elog(NOTICE, " new_price = %f", atof(new_price)); #endif /* DEBUG */ sprintf(sql, MWF1_5, symbol); #ifdef DEBUG elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_exec(sql, 0); if (ret != SPI_OK_SELECT) { dump_mwf1_inputs(acct_id, cust_id, ending_co_id, industry_name, buf, starting_co_id); elog(NOTICE, "ERROR: sql not ok = %d", ret); } tupdesc4 = SPI_tuptable->tupdesc; tuptable4 = SPI_tuptable; tuple4 = tuptable4->vals[0]; s_num_out = SPI_getvalue(tuple4, tupdesc4, 1); #ifdef DEBUG elog(NOTICE, " s_num_out = %s", s_num_out); #endif /* DEBUG */ sprintf(sql, MWF1_6, symbol, pstrdup(buf)); #ifdef DEBUG elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_exec(sql, 0); if (ret != SPI_OK_SELECT) { dump_mwf1_inputs(acct_id, cust_id, ending_co_id, industry_name, buf, starting_co_id); FAIL_FRAME(sql); } if (SPI_processed == 0) { elog(NOTICE, "No rows returned for getting old_price."); } else { tupdesc4 = SPI_tuptable->tupdesc; tuptable4 = SPI_tuptable; tuple4 = tuptable4->vals[0]; old_price = SPI_getvalue(tuple4, tupdesc4, 1); #ifdef DEBUG elog(NOTICE, " old_price = %s", old_price); elog(NOTICE, " old_price = %f", atof(old_price)); #endif /* DEBUG */ old_mkt_cap += atof(s_num_out) * atof(old_price); } new_mkt_cap += atof(s_num_out) * atof(new_price); #ifdef DEBUG elog(NOTICE, "old_mkt_cap = %f", old_mkt_cap); elog(NOTICE, "new_mkt_cap = %f", new_mkt_cap); #endif /* DEBUG */ } pct_change = 100.0 * (new_mkt_cap / old_mkt_cap - 1.0); #ifdef DEBUG elog(NOTICE, "pct_change = %f", pct_change); #endif /* DEBUG */ } #ifdef DEBUG elog(NOTICE, "MWF1 OUT: 1 %f", pct_change); #endif /* DEBUG */ SPI_finish(); result = DirectFunctionCall1(float8_numeric, Float8GetDatum(pct_change)); PG_RETURN_NUMERIC(result); }
Datum formatter_import(PG_FUNCTION_ARGS) { HeapTuple tuple; TupleDesc tupdesc; MemoryContext m, oldcontext; format_t *myData; char *data_buf; int ncolumns = 0; int data_cur; int data_len; int i; /* Must be called via the external table format manager */ if (!CALLED_AS_FORMATTER(fcinfo)) elog(ERROR, "formatter_import: not called by format manager"); tupdesc = FORMATTER_GET_TUPDESC(fcinfo); /* Get our internal description of the formatter */ ncolumns = tupdesc->natts; myData = (format_t *) FORMATTER_GET_USER_CTX(fcinfo); if (myData == NULL) { myData = palloc(sizeof(format_t)); myData->ncols = ncolumns; myData->values = palloc(sizeof(Datum) * ncolumns); myData->nulls = palloc(sizeof(bool) * ncolumns); /* misc verification */ for (i = 0; i < ncolumns; i++) { Oid type = tupdesc->attrs[i]->atttypid; //int32 typmod = tupdesc->attrs[i]->atttypmod; /* Don't know how to format dropped columns, error for now */ if (tupdesc->attrs[i]->attisdropped) elog(ERROR, "formatter_import: dropped columns"); switch (type) { case FLOAT8OID: case VARCHAROID: case BPCHAROID: case TEXTOID: break; default: { elog(ERROR, "formatter_import error: unsupported data type"); break; } } } FORMATTER_SET_USER_CTX(fcinfo, myData); } if (myData->ncols != ncolumns) elog(ERROR, "formatter_import: unexpected change of output record type"); /* get our input data buf and number of valid bytes in it */ data_buf = FORMATTER_GET_DATABUF(fcinfo); data_len = FORMATTER_GET_DATALEN(fcinfo); data_cur = FORMATTER_GET_DATACURSOR(fcinfo); /* start clean */ MemSet(myData->values, 0, ncolumns * sizeof(Datum)); MemSet(myData->nulls, true, ncolumns * sizeof(bool)); /* ======================================================================= * MAIN FORMATTING CODE * * Currently this code assumes: * - Homogoneos hardware => No need to convert data to network byte order * - Support for TEXT/VARCHAR/BPCHAR/FLOAT8 only * - Length Prefixed strings * - No end of record tags, checksums, or optimizations for alignment. * - NULL values are cast to some sensible default value (NaN, "") * * ======================================================================= */ m = FORMATTER_GET_PER_ROW_MEM_CTX(fcinfo); oldcontext = MemoryContextSwitchTo(m); for (i = 0; i < ncolumns; i++) { Oid type = tupdesc->attrs[i]->atttypid; //int typmod = tupdesc->attrs[i]->atttypmod; int remaining = 0; int attr_len = 0; remaining = data_len - data_cur; switch (type) { case FLOAT8OID: { float8 value; attr_len = sizeof(value); if (remaining < attr_len) { MemoryContextSwitchTo(oldcontext); FORMATTER_RETURN_NOTIFICATION(fcinfo, FMT_NEED_MORE_DATA); } memcpy(&value, data_buf + data_cur, attr_len); if(value != NULL_FLOAT8_VALUE) { myData->nulls[i] = false; myData->values[i] = Float8GetDatum(value); } /* TODO: check for nan? */ break; } case TEXTOID: case VARCHAROID: case BPCHAROID: { text* value; int32 len; bool nextlen = remaining >= sizeof(len); if (nextlen) memcpy(&len, data_buf + data_cur, sizeof(len)); /* if len or data bytes don't exist in this buffer, return */ if (!nextlen || (nextlen && (remaining - sizeof(len) < len))) { MemoryContextSwitchTo(oldcontext); FORMATTER_RETURN_NOTIFICATION(fcinfo, FMT_NEED_MORE_DATA); } if (len > 0) { value = (text *) palloc(len + VARHDRSZ); SET_VARSIZE(value, len + VARHDRSZ); memcpy(VARDATA(value), data_buf + data_cur + sizeof(len), len); myData->nulls[i] = false; myData->values[i] = PointerGetDatum(value); } attr_len = len + sizeof(len); break; } default: elog(ERROR, "formatter_import: unsupported datatype"); break; } /* add byte length of last attribute to the temporary cursor */ data_cur += attr_len; } /* ======================================================================= */ MemoryContextSwitchTo(oldcontext); FORMATTER_SET_DATACURSOR(fcinfo, data_cur); tuple = heap_form_tuple(tupdesc, myData->values, myData->nulls); /* hack... pass tuple here. don't free prev tuple - the executor does it */ ((FormatterData*) fcinfo->context)->fmt_tuple = tuple; FORMATTER_RETURN_TUPLE(tuple); }
Datum #else // _MSC_VER PGDLLEXPORT Datum #endif one_to_one_dijkstra(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; uint32_t call_cntr; uint32_t max_calls; TupleDesc tuple_desc; /**************************************************************************/ /* MODIFY AS NEEDED */ /* */ General_path_element_t *result_tuples = 0; size_t result_count = 0; /* */ /**************************************************************************/ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /**********************************************************************/ /* MODIFY AS NEEDED */ // CREATE OR REPLACE FUNCTION pgr_dijkstra( // sql text, start_vids BIGINT, // end_vid BIGINT, // directed BOOLEAN default true, PGR_DBG("Calling process"); process( pgr_text2char(PG_GETARG_TEXT_P(0)), PG_GETARG_INT64(1), PG_GETARG_INT64(2), PG_GETARG_BOOL(3), PG_GETARG_BOOL(4), &result_tuples, &result_count); /* */ /**********************************************************************/ funcctx->max_calls = (uint32_t)result_count; funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); } funcctx->tuple_desc = tuple_desc; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; tuple_desc = funcctx->tuple_desc; result_tuples = (General_path_element_t*) funcctx->user_fctx; if (call_cntr < max_calls) { HeapTuple tuple; Datum result; Datum *values; bool* nulls; /**********************************************************************/ /* MODIFY AS NEEDED */ // OUT seq INTEGER, // OUT path_seq INTEGER, // OUT node BIGINT, // OUT edge BIGINT, // OUT cost FLOAT, // OUT agg_cost FLOAT values = palloc(6 * sizeof(Datum)); nulls = palloc(6 * sizeof(bool)); size_t i; for (i = 0; i < 6; ++i) { nulls[i] = false; } // postgres starts counting from 1 values[0] = Int32GetDatum(call_cntr + 1); values[1] = Int32GetDatum(result_tuples[call_cntr].seq); values[2] = Int64GetDatum(result_tuples[call_cntr].node); values[3] = Int64GetDatum(result_tuples[call_cntr].edge); values[4] = Float8GetDatum(result_tuples[call_cntr].cost); values[5] = Float8GetDatum(result_tuples[call_cntr].agg_cost); /**********************************************************************/ tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { // cleanup if (result_tuples) free(result_tuples); SRF_RETURN_DONE(funcctx); } }
Datum normal_rand(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; normal_rand_fctx *fctx; float8 mean; float8 stddev; float8 carry_val; bool use_carry; MemoryContext oldcontext; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { /* 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); /* total number of tuples to be returned */ funcctx->max_calls = PG_GETARG_UINT32(0); /* allocate memory for user context */ fctx = (normal_rand_fctx *) palloc(sizeof(normal_rand_fctx)); /* * Use fctx to keep track of upper and lower bounds from call to call. * It will also be used to carry over the spare value we get from the * Box-Muller algorithm so that we only actually calculate a new value * every other call. */ fctx->mean = PG_GETARG_FLOAT8(1); fctx->stddev = PG_GETARG_FLOAT8(2); fctx->carry_val = 0; fctx->use_carry = false; funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; fctx = funcctx->user_fctx; mean = fctx->mean; stddev = fctx->stddev; carry_val = fctx->carry_val; use_carry = fctx->use_carry; if (call_cntr < max_calls) /* do when there is more left to send */ { float8 result; if (use_carry) { /* * reset use_carry and use second value obtained on last pass */ fctx->use_carry = false; result = carry_val; } else { float8 normval_1; float8 normval_2; /* Get the next two normal values */ get_normal_pair(&normval_1, &normval_2); /* use the first */ result = mean + (stddev * normval_1); /* and save the second */ fctx->carry_val = mean + (stddev * normval_2); fctx->use_carry = true; } /* send the result */ SRF_RETURN_NEXT(funcctx, Float8GetDatum(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); } }