Datum pg_stat_get_archiver(PG_FUNCTION_ARGS) { TupleDesc tupdesc; Datum values[7]; bool nulls[7]; PgStat_ArchiverStats *archiver_stats; /* Initialise values and NULL flags arrays */ MemSet(values, 0, sizeof(values)); MemSet(nulls, 0, sizeof(nulls)); /* Initialise attributes information in the tuple descriptor */ tupdesc = CreateTemplateTupleDesc(7, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset", TIMESTAMPTZOID, -1, 0); BlessTupleDesc(tupdesc); /* Get statistics about the archiver process */ archiver_stats = pgstat_fetch_stat_archiver(); /* Fill values and NULLs */ values[0] = Int64GetDatum(archiver_stats->archived_count); if (*(archiver_stats->last_archived_wal) == '\0') nulls[1] = true; else values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal); if (archiver_stats->last_archived_timestamp == 0) nulls[2] = true; else values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp); values[3] = Int64GetDatum(archiver_stats->failed_count); if (*(archiver_stats->last_failed_wal) == '\0') nulls[4] = true; else values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal); if (archiver_stats->last_failed_timestamp == 0) nulls[5] = true; else values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp); if (archiver_stats->stat_reset_timestamp == 0) nulls[6] = true; else values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp); /* Returns the record as Datum */ PG_RETURN_DATUM(HeapTupleGetDatum( heap_form_tuple(tupdesc, values, nulls))); }
Datum pg_buffercache_pages(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; Datum result; MemoryContext oldcontext; BufferCachePagesContext *fctx; /* User function context. */ TupleDesc tupledesc; TupleDesc expected_tupledesc; HeapTuple tuple; if (SRF_IS_FIRSTCALL()) { int i; funcctx = SRF_FIRSTCALL_INIT(); /* Switch context when allocating stuff to be used in later calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* Create a user function context for cross-call persistence */ fctx = (BufferCachePagesContext *) palloc(sizeof(BufferCachePagesContext)); /* * To smoothly support upgrades from version 1.0 of this extension * transparently handle the (non-)existence of the pinning_backends * column. We unfortunately have to get the result type for that... - * we can't use the result type determined by the function definition * without potentially crashing when somebody uses the old (or even * wrong) function definition though. */ if (get_call_result_type(fcinfo, NULL, &expected_tupledesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); if (expected_tupledesc->natts < NUM_BUFFERCACHE_PAGES_MIN_ELEM || expected_tupledesc->natts > NUM_BUFFERCACHE_PAGES_ELEM) elog(ERROR, "incorrect number of output arguments"); /* Construct a tuple descriptor for the result rows. */ tupledesc = CreateTemplateTupleDesc(expected_tupledesc->natts, false); TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid", INT4OID, -1, 0); TupleDescInitEntry(tupledesc, (AttrNumber) 2, "relfilenode", OIDOID, -1, 0); TupleDescInitEntry(tupledesc, (AttrNumber) 3, "reltablespace", OIDOID, -1, 0); TupleDescInitEntry(tupledesc, (AttrNumber) 4, "reldatabase", OIDOID, -1, 0); TupleDescInitEntry(tupledesc, (AttrNumber) 5, "relforknumber", INT2OID, -1, 0); TupleDescInitEntry(tupledesc, (AttrNumber) 6, "relblocknumber", INT8OID, -1, 0); TupleDescInitEntry(tupledesc, (AttrNumber) 7, "isdirty", BOOLOID, -1, 0); TupleDescInitEntry(tupledesc, (AttrNumber) 8, "usage_count", INT2OID, -1, 0); if (expected_tupledesc->natts == NUM_BUFFERCACHE_PAGES_ELEM) TupleDescInitEntry(tupledesc, (AttrNumber) 9, "pinning_backends", INT4OID, -1, 0); fctx->tupdesc = BlessTupleDesc(tupledesc); /* Allocate NBuffers worth of BufferCachePagesRec records. */ fctx->record = (BufferCachePagesRec *) MemoryContextAllocHuge(CurrentMemoryContext, sizeof(BufferCachePagesRec) * NBuffers); /* Set max calls and remember the user function context. */ funcctx->max_calls = NBuffers; funcctx->user_fctx = fctx; /* Return to original context when allocating transient memory */ MemoryContextSwitchTo(oldcontext); /* * Scan through all the buffers, saving the relevant fields in the * fctx->record structure. * * We don't hold the partition locks, so we don't get a consistent * snapshot across all buffers, but we do grab the buffer header * locks, so the information of each buffer is self-consistent. */ for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; uint32 buf_state; bufHdr = GetBufferDescriptor(i); /* Lock each buffer header before inspecting. */ buf_state = LockBufHdr(bufHdr); fctx->record[i].bufferid = BufferDescriptorGetBuffer(bufHdr); fctx->record[i].relfilenode = bufHdr->tag.rnode.relNode; fctx->record[i].reltablespace = bufHdr->tag.rnode.spcNode; fctx->record[i].reldatabase = bufHdr->tag.rnode.dbNode; fctx->record[i].forknum = bufHdr->tag.forkNum; fctx->record[i].blocknum = bufHdr->tag.blockNum; fctx->record[i].usagecount = BUF_STATE_GET_USAGECOUNT(buf_state); fctx->record[i].pinning_backends = BUF_STATE_GET_REFCOUNT(buf_state); if (buf_state & BM_DIRTY) fctx->record[i].isdirty = true; else fctx->record[i].isdirty = false; /* Note if the buffer is valid, and has storage created */ if ((buf_state & BM_VALID) && (buf_state & BM_TAG_VALID)) fctx->record[i].isvalid = true; else fctx->record[i].isvalid = false; UnlockBufHdr(bufHdr, buf_state); } } funcctx = SRF_PERCALL_SETUP(); /* Get the saved state */ fctx = funcctx->user_fctx; if (funcctx->call_cntr < funcctx->max_calls) { uint32 i = funcctx->call_cntr; Datum values[NUM_BUFFERCACHE_PAGES_ELEM]; bool nulls[NUM_BUFFERCACHE_PAGES_ELEM]; values[0] = Int32GetDatum(fctx->record[i].bufferid); nulls[0] = false; /* * Set all fields except the bufferid to null if the buffer is unused * or not valid. */ if (fctx->record[i].blocknum == InvalidBlockNumber || fctx->record[i].isvalid == false) { nulls[1] = true; nulls[2] = true; nulls[3] = true; nulls[4] = true; nulls[5] = true; nulls[6] = true; nulls[7] = true; /* unused for v1.0 callers, but the array is always long enough */ nulls[8] = true; } else { values[1] = ObjectIdGetDatum(fctx->record[i].relfilenode); nulls[1] = false; values[2] = ObjectIdGetDatum(fctx->record[i].reltablespace); nulls[2] = false; values[3] = ObjectIdGetDatum(fctx->record[i].reldatabase); nulls[3] = false; values[4] = ObjectIdGetDatum(fctx->record[i].forknum); nulls[4] = false; values[5] = Int64GetDatum((int64) fctx->record[i].blocknum); nulls[5] = false; values[6] = BoolGetDatum(fctx->record[i].isdirty); nulls[6] = false; values[7] = Int16GetDatum(fctx->record[i].usagecount); nulls[7] = false; /* unused for v1.0 callers, but the array is always long enough */ values[8] = Int32GetDatum(fctx->record[i].pinning_backends); nulls[8] = false; } /* Build and return the tuple. */ tuple = heap_form_tuple(fctx->tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else SRF_RETURN_DONE(funcctx); }
/* ------------------------------------------------ * bt_metap() * * Get a btree's meta-page information * * Usage: SELECT * FROM bt_metap('t1_pkey') * ------------------------------------------------ */ Datum bt_metap(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_PP(0); Datum result; Relation rel; RangeVar *relrv; BTMetaPageData *metad; TupleDesc tupleDesc; int j; char *values[8]; Buffer buffer; Page page; HeapTuple tuple; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pageinspect functions")))); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = relation_openrv(relrv, AccessShareLock); if (!IS_INDEX(rel) || !IS_BTREE(rel)) elog(ERROR, "relation \"%s\" is not a btree index", RelationGetRelationName(rel)); /* * 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 (RELATION_IS_OTHER_TEMP(rel)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); buffer = ReadBuffer(rel, 0); LockBuffer(buffer, BUFFER_LOCK_SHARE); page = BufferGetPage(buffer); metad = BTPageGetMeta(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"); j = 0; values[j++] = psprintf("%d", metad->btm_magic); values[j++] = psprintf("%d", metad->btm_version); values[j++] = psprintf("%d", metad->btm_root); values[j++] = psprintf("%d", metad->btm_level); values[j++] = psprintf("%d", metad->btm_fastroot); values[j++] = psprintf("%d", metad->btm_fastlevel); /* * Get values of extended metadata if available, use default values * otherwise. */ if (metad->btm_version >= BTREE_NOVAC_VERSION) { values[j++] = psprintf("%u", metad->btm_oldest_btpo_xact); values[j++] = psprintf("%f", metad->btm_last_cleanup_num_heap_tuples); } else { values[j++] = "0"; values[j++] = "-1"; } tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); result = HeapTupleGetDatum(tuple); UnlockReleaseBuffer(buffer); relation_close(rel, AccessShareLock); PG_RETURN_DATUM(result); }
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 #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); } }
/* Function to return the list of grammar keywords */ Datum pg_get_keywords(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; TupleDesc tupdesc; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); tupdesc = CreateTemplateTupleDesc(3, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode", CHAROID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc", TEXTOID, -1, 0); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); if (funcctx->call_cntr < NumScanKeywords) { char *values[3]; HeapTuple tuple; /* cast-away-const is ugly but alternatives aren't much better */ values[0] = (char *) ScanKeywords[funcctx->call_cntr].name; switch (ScanKeywords[funcctx->call_cntr].category) { case UNRESERVED_KEYWORD: values[1] = "U"; values[2] = _("unreserved"); break; case COL_NAME_KEYWORD: values[1] = "C"; values[2] = _("unreserved (cannot be function or type name)"); break; case TYPE_FUNC_NAME_KEYWORD: values[1] = "T"; values[2] = _("reserved (can be function or type name)"); break; case RESERVED_KEYWORD: values[1] = "R"; values[2] = _("reserved"); break; default: /* shouldn't be possible */ values[1] = NULL; values[2] = NULL; break; } tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); } SRF_RETURN_DONE(funcctx); }
Datum pg_stat_get_activity(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; TupleDesc tupdesc; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); tupdesc = CreateTemplateTupleDesc(12, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid", OIDOID, -1, 0); /* This should have been called 'pid'; can't change it. 2011-06-11 */ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "procpid", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "usesysid", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "application_name", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "current_query", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "waiting", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 7, "act_start", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 8, "query_start", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 9, "backend_start", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 10, "client_addr", INETOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 11, "client_hostname", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 12, "client_port", INT4OID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); funcctx->user_fctx = palloc0(sizeof(int)); if (PG_ARGISNULL(0)) { /* Get all backends */ funcctx->max_calls = pgstat_fetch_stat_numbackends(); } else { /* * Get one backend - locate by pid. * * We lookup the backend early, so we can return zero rows if it * doesn't exist, instead of returning a single row full of NULLs. */ int pid = PG_GETARG_INT32(0); int i; int n = pgstat_fetch_stat_numbackends(); for (i = 1; i <= n; i++) { PgBackendStatus *be = pgstat_fetch_stat_beentry(i); if (be) { if (be->st_procpid == pid) { *(int *) (funcctx->user_fctx) = i; break; } } } if (*(int *) (funcctx->user_fctx) == 0) /* Pid not found, return zero rows */ funcctx->max_calls = 0; else funcctx->max_calls = 1; } MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); if (funcctx->call_cntr < funcctx->max_calls) { /* for each row */ Datum values[12]; bool nulls[12]; HeapTuple tuple; PgBackendStatus *beentry; SockAddr zero_clientaddr; MemSet(values, 0, sizeof(values)); MemSet(nulls, 0, sizeof(nulls)); if (*(int *) (funcctx->user_fctx) > 0) { /* Get specific pid slot */ beentry = pgstat_fetch_stat_beentry(*(int *) (funcctx->user_fctx)); } else { /* Get the next one in the list */ beentry = pgstat_fetch_stat_beentry(funcctx->call_cntr + 1); /* 1-based index */ } if (!beentry) { int i; for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++) nulls[i] = true; nulls[4] = false; values[4] = CStringGetTextDatum("<backend information not available>"); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); } /* Values available to all callers */ values[0] = ObjectIdGetDatum(beentry->st_databaseid); values[1] = Int32GetDatum(beentry->st_procpid); values[2] = ObjectIdGetDatum(beentry->st_userid); if (beentry->st_appname) values[3] = CStringGetTextDatum(beentry->st_appname); else nulls[3] = true; /* Values only available to same user or superuser */ if (superuser() || beentry->st_userid == GetUserId()) { if (*(beentry->st_activity) == '\0') { values[4] = CStringGetTextDatum("<command string not enabled>"); } else { values[4] = CStringGetTextDatum(beentry->st_activity); } values[5] = BoolGetDatum(beentry->st_waiting); if (beentry->st_xact_start_timestamp != 0) values[6] = TimestampTzGetDatum(beentry->st_xact_start_timestamp); else nulls[6] = true; if (beentry->st_activity_start_timestamp != 0) values[7] = TimestampTzGetDatum(beentry->st_activity_start_timestamp); else nulls[7] = true; if (beentry->st_proc_start_timestamp != 0) values[8] = TimestampTzGetDatum(beentry->st_proc_start_timestamp); else nulls[8] = true; /* A zeroed client addr means we don't know */ memset(&zero_clientaddr, 0, sizeof(zero_clientaddr)); if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr, sizeof(zero_clientaddr) == 0)) { nulls[9] = true; nulls[10] = true; nulls[11] = true; } else { if (beentry->st_clientaddr.addr.ss_family == AF_INET #ifdef HAVE_IPV6 || beentry->st_clientaddr.addr.ss_family == AF_INET6 #endif ) { char remote_host[NI_MAXHOST]; char remote_port[NI_MAXSERV]; int ret; remote_host[0] = '\0'; remote_port[0] = '\0'; ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr, beentry->st_clientaddr.salen, remote_host, sizeof(remote_host), remote_port, sizeof(remote_port), NI_NUMERICHOST | NI_NUMERICSERV); if (ret == 0) { clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host); values[9] = DirectFunctionCall1(inet_in, CStringGetDatum(remote_host)); if (beentry->st_clienthostname) values[10] = CStringGetTextDatum(beentry->st_clienthostname); else nulls[10] = true; values[11] = Int32GetDatum(atoi(remote_port)); } else { nulls[9] = true; nulls[10] = true; nulls[11] = true; } } else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX) { /* * Unix sockets always reports NULL for host and -1 for * port, so it's possible to tell the difference to * connections we have no permissions to view, or with * errors. */ nulls[9] = true; nulls[10] = true; values[11] = DatumGetInt32(-1); } else { /* Unknown address type, should never happen */ nulls[9] = true; nulls[10] = true; nulls[11] = true; } } } else { /* No permissions to view data about this session */ values[4] = CStringGetTextDatum("<insufficient privilege>"); nulls[5] = true; nulls[6] = true; nulls[7] = true; nulls[8] = true; nulls[9] = true; nulls[10] = true; nulls[11] = true; } tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); } else { /* nothing left */ SRF_RETURN_DONE(funcctx); } }
/* * pgdatabasev - produce a view of gp_distributed_xacts to include transient state */ Datum gp_distributed_xacts__(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TMGALLXACTSTATUS *allDistributedXactStatus; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext oldcontext; /* 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); /* build tupdesc for result tuples */ /* this had better match gp_distributed_xacts view in system_views.sql */ tupdesc = CreateTemplateTupleDesc(5, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "distributed_xid", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "distributed_id", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "state", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "gp_session_id", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "xmin_distributed_snapshot", XIDOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* * Collect all the locking information that we will format and * send out as a result set. */ getAllDistributedXactStatus(&allDistributedXactStatus); funcctx->user_fctx = (void *) allDistributedXactStatus; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); allDistributedXactStatus = (TMGALLXACTSTATUS *) funcctx->user_fctx; while (true) { TMGXACTSTATUS *distributedXactStatus; Datum values[6]; bool nulls[6]; HeapTuple tuple; Datum result; if (!getNextDistributedXactStatus(allDistributedXactStatus, &distributedXactStatus)) break; /* * Form tuple with appropriate data. */ MemSet(values, 0, sizeof(values)); MemSet(nulls, false, sizeof(nulls)); values[0] = TransactionIdGetDatum(distributedXactStatus->gxid); values[1] = DirectFunctionCall1(textin, CStringGetDatum(distributedXactStatus->gid)); values[2] = DirectFunctionCall1(textin, CStringGetDatum(DtxStateToString(distributedXactStatus->state))); values[3] = UInt32GetDatum(distributedXactStatus->sessionId); values[4] = TransactionIdGetDatum(distributedXactStatus->xminDistributedSnapshot); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } SRF_RETURN_DONE(funcctx); }
/* * pg_lock_status - produce a view with one row per held or awaited lock mode */ Datum pg_lock_status(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; PG_Lock_Status *mystatus; LockData *lockData; PredicateLockData *predLockData; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext oldcontext; /* 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); /* build tupdesc for result tuples */ /* this had better match pg_locks view in system_views.sql */ tupdesc = CreateTemplateTupleDesc(14, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple", INT2OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid", INT2OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted", BOOLOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* * Collect all the locking information that we will format and send * out as a result set. */ mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status)); funcctx->user_fctx = (void *) mystatus; mystatus->lockData = GetLockStatusData(); mystatus->currIdx = 0; mystatus->predLockData = GetPredicateLockStatusData(); mystatus->predLockIdx = 0; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); mystatus = (PG_Lock_Status *) funcctx->user_fctx; lockData = mystatus->lockData; while (mystatus->currIdx < lockData->nelements) { PROCLOCK *proclock; LOCK *lock; PGPROC *proc; bool granted; LOCKMODE mode = 0; const char *locktypename; char tnbuf[32]; Datum values[14]; bool nulls[14]; HeapTuple tuple; Datum result; proclock = &(lockData->proclocks[mystatus->currIdx]); lock = &(lockData->locks[mystatus->currIdx]); proc = &(lockData->procs[mystatus->currIdx]); /* * Look to see if there are any held lock modes in this PROCLOCK. If * so, report, and destructively modify lockData so we don't report * again. */ granted = false; if (proclock->holdMask) { for (mode = 0; mode < MAX_LOCKMODES; mode++) { if (proclock->holdMask & LOCKBIT_ON(mode)) { granted = true; proclock->holdMask &= LOCKBIT_OFF(mode); break; } } } /* * If no (more) held modes to report, see if PROC is waiting for a * lock on this lock. */ if (!granted) { if (proc->waitLock == proclock->tag.myLock) { /* Yes, so report it with proper mode */ mode = proc->waitLockMode; /* * We are now done with this PROCLOCK, so advance pointer to * continue with next one on next call. */ mystatus->currIdx++; } else { /* * Okay, we've displayed all the locks associated with this * PROCLOCK, proceed to the next one. */ mystatus->currIdx++; continue; } } /* * Form tuple with appropriate data. */ MemSet(values, 0, sizeof(values)); MemSet(nulls, false, sizeof(nulls)); if (lock->tag.locktag_type <= LOCKTAG_LAST_TYPE) locktypename = LockTagTypeNames[lock->tag.locktag_type]; else { snprintf(tnbuf, sizeof(tnbuf), "unknown %d", (int) lock->tag.locktag_type); locktypename = tnbuf; } values[0] = CStringGetTextDatum(locktypename); switch ((LockTagType) lock->tag.locktag_type) { case LOCKTAG_RELATION: case LOCKTAG_RELATION_EXTEND: values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); values[2] = ObjectIdGetDatum(lock->tag.locktag_field2); nulls[3] = true; nulls[4] = true; nulls[5] = true; nulls[6] = true; nulls[7] = true; nulls[8] = true; nulls[9] = true; break; case LOCKTAG_PAGE: values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); values[2] = ObjectIdGetDatum(lock->tag.locktag_field2); values[3] = UInt32GetDatum(lock->tag.locktag_field3); nulls[4] = true; nulls[5] = true; nulls[6] = true; nulls[7] = true; nulls[8] = true; nulls[9] = true; break; case LOCKTAG_TUPLE: values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); values[2] = ObjectIdGetDatum(lock->tag.locktag_field2); values[3] = UInt32GetDatum(lock->tag.locktag_field3); values[4] = UInt16GetDatum(lock->tag.locktag_field4); nulls[5] = true; nulls[6] = true; nulls[7] = true; nulls[8] = true; nulls[9] = true; break; case LOCKTAG_TRANSACTION: values[6] = TransactionIdGetDatum(lock->tag.locktag_field1); nulls[1] = true; nulls[2] = true; nulls[3] = true; nulls[4] = true; nulls[5] = true; nulls[7] = true; nulls[8] = true; nulls[9] = true; break; case LOCKTAG_VIRTUALTRANSACTION: values[5] = VXIDGetDatum(lock->tag.locktag_field1, lock->tag.locktag_field2); nulls[1] = true; nulls[2] = true; nulls[3] = true; nulls[4] = true; nulls[6] = true; nulls[7] = true; nulls[8] = true; nulls[9] = true; break; case LOCKTAG_OBJECT: case LOCKTAG_USERLOCK: case LOCKTAG_ADVISORY: default: /* treat unknown locktags like OBJECT */ values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); values[7] = ObjectIdGetDatum(lock->tag.locktag_field2); values[8] = ObjectIdGetDatum(lock->tag.locktag_field3); values[9] = Int16GetDatum(lock->tag.locktag_field4); nulls[2] = true; nulls[3] = true; nulls[4] = true; nulls[5] = true; nulls[6] = true; break; } values[10] = VXIDGetDatum(proc->backendId, proc->lxid); if (proc->pid != 0) values[11] = Int32GetDatum(proc->pid); else nulls[11] = true; values[12] = CStringGetTextDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock), mode)); values[13] = BoolGetDatum(granted); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } /* * Have returned all regular locks. Now start on the SIREAD predicate * locks. */ predLockData = mystatus->predLockData; if (mystatus->predLockIdx < predLockData->nelements) { PredicateLockTargetType lockType; PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]); SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]); Datum values[14]; bool nulls[14]; HeapTuple tuple; Datum result; mystatus->predLockIdx++; /* * Form tuple with appropriate data. */ MemSet(values, 0, sizeof(values)); MemSet(nulls, false, sizeof(nulls)); /* lock type */ lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag); values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]); /* lock target */ values[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag); values[2] = GET_PREDICATELOCKTARGETTAG_RELATION(*predTag); if (lockType == PREDLOCKTAG_TUPLE) values[4] = GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag); else nulls[4] = true; if ((lockType == PREDLOCKTAG_TUPLE) || (lockType == PREDLOCKTAG_PAGE)) values[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag); else nulls[3] = true; /* these fields are targets for other types of locks */ nulls[5] = true; /* virtualxid */ nulls[6] = true; /* transactionid */ nulls[7] = true; /* classid */ nulls[8] = true; /* objid */ nulls[9] = true; /* objsubid */ /* lock holder */ values[10] = VXIDGetDatum(xact->vxid.backendId, xact->vxid.localTransactionId); if (xact->pid != 0) values[11] = Int32GetDatum(xact->pid); else nulls[11] = true; /* * Lock mode. Currently all predicate locks are SIReadLocks, which are * always held (never waiting) */ values[12] = CStringGetTextDatum("SIReadLock"); values[13] = BoolGetDatum(true); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } SRF_RETURN_DONE(funcctx); }
/* Clause 3.3.1.3 */ Datum BrokerVolumeFrame1(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; AttInMetadata *attinmeta; int call_cntr; int max_calls; int i; int ndim, nitems; int *dim; char *broker_list; char **values = NULL; /* Stuff done only on the first call of the function. */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; ArrayType *broker_list_p = PG_GETARG_ARRAYTYPE_P(0); text *sector_name_p = PG_GETARG_TEXT_P(1); enum bvf1 { i_broker_name=0, i_list_len, i_volume }; int16 typlen; bool typbyval; char typalign; int ret; TupleDesc tupdesc; SPITupleTable *tuptable = NULL; HeapTuple tuple = NULL; #ifdef DEBUG char sql[2048]; #endif char broker_list_array[(B_NAME_LEN + 3) * 40 + 5] = "'{"; Datum args[2]; char nulls[2] = { ' ', ' ' }; /* * Prepare a values array for building the returned tuple. * This should be an array of C strings, which will * be processed later by the type input functions. */ values = (char **) palloc(sizeof(char *) * 3); values[i_list_len] = (char *) palloc((SMALLINT_LEN + 1) * sizeof(char)); /* * This might be overkill since we always expect single dimensions * arrays. */ ndim = ARR_NDIM(broker_list_p); dim = ARR_DIMS(broker_list_p); nitems = ArrayGetNItems(ndim, dim); get_typlenbyvalalign(ARR_ELEMTYPE(broker_list_p), &typlen, &typbyval, &typalign); broker_list = ARR_DATA_PTR(broker_list_p); /* Turn the broker_list input into an array format. */ if (nitems > 0) { strcat(broker_list_array, "\""); strcat(broker_list_array, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(broker_list)))); broker_list = att_addlength_pointer(broker_list, typlen, broker_list); broker_list = (char *) att_align_nominal(broker_list, typalign); strcat(broker_list_array, "\""); } for (i = 1; i < nitems; i++) { strcat(broker_list_array, ",\""); strcat(broker_list_array, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(broker_list)))); broker_list = att_addlength_pointer(broker_list, typlen, broker_list); broker_list = (char *) att_align_nominal(broker_list, typalign); strcat(broker_list_array, "\""); } strcat(broker_list_array, "}'"); #ifdef DEBUG dump_bvf1_inputs(broker_list_p, sector_name_p); #endif /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); funcctx->max_calls = 1; /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); SPI_connect(); plan_queries(BVF1_statements); #ifdef DEBUG sprintf(sql, SQLBVF1_1, broker_list_array, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(sector_name_p)))); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = PointerGetDatum(broker_list_p); args[1] = PointerGetDatum(sector_name_p); ret = SPI_execute_plan(BVF1_1, args, nulls, true, 0); if (ret == SPI_OK_SELECT) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; } else { dump_bvf1_inputs(broker_list_p, sector_name_p); FAIL_FRAME_SET(&funcctx->max_calls, BVF1_statements[0].sql); } sprintf(values[i_list_len], "%d", SPI_processed); values[i_broker_name] = (char *) palloc(((B_NAME_LEN + 2) * (SPI_processed + 1) + 3) * sizeof(char)); values[i_volume] = (char *) palloc((INTEGER_LEN * (SPI_processed + 1) + 3) * sizeof(char)); if (SPI_processed == 0) { strcpy(values[i_broker_name], "{}"); strcpy(values[i_volume], "{}"); } else { strcpy(values[i_broker_name], "{"); strcpy(values[i_volume], "{"); if (SPI_processed > 0) { strcat(values[i_broker_name], "\""); strcat(values[i_broker_name], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_broker_name], "\""); strcat(values[i_volume], SPI_getvalue(tuple, tupdesc, 2)); } for (i = 1; i < SPI_processed; i++) { tuple = tuptable->vals[i]; strcat(values[i_broker_name], ","); strcat(values[i_broker_name], "\""); strcat(values[i_broker_name], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_broker_name], "\""); strcat(values[i_volume], ","); strcat(values[i_volume], SPI_getvalue(tuple, tupdesc, 2)); } strcat(values[i_broker_name], "}"); strcat(values[i_volume], "}"); } /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); } /* * generate attribute metadata needed later to produce tuples from raw * C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) { /* do when there is more left to send */ HeapTuple tuple; Datum result; #ifdef DEBUG for (i = 0; i < 3; i++) { elog(NOTICE, "BVF1 OUT: %d %s", i, values[i]); } #endif /* DEBUG */ /* Build a tuple. */ tuple = BuildTupleFromCStrings(attinmeta, values); /* Make the tuple into a datum. */ result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { /* Do when there is no more left. */ SPI_finish(); SRF_RETURN_DONE(funcctx); } }
/** * @brief Entry point of the user-defined function for pg_bulkload. * @return Returns number of loaded tuples. If the case of errors, -1 will be * returned. */ Datum pg_bulkload(PG_FUNCTION_ARGS) { Reader *rd = NULL; Writer *wt = NULL; Datum options; MemoryContext ctx; MemoryContext ccxt; PGRUsage ru0; PGRUsage ru1; int64 count; int64 parse_errors; int64 skip; WriterResult ret; char *start; char *end; float8 system; float8 user; float8 duration; TupleDesc tupdesc; Datum values[PG_BULKLOAD_COLS]; bool nulls[PG_BULKLOAD_COLS]; HeapTuple result; /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); BULKLOAD_PROFILE_PUSH(); pg_rusage_init(&ru0); /* must be the super user */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use pg_bulkload"))); options = PG_GETARG_DATUM(0); ccxt = CurrentMemoryContext; /* * STEP 1: Initialization */ /* parse options and create reader and writer */ ParseOptions(options, &rd, &wt, ru0.tv.tv_sec); /* initialize reader */ ReaderInit(rd); /* * We need to split PG_TRY block because gcc optimizes if-branches with * longjmp codes too much. Local variables initialized in either branch * cannot be handled another branch. */ PG_TRY(); { /* truncate heap */ if (wt->truncate) TruncateTable(wt->relid); /* initialize writer */ WriterInit(wt); /* initialize checker */ CheckerInit(&rd->checker, wt->rel, wt->tchecker); /* initialize parser */ ParserInit(rd->parser, &rd->checker, rd->infile, wt->desc, wt->multi_process, PG_GET_COLLATION()); } PG_CATCH(); { if (rd) ReaderClose(rd, true); if (wt) WriterClose(wt, true); PG_RE_THROW(); } PG_END_TRY(); /* No throwable codes here! */ PG_TRY(); { /* create logger */ CreateLogger(rd->logfile, wt->verbose, rd->infile[0] == ':'); start = timeval_to_cstring(ru0.tv); LoggerLog(INFO, "\npg_bulkload %s on %s\n\n", PG_BULKLOAD_VERSION, start); ReaderDumpParams(rd); WriterDumpParams(wt); LoggerLog(INFO, "\n"); BULKLOAD_PROFILE(&prof_init); /* * STEP 2: Build heap */ /* Switch into its memory context */ Assert(wt->context); ctx = MemoryContextSwitchTo(wt->context); /* Loop for each input file record. */ while (wt->count < rd->limit) { HeapTuple tuple; CHECK_FOR_INTERRUPTS(); /* read tuple */ BULKLOAD_PROFILE_PUSH(); tuple = ReaderNext(rd); BULKLOAD_PROFILE_POP(); BULKLOAD_PROFILE(&prof_reader); if (tuple == NULL) break; /* write tuple */ BULKLOAD_PROFILE_PUSH(); WriterInsert(wt, tuple); wt->count += 1; BULKLOAD_PROFILE_POP(); BULKLOAD_PROFILE(&prof_writer); MemoryContextReset(wt->context); BULKLOAD_PROFILE(&prof_reset); } MemoryContextSwitchTo(ctx); /* * STEP 3: Finalize heap and merge indexes */ count = wt->count; parse_errors = rd->parse_errors; /* * close writer first and reader second because shmem_exit callback * is managed by a simple stack. */ ret = WriterClose(wt, false); wt = NULL; skip = ReaderClose(rd, false); rd = NULL; } PG_CATCH(); { ErrorData *errdata; MemoryContext ecxt; ecxt = MemoryContextSwitchTo(ccxt); errdata = CopyErrorData(); LoggerLog(INFO, "%s\n", errdata->message); FreeErrorData(errdata); /* close writer first, and reader second */ if (wt) WriterClose(wt, true); if (rd) ReaderClose(rd, true); MemoryContextSwitchTo(ecxt); PG_RE_THROW(); } PG_END_TRY(); count -= ret.num_dup_new; LoggerLog(INFO, "\n" " " int64_FMT " Rows skipped.\n" " " int64_FMT " Rows successfully loaded.\n" " " int64_FMT " Rows not loaded due to parse errors.\n" " " int64_FMT " Rows not loaded due to duplicate errors.\n" " " int64_FMT " Rows replaced with new rows.\n\n", skip, count, parse_errors, ret.num_dup_new, ret.num_dup_old); pg_rusage_init(&ru1); system = diffTime(ru1.ru.ru_stime, ru0.ru.ru_stime); user = diffTime(ru1.ru.ru_utime, ru0.ru.ru_utime); duration = diffTime(ru1.tv, ru0.tv); end = timeval_to_cstring(ru1.tv); memset(nulls, 0, sizeof(nulls)); values[0] = Int64GetDatum(skip); values[1] = Int64GetDatum(count); values[2] = Int64GetDatum(parse_errors); values[3] = Int64GetDatum(ret.num_dup_new); values[4] = Int64GetDatum(ret.num_dup_old); values[5] = Float8GetDatumFast(system); values[6] = Float8GetDatumFast(user); values[7] = Float8GetDatumFast(duration); LoggerLog(INFO, "Run began on %s\n" "Run ended on %s\n\n" "CPU %.2fs/%.2fu sec elapsed %.2f sec\n", start, end, system, user, duration); LoggerClose(); result = heap_form_tuple(tupdesc, values, nulls); BULKLOAD_PROFILE(&prof_fini); BULKLOAD_PROFILE_POP(); BULKLOAD_PROFILE_PRINT(); PG_RETURN_DATUM(HeapTupleGetDatum(result)); }
/* ------------------------------------------------------ * pgstatginindex() * * Usage: SELECT * FROM pgstatginindex('ginindex'); * ------------------------------------------------------ */ Datum pgstatginindex(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); Relation rel; Buffer buffer; Page page; GinMetaPageData *metadata; GinIndexStat stats; HeapTuple tuple; TupleDesc tupleDesc; Datum values[3]; bool nulls[3] = {false, false, false}; Datum result; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pgstattuple functions")))); rel = relation_open(relid, AccessShareLock); if (!IS_INDEX(rel) || !IS_GIN(rel)) elog(ERROR, "relation \"%s\" is not a GIN index", RelationGetRelationName(rel)); /* * 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 (RELATION_IS_OTHER_TEMP(rel)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary indexes of other sessions"))); /* * Read metapage */ buffer = ReadBuffer(rel, GIN_METAPAGE_BLKNO); LockBuffer(buffer, GIN_SHARE); page = BufferGetPage(buffer); metadata = GinPageGetMeta(page); stats.version = metadata->ginVersion; stats.pending_pages = metadata->nPendingPages; stats.pending_tuples = metadata->nPendingHeapTuples; UnlockReleaseBuffer(buffer); relation_close(rel, AccessShareLock); /* * 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"); values[0] = Int32GetDatum(stats.version); values[1] = UInt32GetDatum(stats.pending_pages); values[2] = Int64GetDatum(stats.pending_tuples); /* * Build and return the tuple */ tuple = heap_form_tuple(tupleDesc, values, nulls); result = HeapTupleGetDatum(tuple); PG_RETURN_DATUM(result); }
static Datum pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo) { Datum result; BlockNumber nblocks; BlockNumber blkno; BTIndexStat indexStat; BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD); if (!IS_INDEX(rel) || !IS_BTREE(rel)) elog(ERROR, "relation \"%s\" is not a btree index", RelationGetRelationName(rel)); /* * 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 (RELATION_IS_OTHER_TEMP(rel)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); /* * Read metapage */ { Buffer buffer = ReadBufferExtended(rel, MAIN_FORKNUM, 0, RBM_NORMAL, bstrategy); Page page = BufferGetPage(buffer); BTMetaPageData *metad = BTPageGetMeta(page); indexStat.version = metad->btm_version; indexStat.level = metad->btm_level; indexStat.root_blkno = metad->btm_root; ReleaseBuffer(buffer); } /* -- init counters -- */ indexStat.root_pages = 0; indexStat.internal_pages = 0; indexStat.leaf_pages = 0; indexStat.empty_pages = 0; indexStat.deleted_pages = 0; indexStat.max_avail = 0; indexStat.free_space = 0; indexStat.fragments = 0; /* * Scan all blocks except the metapage */ nblocks = RelationGetNumberOfBlocks(rel); for (blkno = 1; blkno < nblocks; blkno++) { Buffer buffer; Page page; BTPageOpaque opaque; CHECK_FOR_INTERRUPTS(); /* Read and lock buffer */ buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy); LockBuffer(buffer, BUFFER_LOCK_SHARE); page = BufferGetPage(buffer); opaque = (BTPageOpaque) PageGetSpecialPointer(page); /* Determine page type, and update totals */ if (P_ISLEAF(opaque)) { int max_avail; max_avail = BLCKSZ - (BLCKSZ - ((PageHeader) page)->pd_special + SizeOfPageHeaderData); indexStat.max_avail += max_avail; indexStat.free_space += PageGetFreeSpace(page); indexStat.leaf_pages++; /* * If the next leaf is on an earlier block, it means a * fragmentation. */ if (opaque->btpo_next != P_NONE && opaque->btpo_next < blkno) indexStat.fragments++; } else if (P_ISDELETED(opaque)) indexStat.deleted_pages++; else if (P_IGNORE(opaque)) indexStat.empty_pages++; else if (P_ISROOT(opaque)) indexStat.root_pages++; else indexStat.internal_pages++; /* Unlock and release buffer */ LockBuffer(buffer, BUFFER_LOCK_UNLOCK); ReleaseBuffer(buffer); } relation_close(rel, AccessShareLock); /*---------------------------- * Build a result tuple *---------------------------- */ { TupleDesc tupleDesc; int j; char *values[10]; HeapTuple tuple; /* 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"); 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, INT64_FORMAT, (indexStat.root_pages + indexStat.leaf_pages + indexStat.internal_pages + indexStat.deleted_pages + indexStat.empty_pages) * BLCKSZ); values[j] = palloc(32); snprintf(values[j++], 32, "%u", indexStat.root_blkno); values[j] = palloc(32); snprintf(values[j++], 32, INT64_FORMAT, indexStat.internal_pages); values[j] = palloc(32); snprintf(values[j++], 32, INT64_FORMAT, indexStat.leaf_pages); values[j] = palloc(32); snprintf(values[j++], 32, INT64_FORMAT, indexStat.empty_pages); values[j] = palloc(32); snprintf(values[j++], 32, INT64_FORMAT, indexStat.deleted_pages); values[j] = palloc(32); if (indexStat.max_avail > 0) snprintf(values[j++], 32, "%.2f", 100.0 - (double) indexStat.free_space / (double) indexStat.max_avail * 100.0); else snprintf(values[j++], 32, "NaN"); values[j] = palloc(32); if (indexStat.leaf_pages > 0) snprintf(values[j++], 32, "%.2f", (double) indexStat.fragments / (double) indexStat.leaf_pages * 100.0); else snprintf(values[j++], 32, "NaN"); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); result = HeapTupleGetDatum(tuple); } return result; }
Datum hstore_populate_record(PG_FUNCTION_ARGS) { Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0); HStore *hs; HEntry *entries; char *ptr; HeapTupleHeader rec; Oid tupType; int32 tupTypmod; TupleDesc tupdesc; HeapTupleData tuple; HeapTuple rettuple; RecordIOData *my_extra; int ncolumns; int i; Datum *values; bool *nulls; if (!type_is_rowtype(argtype)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("first argument must be a rowtype"))); if (PG_ARGISNULL(0)) { if (PG_ARGISNULL(1)) PG_RETURN_NULL(); rec = NULL; /* * have no tuple to look at, so the only source of type info is the * argtype. The lookup_rowtype_tupdesc call below will error out if we * don't have a known composite type oid here. */ tupType = argtype; tupTypmod = -1; } else { rec = PG_GETARG_HEAPTUPLEHEADER(0); if (PG_ARGISNULL(1)) PG_RETURN_POINTER(rec); /* Extract type info from the tuple itself */ tupType = HeapTupleHeaderGetTypeId(rec); tupTypmod = HeapTupleHeaderGetTypMod(rec); } hs = PG_GETARG_HS(1); entries = ARRPTR(hs); ptr = STRPTR(hs); /* * if the input hstore is empty, we can only skip the rest if we were * passed in a non-null record, since otherwise there may be issues with * domain nulls. */ if (HS_COUNT(hs) == 0 && rec) PG_RETURN_POINTER(rec); tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); ncolumns = tupdesc->natts; if (rec) { /* Build a temporary HeapTuple control structure */ tuple.t_len = HeapTupleHeaderGetDatumLength(rec); ItemPointerSetInvalid(&(tuple.t_self)); tuple.t_tableOid = InvalidOid; tuple.t_data = rec; } /* * We arrange to look up the needed I/O info just once per series of * calls, assuming the record type doesn't change underneath us. */ my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; if (my_extra == NULL || my_extra->ncolumns != ncolumns) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(RecordIOData) - sizeof(ColumnIOData) + ncolumns * sizeof(ColumnIOData)); my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra; my_extra->record_type = InvalidOid; my_extra->record_typmod = 0; } if (my_extra->record_type != tupType || my_extra->record_typmod != tupTypmod) { MemSet(my_extra, 0, sizeof(RecordIOData) - sizeof(ColumnIOData) + ncolumns * sizeof(ColumnIOData)); my_extra->record_type = tupType; my_extra->record_typmod = tupTypmod; my_extra->ncolumns = ncolumns; } values = (Datum *) palloc(ncolumns * sizeof(Datum)); nulls = (bool *) palloc(ncolumns * sizeof(bool)); if (rec) { /* Break down the tuple into fields */ heap_deform_tuple(&tuple, tupdesc, values, nulls); } else { for (i = 0; i < ncolumns; ++i) { values[i] = (Datum) 0; nulls[i] = true; } } for (i = 0; i < ncolumns; ++i) { ColumnIOData *column_info = &my_extra->columns[i]; Oid column_type = tupdesc->attrs[i]->atttypid; char *value; int idx; int vallen; /* Ignore dropped columns in datatype */ if (tupdesc->attrs[i]->attisdropped) { nulls[i] = true; continue; } idx = hstoreFindKey(hs, 0, NameStr(tupdesc->attrs[i]->attname), strlen(NameStr(tupdesc->attrs[i]->attname))); /* * we can't just skip here if the key wasn't found since we might have * a domain to deal with. If we were passed in a non-null record * datum, we assume that the existing values are valid (if they're * not, then it's not our fault), but if we were passed in a null, * then every field which we don't populate needs to be run through * the input function just in case it's a domain type. */ if (idx < 0 && rec) continue; /* * Prepare to convert the column value from text */ if (column_info->column_type != column_type) { getTypeInputInfo(column_type, &column_info->typiofunc, &column_info->typioparam); fmgr_info_cxt(column_info->typiofunc, &column_info->proc, fcinfo->flinfo->fn_mcxt); column_info->column_type = column_type; } if (idx < 0 || HS_VALISNULL(entries, idx)) { /* * need InputFunctionCall to happen even for nulls, so that domain * checks are done */ values[i] = InputFunctionCall(&column_info->proc, NULL, column_info->typioparam, tupdesc->attrs[i]->atttypmod); nulls[i] = true; } else { vallen = HS_VALLEN(entries, idx); value = palloc(1 + vallen); memcpy(value, HS_VAL(entries, ptr, idx), vallen); value[vallen] = 0; values[i] = InputFunctionCall(&column_info->proc, value, column_info->typioparam, tupdesc->attrs[i]->atttypmod); nulls[i] = false; } } rettuple = heap_form_tuple(tupdesc, values, nulls); ReleaseTupleDesc(tupdesc); PG_RETURN_DATUM(HeapTupleGetDatum(rettuple)); }
Datum ssl_extension_info(PG_FUNCTION_ARGS) { X509 *cert = MyProcPort->peer; FuncCallContext *funcctx; int call_cntr; int max_calls; MemoryContext oldcontext; SSLExtensionInfoContext *fctx; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; /* 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); /* Create a user function context for cross-call persistence */ fctx = (SSLExtensionInfoContext *) palloc(sizeof(SSLExtensionInfoContext)); /* Construct tuple descriptor */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context that cannot accept type record"))); fctx->tupdesc = BlessTupleDesc(tupdesc); /* Set max_calls as a count of extensions in certificate */ max_calls = cert != NULL ? X509_get_ext_count(cert) : 0; if (max_calls > 0) { /* got results, keep track of them */ funcctx->max_calls = max_calls; funcctx->user_fctx = fctx; } else { /* fast track when no results */ MemoryContextSwitchTo(oldcontext); SRF_RETURN_DONE(funcctx); } MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); /* * Initialize per-call variables. */ call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; fctx = funcctx->user_fctx; /* do while there are more left to send */ if (call_cntr < max_calls) { Datum values[3]; bool nulls[3]; char *buf; HeapTuple tuple; Datum result; BIO *membuf; X509_EXTENSION *ext; ASN1_OBJECT *obj; int nid; int len; /* need a BIO for this */ membuf = BIO_new(BIO_s_mem()); if (membuf == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("could not create OpenSSL BIO structure"))); /* Get the extension from the certificate */ ext = X509_get_ext(cert, call_cntr); obj = X509_EXTENSION_get_object(ext); /* Get the extension name */ nid = OBJ_obj2nid(obj); if (nid == NID_undef) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("unknown OpenSSL extension in certificate at position %d", call_cntr))); values[0] = CStringGetTextDatum(OBJ_nid2sn(nid)); nulls[0] = false; /* Get the extension value */ if (X509V3_EXT_print(membuf, ext, 0, 0) <= 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not print extension value in certificate at position %d", call_cntr))); len = BIO_get_mem_data(membuf, &buf); values[1] = PointerGetDatum(cstring_to_text_with_len(buf, len)); nulls[1] = false; /* Get critical status */ values[2] = BoolGetDatum(X509_EXTENSION_get_critical(ext)); nulls[2] = false; /* Build tuple */ tuple = heap_form_tuple(fctx->tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); if (BIO_free(membuf) != 1) elog(ERROR, "could not free OpenSSL BIO structure"); SRF_RETURN_NEXT(funcctx, result); } /* All done */ SRF_RETURN_DONE(funcctx); }
/*------------------------------------------------------- * hash_page_items() * * Get IndexTupleData set in a hash page * * Usage: SELECT * FROM hash_page_items(get_raw_page('con_hash_index', 1)); *------------------------------------------------------- */ Datum hash_page_items(PG_FUNCTION_ARGS) { bytea *raw_page = PG_GETARG_BYTEA_P(0); Page page; Datum result; Datum values[3]; bool nulls[3]; uint32 hashkey; HeapTuple tuple; FuncCallContext *fctx; MemoryContext mctx; struct user_args *uargs; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw page functions")))); if (SRF_IS_FIRSTCALL()) { TupleDesc tupleDesc; fctx = SRF_FIRSTCALL_INIT(); mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); page = verify_hash_page(raw_page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE); uargs = palloc(sizeof(struct user_args)); uargs->page = page; uargs->offset = FirstOffsetNumber; fctx->max_calls = PageGetMaxOffsetNumber(uargs->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); fctx->attinmeta = TupleDescGetAttInMetadata(tupleDesc); fctx->user_fctx = uargs; MemoryContextSwitchTo(mctx); } fctx = SRF_PERCALL_SETUP(); uargs = fctx->user_fctx; if (fctx->call_cntr < fctx->max_calls) { ItemId id; IndexTuple itup; int j; id = PageGetItemId(uargs->page, uargs->offset); if (!ItemIdIsValid(id)) elog(ERROR, "invalid ItemId"); itup = (IndexTuple) PageGetItem(uargs->page, id); MemSet(nulls, 0, sizeof(nulls)); j = 0; values[j++] = Int32GetDatum((int32) uargs->offset); values[j++] = PointerGetDatum(&itup->t_tid); hashkey = _hash_get_indextuple_hashkey(itup); values[j] = Int64GetDatum((int64) hashkey); tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); uargs->offset = uargs->offset + 1; SRF_RETURN_NEXT(fctx, result); } else { pfree(uargs); SRF_RETURN_DONE(fctx); } }
/* * pgdatabasev - produce a view of pgdatabase to include transient state */ Datum gp_pgdatabase__(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; Working_State *mystatus; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext oldcontext; /* 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); /* build tupdesc for result tuples */ /* this had better match pg_prepared_xacts view in system_views.sql */ tupdesc = CreateTemplateTupleDesc(5, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "dbid", INT2OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "isprimary", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "content", INT2OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "valid", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "definedprimary", BOOLOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* * Collect all the locking information that we will format and * send out as a result set. */ mystatus = (Working_State *) palloc(sizeof(Working_State)); funcctx->user_fctx = (void *) mystatus; mystatus->master = GetMasterSegment(); mystatus->standby = GetStandbySegment(); mystatus->segments = GetSegmentList(); mystatus->idx = 0; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); mystatus = (Working_State *) funcctx->user_fctx; while (mystatus->master || mystatus->standby || (mystatus->idx < list_length(mystatus->segments))) { Datum values[6]; bool nulls[6]; HeapTuple tuple; Datum result; Segment *current = NULL; if (mystatus->master) { current = mystatus->master; mystatus->master = NULL; } else if (mystatus->standby) { current = mystatus->standby; mystatus->standby = NULL; } else { current = list_nth(mystatus->segments, mystatus->idx); mystatus->idx++; } /* * Form tuple with appropriate data. */ MemSet(values, 0, sizeof(values)); MemSet(nulls, false, sizeof(nulls)); //values[0] = UInt16GetDatum(current->dbid); values[1] = current->standby ? false : true;; values[2] = UInt16GetDatum(current->segindex); values[3] = BoolGetDatum(true); values[4] = values[1]; tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } SRF_RETURN_DONE(funcctx); }
/* ------------------------------------------------ * hash_bitmap_info() * * Get bitmap information for a particular overflow page * * Usage: SELECT * FROM hash_bitmap_info('con_hash_index'::regclass, 5); * ------------------------------------------------ */ Datum hash_bitmap_info(PG_FUNCTION_ARGS) { Oid indexRelid = PG_GETARG_OID(0); uint64 ovflblkno = PG_GETARG_INT64(1); HashMetaPage metap; Buffer metabuf, mapbuf; BlockNumber bitmapblkno; Page mappage; bool bit = false; TupleDesc tupleDesc; Relation indexRel; uint32 ovflbitno; int32 bitmappage, bitmapbit; HeapTuple tuple; int i, j; Datum values[3]; bool nulls[3]; uint32 *freep; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw page functions")))); indexRel = index_open(indexRelid, AccessShareLock); if (!IS_HASH(indexRel)) elog(ERROR, "relation \"%s\" is not a hash index", RelationGetRelationName(indexRel)); if (RELATION_IS_OTHER_TEMP(indexRel)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); if (ovflblkno >= RelationGetNumberOfBlocks(indexRel)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("block number " UINT64_FORMAT " is out of range for relation \"%s\"", ovflblkno, RelationGetRelationName(indexRel)))); /* Read the metapage so we can determine which bitmap page to use */ metabuf = _hash_getbuf(indexRel, HASH_METAPAGE, HASH_READ, LH_META_PAGE); metap = HashPageGetMeta(BufferGetPage(metabuf)); /* * Reject attempt to read the bit for a metapage or bitmap page; this is * only meaningful for overflow pages. */ if (ovflblkno == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid overflow block number %u", (BlockNumber) ovflblkno))); for (i = 0; i < metap->hashm_nmaps; i++) if (metap->hashm_mapp[i] == ovflblkno) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid overflow block number %u", (BlockNumber) ovflblkno))); /* * Identify overflow bit number. This will error out for primary bucket * pages, and we've already rejected the metapage and bitmap pages above. */ ovflbitno = _hash_ovflblkno_to_bitno(metap, (BlockNumber) ovflblkno); bitmappage = ovflbitno >> BMPG_SHIFT(metap); bitmapbit = ovflbitno & BMPG_MASK(metap); if (bitmappage >= metap->hashm_nmaps) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid overflow block number %u", (BlockNumber) ovflblkno))); bitmapblkno = metap->hashm_mapp[bitmappage]; _hash_relbuf(indexRel, metabuf); /* Check the status of bitmap bit for overflow page */ mapbuf = _hash_getbuf(indexRel, bitmapblkno, HASH_READ, LH_BITMAP_PAGE); mappage = BufferGetPage(mapbuf); freep = HashPageGetBitmap(mappage); bit = ISSET(freep, bitmapbit) != 0; _hash_relbuf(indexRel, mapbuf); index_close(indexRel, AccessShareLock); /* 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); MemSet(nulls, 0, sizeof(nulls)); j = 0; values[j++] = Int64GetDatum((int64) bitmapblkno); values[j++] = Int32GetDatum(bitmapbit); values[j++] = BoolGetDatum(bit); tuple = heap_form_tuple(tupleDesc, values, nulls); PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); }
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); } }
/* ------------------------------------------------ * 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)); }
Datum pgrowlocks(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; HeapScanDesc scan; HeapTuple tuple; TupleDesc tupdesc; AttInMetadata *attinmeta; Datum result; MyData *mydata; Relation rel; if (SRF_IS_FIRSTCALL()) { text *relname; RangeVar *relrv; MemoryContext oldcontext; AclResult aclresult; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; relname = PG_GETARG_TEXT_P(0); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = heap_openrv(relrv, AccessShareLock); /* check permissions: must have SELECT on table */ aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_SELECT); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_CLASS, RelationGetRelationName(rel)); scan = heap_beginscan(rel, GetActiveSnapshot(), 0, NULL); mydata = palloc(sizeof(*mydata)); mydata->rel = rel; mydata->scan = scan; mydata->ncolumns = tupdesc->natts; funcctx->user_fctx = mydata; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); attinmeta = funcctx->attinmeta; mydata = (MyData *) funcctx->user_fctx; scan = mydata->scan; /* scan the relation */ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { HTSU_Result htsu; TransactionId xmax; uint16 infomask; /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */ LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); htsu = HeapTupleSatisfiesUpdate(tuple, GetCurrentCommandId(false), scan->rs_cbuf); xmax = HeapTupleHeaderGetRawXmax(tuple->t_data); infomask = tuple->t_data->t_infomask; /* * a tuple is locked if HTSU returns BeingUpdated, and if it returns * MayBeUpdated but the Xmax is valid and pointing at us. */ if (htsu == HeapTupleBeingUpdated || (htsu == HeapTupleMayBeUpdated && !(infomask & HEAP_XMAX_INVALID) && !(infomask & HEAP_XMAX_IS_MULTI) && (xmax == GetCurrentTransactionIdIfAny()))) { char **values; values = (char **) palloc(mydata->ncolumns * sizeof(char *)); values[Atnum_tid] = (char *) DirectFunctionCall1(tidout, PointerGetDatum(&tuple->t_self)); values[Atnum_xmax] = palloc(NCHARS * sizeof(char)); snprintf(values[Atnum_xmax], NCHARS, "%d", xmax); if (infomask & HEAP_XMAX_IS_MULTI) { MultiXactMember *members; int nmembers; bool first = true; bool allow_old; values[Atnum_ismulti] = pstrdup("true"); allow_old = !(infomask & HEAP_LOCK_MASK) && (infomask & HEAP_XMAX_LOCK_ONLY); nmembers = GetMultiXactIdMembers(xmax, &members, allow_old, false); if (nmembers == -1) { values[Atnum_xids] = "{0}"; values[Atnum_modes] = "{transient upgrade status}"; values[Atnum_pids] = "{0}"; } else { int j; values[Atnum_xids] = palloc(NCHARS * nmembers); values[Atnum_modes] = palloc(NCHARS * nmembers); values[Atnum_pids] = palloc(NCHARS * nmembers); strcpy(values[Atnum_xids], "{"); strcpy(values[Atnum_modes], "{"); strcpy(values[Atnum_pids], "{"); for (j = 0; j < nmembers; j++) { char buf[NCHARS]; if (!first) { strcat(values[Atnum_xids], ","); strcat(values[Atnum_modes], ","); strcat(values[Atnum_pids], ","); } snprintf(buf, NCHARS, "%d", members[j].xid); strcat(values[Atnum_xids], buf); switch (members[j].status) { case MultiXactStatusUpdate: snprintf(buf, NCHARS, "Update"); break; case MultiXactStatusNoKeyUpdate: snprintf(buf, NCHARS, "No Key Update"); break; case MultiXactStatusForUpdate: snprintf(buf, NCHARS, "For Update"); break; case MultiXactStatusForNoKeyUpdate: snprintf(buf, NCHARS, "For No Key Update"); break; case MultiXactStatusForShare: snprintf(buf, NCHARS, "Share"); break; case MultiXactStatusForKeyShare: snprintf(buf, NCHARS, "Key Share"); break; } strcat(values[Atnum_modes], buf); snprintf(buf, NCHARS, "%d", BackendXidGetPid(members[j].xid)); strcat(values[Atnum_pids], buf); first = false; } strcat(values[Atnum_xids], "}"); strcat(values[Atnum_modes], "}"); strcat(values[Atnum_pids], "}"); } } else { values[Atnum_ismulti] = pstrdup("false"); values[Atnum_xids] = palloc(NCHARS * sizeof(char)); snprintf(values[Atnum_xids], NCHARS, "{%d}", xmax); values[Atnum_modes] = palloc(NCHARS); if (infomask & HEAP_XMAX_LOCK_ONLY) { if (HEAP_XMAX_IS_SHR_LOCKED(infomask)) snprintf(values[Atnum_modes], NCHARS, "{For Share}"); else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask)) snprintf(values[Atnum_modes], NCHARS, "{For Key Share}"); else if (HEAP_XMAX_IS_EXCL_LOCKED(infomask)) { if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED) snprintf(values[Atnum_modes], NCHARS, "{For Update}"); else snprintf(values[Atnum_modes], NCHARS, "{For No Key Update}"); } else /* neither keyshare nor exclusive bit it set */ snprintf(values[Atnum_modes], NCHARS, "{transient upgrade status}"); } else { if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED) snprintf(values[Atnum_modes], NCHARS, "{Update}"); else snprintf(values[Atnum_modes], NCHARS, "{No Key Update}"); } values[Atnum_pids] = palloc(NCHARS * sizeof(char)); snprintf(values[Atnum_pids], NCHARS, "{%d}", BackendXidGetPid(xmax)); } LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); /* build a tuple */ tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); /* * no need to pfree what we allocated; it's on a short-lived * memory context anyway */ SRF_RETURN_NEXT(funcctx, result); } else { LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); } } heap_endscan(scan); heap_close(mydata->rel, AccessShareLock); SRF_RETURN_DONE(funcctx); }
static Datum caql_scan_in_memory_pg_class_private(PG_FUNCTION_ARGS, bool isForward) { text *inText = PG_GETARG_TEXT_P(0); char *inStr = text_to_cstring(inText);; FuncCallContext *funcctx; Datum result; MemoryContext oldcontext; TupleDesc tupdesc; HeapTuple restuple; //int count = 0; HeapTuple readtup = NULL; cqContext *pcqCtx; StringInfoData buf; initStringInfo(&buf); if (SRF_IS_FIRSTCALL()) { funcctx = SRF_FIRSTCALL_INIT(); /* switch context when allocating stuff to be used in later calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); tupdesc = CreateTemplateTupleDesc(NUM_COLS, false /*hasoid*/); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relname", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relkind", CHAROID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "oid", OIDOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* create tuples for pg_class table */ pcqCtx = caql_beginscan( NULL, cql("SELECT * FROM pg_class " " WHERE relname = :1", CStringGetDatum((char *) inStr))); funcctx->user_fctx = pcqCtx; /* return to original context when allocating transient memory */ MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); pcqCtx = (cqContext *)funcctx->user_fctx; if (NULL != (readtup = getnext(pcqCtx, isForward))) { Datum values[NUM_COLS]; bool nulls[NUM_COLS]; Relation relation = RelationIdGetRelation(RelationRelationId); TupleDesc tupleDesc = RelationGetDescr(relation); char *nspname = DatumGetCString(tuple_getattr(readtup, tupleDesc, Anum_pg_class_relname)); text *t = cstring_to_text(nspname); values[0] = PointerGetDatum(t); nulls[0] = false; values[1] = CharGetDatum(tuple_getattr(readtup, tupleDesc, Anum_pg_class_relkind)); nulls[1] = false; values[2] = ObjectIdGetDatum(HeapTupleGetOid(readtup)); nulls[2] = false; /* build tuple */ restuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); /* make the tuple into a datum */ result = HeapTupleGetDatum(restuple); elog(DEBUG1, "Reloid: %d", HeapTupleGetOid(readtup)); RelationClose(relation); SRF_RETURN_NEXT(funcctx, result); } else { caql_endscan(pcqCtx); SRF_RETURN_DONE(funcctx); } }
datum_t page_header(PG_FUNC_ARGS) { bytea *raw_page = ARG_BYTEA_P(0); int raw_page_size; struct tuple * tupdesc; datum_t result; struct heap_tuple * tuple; datum_t values[9]; bool nulls[9]; struct page_hdr * page; struct xlr_ptr lsn; char lsnchar[64]; if (!superuser()) ereport(ERROR, (errcode(E_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw page functions")))); raw_page_size = VLA_SZ(raw_page) - VAR_HDR_SZ; /* * Check that enough data was supplied, so that we don't try to access * fields outside the supplied buffer. */ if (raw_page_size < sizeof(struct page_hdr)) ereport(ERROR, (errcode(E_INVALID_PARAMETER_VALUE), errmsg("input page too small (%d bytes)", raw_page_size))); page = (struct page_hdr *) VLA_DATA(raw_page); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); /* Extract information from the page header */ lsn = PAGE_LSN(page); snprintf(lsnchar, sizeof(lsnchar), "%X/%X", lsn.xlogid, lsn.xrecoff); values[0] = CStringGetTextDatum(lsnchar); values[1] = UINT16_TO_D(PAGE_TLI(page)); values[2] = UINT16_TO_D(page->pd_flags); values[3] = UINT16_TO_D(page->pd_lower); values[4] = UINT16_TO_D(page->pd_upper); values[5] = UINT16_TO_D(page->pd_special); values[6] = UINT16_TO_D(PAGE_SZ(page)); values[7] = UINT16_TO_D(PAGE_VERSION(page)); values[8] = XID_TO_D(page->pd_prune_xid); /* Build and return the tuple. */ memset(nulls, 0, sizeof(nulls)); tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); RET_DATUM(result); }
Datum pg_logdir_ls(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; struct dirent *de; directory_fctx *fctx; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("only superuser can list the log directory")))); if (strcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log") != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'")))); if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; TupleDesc tupdesc; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); fctx = palloc(sizeof(directory_fctx)); tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime", TIMESTAMPOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename", TEXTOID, -1, 0); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); fctx->location = pstrdup(Log_directory); fctx->dirdesc = AllocateDir(fctx->location); if (!fctx->dirdesc) ereport(ERROR, (errcode_for_file_access(), errmsg("could not read directory \"%s\": %m", fctx->location))); funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); fctx = (directory_fctx *) funcctx->user_fctx; while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL) { char *values[2]; HeapTuple tuple; char timestampbuf[32]; char *field[MAXDATEFIELDS]; char lowstr[MAXDATELEN + 1]; int dtype; int nf, ftype[MAXDATEFIELDS]; fsec_t fsec; int tz = 0; struct pg_tm date; /* * Default format: postgresql-YYYY-MM-DD_HHMMSS.log */ if (strlen(de->d_name) != 32 || strncmp(de->d_name, "postgresql-", 11) != 0 || de->d_name[21] != '_' || strcmp(de->d_name + 28, ".log") != 0) continue; /* extract timestamp portion of filename */ strcpy(timestampbuf, de->d_name + 11); timestampbuf[17] = '\0'; /* parse and decode expected timestamp to verify it's OK format */ if (ParseDateTime(timestampbuf, lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf)) continue; if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz)) continue; /* Seems the timestamp is OK; prepare and return tuple */ values[0] = timestampbuf; values[1] = psprintf("%s/%s", fctx->location, de->d_name); tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); } FreeDir(fctx->dirdesc); SRF_RETURN_DONE(funcctx); }
PGDLLEXPORT Datum edge_disjoint_paths_many_to_one(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 */ int64_t *source_vertices; size_t size_source_verticesArr; source_vertices = (int64_t *) pgr_get_bigIntArray(&size_source_verticesArr, PG_GETARG_ARRAYTYPE_P(1)); PGR_DBG("source_verticesArr size %ld ", size_source_verticesArr); PGR_DBG("Calling process"); process( pgr_text2char(PG_GETARG_TEXT_P(0)), source_vertices, size_source_verticesArr, PG_GETARG_INT64(2), PG_GETARG_BOOL(3), &result_tuples, &result_count); free(source_vertices); /* */ /**********************************************************************/ 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 = (uint32_t)funcctx->call_cntr; max_calls = (uint32_t)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 */ values = palloc(5 * sizeof(Datum)); nulls = palloc(5 * sizeof(bool)); size_t i; for (i = 0; i < 5; ++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].start_id); values[3] = Int64GetDatum(result_tuples[call_cntr].node); values[4] = Int64GetDatum(result_tuples[call_cntr].edge); /**********************************************************************/ 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); } }
/* Clause 3.3.9.3 */ Datum TradeUpdateFrame1(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; AttInMetadata *attinmeta; int call_cntr; int max_calls; int i; int j; char **values = NULL; /* Stuff done only on the first call of the function. */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; enum tuf1 { i_bid_price=0, i_cash_transaction_amount, i_cash_transaction_dts, i_cash_transaction_name, i_exec_name, i_is_cash, i_is_market, i_num_found, i_num_updated, i_settlement_amount, i_settlement_cash_due_date, i_settlement_cash_type, i_trade_history_dts, i_trade_history_status_id, i_trade_price }; int max_trades = PG_GETARG_INT32(0); int max_updates = PG_GETARG_INT32(1); ArrayType *trade_id_p = PG_GETARG_ARRAYTYPE_P(2); int16 typlen; bool typbyval; char typalign; int ndim, nitems; int *dim; long *trade_id; int ret; TupleDesc tupdesc; SPITupleTable *tuptable = NULL; HeapTuple tuple = NULL; #ifdef DEBUG char sql[2048]; #endif Datum args[2]; char nulls[2] = { ' ', ' ' }; int num_found = max_trades; int num_updated = 0; int num_updated4 = 0; int num_updated5 = 0; int num_updated7 = 0; int num_cash = 0; ndim = ARR_NDIM(trade_id_p); dim = ARR_DIMS(trade_id_p); nitems = ArrayGetNItems(ndim, dim); get_typlenbyvalalign(ARR_ELEMTYPE(trade_id_p), &typlen, &typbyval, &typalign); trade_id = (long *) ARR_DATA_PTR(trade_id_p); /* * Prepare a values array for building the returned tuple. * This should be an array of C strings, which will * be processed later by the type input functions. * Don't forget to factor in commas (,) and braces ({}) for the arrays. */ values = (char **) palloc(sizeof(char *) * 15); values[i_bid_price] = (char *) palloc(((S_PRICE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_amount] = (char *) palloc(((VALUE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_dts] = (char *) palloc(((MAXDATELEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_name] = (char *) palloc(((CT_NAME_LEN + 3) * 20 + 2) * sizeof(char)); values[i_exec_name] = (char *) palloc(((T_EXEC_NAME_LEN + 3) * 20 + 2) * sizeof(char)); values[i_is_cash] = (char *) palloc(((SMALLINT_LEN + 1) * 20 + 2) * sizeof(char)); values[i_is_market] = (char *) palloc(((SMALLINT_LEN + 1) * 20 + 2) * sizeof(char)); values[i_num_found] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char)); values[i_num_updated] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char)); values[i_settlement_amount] = (char *) palloc(((VALUE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_settlement_cash_due_date] = (char *) palloc(((MAXDATELEN + 1) * 20 + 2) * sizeof(char)); values[i_settlement_cash_type] = (char *) palloc(((SE_CASH_TYPE_LEN + 3) * 20 + 2) * sizeof(char)); values[i_trade_history_dts] = (char *) palloc(((MAXDATELEN * 3 + 4) * 20 + 22) * sizeof(char)); values[i_trade_history_status_id] = (char *) palloc((((ST_ID_LEN + 2) * 3 + 4) * 20 + 22) * sizeof(char)); values[i_trade_price] = (char *) palloc(((S_PRICE_T_LEN + 1) * 20 + 2) * sizeof(char)); #ifdef DEBUG dump_tuf1_inputs(max_trades, max_updates, trade_id); #endif /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); funcctx->max_calls = 1; /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); SPI_connect(); plan_queries(TUF1_statements); strcpy(values[i_bid_price], "{"); strcpy(values[i_exec_name], "{"); strcpy(values[i_is_cash], "{"); strcpy(values[i_is_market], "{"); strcpy(values[i_trade_price], "{"); strcpy(values[i_settlement_amount], "{"); strcpy(values[i_settlement_cash_due_date], "{"); strcpy(values[i_settlement_cash_type], "{"); strcpy(values[i_cash_transaction_amount], "{"); strcpy(values[i_cash_transaction_dts], "{"); strcpy(values[i_cash_transaction_name], "{"); strcpy(values[i_trade_history_dts], "{"); strcpy(values[i_trade_history_status_id], "{"); for (i = 0; i < max_trades; i++) { char *is_cash_str = NULL; char *is_market_str; if (num_updated < max_updates) { char *ex_name; #ifdef DEBUG sprintf(sql, SQLTUF1_1, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(trade_id[i]); ret = SPI_execute_plan(TUF1_1, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; ex_name = SPI_getvalue(tuple, tupdesc, 1); } else { continue; } #ifdef DEBUG elog(NOTICE, "ex_name = %s", ex_name); if (strstr(ex_name, " X ")) { sprintf(sql, SQLTUF1_2a, ex_name); } else { sprintf(sql, SQLTUF1_2b, ex_name); } elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = CStringGetTextDatum(ex_name); if (strstr(ex_name, " X ")) { ret = SPI_execute_plan(TUF1_2a, args, nulls, true, 0); } else { ret = SPI_execute_plan(TUF1_2b, args, nulls, true, 0); } if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; ex_name = SPI_getvalue(tuple, tupdesc, 1); } else { FAIL_FRAME_SET(&funcctx->max_calls, strstr(ex_name, " X ")? TUF1_statements[1].sql: TUF1_statements[2].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } #ifdef DEBUG elog(NOTICE, "ex_name = %s", ex_name); sprintf(sql, SQLTUF1_3, ex_name, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[1] = Int64GetDatum(trade_id[i]); ret = SPI_execute_plan(TUF1_3, args, nulls, false, 0); if (ret != SPI_OK_UPDATE) { FAIL_FRAME_SET(&funcctx->max_calls, TUF1_statements[4].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } num_updated += SPI_processed; } #ifdef DEBUG sprintf(sql, SQLTUF1_4, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(trade_id[i]); ret = SPI_execute_plan(TUF1_4, args, nulls, true, 0); if (ret != SPI_OK_SELECT) { FAIL_FRAME_SET(&funcctx->max_calls, TUF1_statements[5].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; for (j = 0; j < SPI_processed; j++) { char *trade_price; if (num_updated4 > 0) { strcat(values[i_bid_price], ","); strcat(values[i_exec_name], ","); strcat(values[i_is_cash], ","); strcat(values[i_is_market], ","); strcat(values[i_trade_price], ","); } tuple = tuptable->vals[j]; strcat(values[i_bid_price], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_exec_name], "\""); strcat(values[i_exec_name], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_exec_name], "\""); is_cash_str = SPI_getvalue(tuple, tupdesc, 3); strcat(values[i_is_cash], (is_cash_str[0] == 't' ? "1": "0")); is_market_str = SPI_getvalue(tuple, tupdesc, 4); strcat(values[i_is_market], (is_market_str[0] == 't' ? "0" : "1")); trade_price = SPI_getvalue(tuple, tupdesc, 5); if (trade_price != NULL) strcat(values[i_trade_price], SPI_getvalue(tuple, tupdesc, 5)); else strcat(values[i_trade_price], "NULL"); num_updated4++; } #ifdef DEBUG sprintf(sql, SQLTUF1_5, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TUF1_5, args, nulls, true, 0); if (ret != SPI_OK_SELECT) { FAIL_FRAME_SET(&funcctx->max_calls, TUF1_statements[6].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; for (j = 0; j < SPI_processed; j++) { if (num_updated5 > 0) { strcat(values[i_settlement_amount], ","); strcat(values[i_settlement_cash_due_date], ","); strcat(values[i_settlement_cash_type], ","); } tuple = tuptable->vals[j]; strcat(values[i_settlement_amount], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_settlement_cash_due_date], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_settlement_cash_type], "\""); strcat(values[i_settlement_cash_type], SPI_getvalue(tuple, tupdesc, 3)); strcat(values[i_settlement_cash_type], "\""); num_updated5++; } if (is_cash_str[0] == 't') { if (num_cash > 0) { strcat(values[i_cash_transaction_amount], ","); strcat(values[i_cash_transaction_dts], ","); strcat(values[i_cash_transaction_name], ","); } #ifdef DEBUG sprintf(sql, SQLTUF1_6, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TUF1_6, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; tuple = tuptable->vals[0]; strcat(values[i_cash_transaction_amount], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_cash_transaction_dts], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_cash_transaction_name], "\""); strcat(values[i_cash_transaction_name], SPI_getvalue(tuple, tupdesc, 3)); strcat(values[i_cash_transaction_name], "\""); ++num_cash; } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF1_statements[7].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } } #ifdef DEBUG sprintf(sql, SQLTUF1_7, trade_id[i]); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TUF1_7, args, nulls, true, 0); if (ret == SPI_OK_SELECT) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF1_statements[8].sql); dump_tuf1_inputs(max_trades, max_updates, trade_id); continue; } if (num_updated7 > 0) { strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } strcat(values[i_trade_history_dts], "{"); strcat(values[i_trade_history_status_id], "{"); for (j = 0; j < SPI_processed; j++) { if (j > 0) { strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } tuple = tuptable->vals[j]; strcat(values[i_trade_history_dts], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_trade_history_status_id], "\""); strcat(values[i_trade_history_status_id], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_trade_history_status_id], "\""); num_updated7++; } for (j = SPI_processed; j < 3; j++) { if (j > 0) { strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } strcat(values[i_trade_history_dts], "NULL"); strcat(values[i_trade_history_status_id], "\"\""); num_updated7++; } strcat(values[i_trade_history_dts], "}"); strcat(values[i_trade_history_status_id], "}"); } strcat(values[i_bid_price], "}"); strcat(values[i_exec_name], "}"); strcat(values[i_is_cash], "}"); strcat(values[i_is_market], "}"); strcat(values[i_trade_price], "}"); strcat(values[i_settlement_amount], "}"); strcat(values[i_settlement_cash_due_date], "}"); strcat(values[i_settlement_cash_type], "}"); strcat(values[i_cash_transaction_amount], "}"); strcat(values[i_cash_transaction_dts], "}"); strcat(values[i_cash_transaction_name], "}"); strcat(values[i_trade_history_dts], "}"); strcat(values[i_trade_history_status_id], "}"); sprintf(values[i_num_found], "%d", num_found); sprintf(values[i_num_updated], "%d", num_updated); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); } /* * generate attribute metadata needed later to produce tuples from raw * C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) { /* do when there is more left to send */ HeapTuple tuple; Datum result; #ifdef DEBUG for (i = 0; i < 15; i++) { elog(NOTICE, "TUF1 OUT: %d %s", i, values[i]); } #endif /* DEBUG */ /* Build a tuple. */ tuple = BuildTupleFromCStrings(attinmeta, values); /* Make the tuple into a datum. */ result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { /* Do when there is no more left. */ SPI_finish(); SRF_RETURN_DONE(funcctx); } }
/* ----------------------------------------------- * bt_page_stats() * * Usage: SELECT * FROM bt_page_stats('t1_pkey', 1); * ----------------------------------------------- */ Datum bt_page_stats(PG_FUNCTION_ARGS) { text *relname = PG_GETARG_TEXT_PP(0); uint32 blkno = PG_GETARG_UINT32(1); Buffer buffer; Relation rel; RangeVar *relrv; Datum result; HeapTuple tuple; TupleDesc tupleDesc; int j; char *values[11]; BTPageStat stat; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pageinspect functions")))); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = relation_openrv(relrv, AccessShareLock); if (!IS_INDEX(rel) || !IS_BTREE(rel)) elog(ERROR, "relation \"%s\" is not a btree index", RelationGetRelationName(rel)); /* * 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 (RELATION_IS_OTHER_TEMP(rel)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); if (blkno == 0) elog(ERROR, "block 0 is a meta page"); CHECK_RELATION_BLOCK_RANGE(rel, blkno); buffer = ReadBuffer(rel, blkno); LockBuffer(buffer, BUFFER_LOCK_SHARE); /* keep compiler quiet */ stat.btpo_prev = stat.btpo_next = InvalidBlockNumber; stat.btpo_flags = stat.free_size = stat.avg_item_size = 0; GetBTPageStatistics(blkno, buffer, &stat); UnlockReleaseBuffer(buffer); relation_close(rel, AccessShareLock); /* 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"); j = 0; values[j++] = psprintf("%d", stat.blkno); values[j++] = psprintf("%c", stat.type); values[j++] = psprintf("%d", stat.live_items); values[j++] = psprintf("%d", stat.dead_items); values[j++] = psprintf("%d", stat.avg_item_size); values[j++] = psprintf("%d", stat.page_size); values[j++] = psprintf("%d", stat.free_size); values[j++] = psprintf("%d", stat.btpo_prev); values[j++] = psprintf("%d", stat.btpo_next); values[j++] = psprintf("%d", (stat.type == 'd') ? stat.btpo.xact : stat.btpo.level); values[j++] = psprintf("%d", stat.btpo_flags); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); result = HeapTupleGetDatum(tuple); PG_RETURN_DATUM(result); }
/* Clause 3.3.9.4 */ Datum TradeUpdateFrame2(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; AttInMetadata *attinmeta; int call_cntr; int max_calls; int i; int j; char **values = NULL; /* Stuff done only on the first call of the function. */ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; enum tuf2 { i_bid_price=0, i_cash_transaction_amount, i_cash_transaction_dts, i_cash_transaction_name, i_exec_name, i_is_cash, i_num_found, i_num_updated, i_settlement_amount, i_settlement_cash_due_date, i_settlement_cash_type, i_trade_history_dts, i_trade_history_status_id, i_trade_list, i_trade_price }; long acct_id = PG_GETARG_INT64(0); Timestamp end_trade_dts_ts = PG_GETARG_TIMESTAMP(1); int max_trades = PG_GETARG_INT32(2); int max_updates = PG_GETARG_INT32(3); Timestamp start_trade_dts_ts = PG_GETARG_TIMESTAMP(4); int ret; TupleDesc tupdesc; SPITupleTable *tuptable = NULL; HeapTuple tuple = NULL; struct pg_tm tt, *tm = &tt; fsec_t fsec; char *tzn = NULL; #ifdef DEBUG char sql[2048]; #endif Datum args[4]; char nulls[4] = { ' ', ' ', ' ', ' ' }; char end_trade_dts[MAXDATELEN + 1]; char start_trade_dts[MAXDATELEN + 1]; int num_found; int num_updated = 0; int num_cash = 0; if (timestamp2tm(end_trade_dts_ts, NULL, tm, &fsec, NULL, NULL) == 0) { EncodeDateTimeM(tm, fsec, tzn, end_trade_dts); } if (timestamp2tm(start_trade_dts_ts, NULL, tm, &fsec, NULL, NULL) == 0) { EncodeDateTimeM(tm, fsec, tzn, start_trade_dts); } #ifdef DEBUG dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); #endif /* * Prepare a values array for building the returned tuple. * This should be an array of C strings, which will * be processed later by the type input functions. * Don't forget to factor in commas (,) and braces ({}) for the arrays. */ values = (char **) palloc(sizeof(char *) * 15); values[i_bid_price] = (char *) palloc(((S_PRICE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_amount] = (char *) palloc(((VALUE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_dts] = (char *) palloc(((MAXDATELEN + 1) * 20 + 2) * sizeof(char)); values[i_cash_transaction_name] = (char *) palloc(((CT_NAME_LEN + 3) * 20 + 2) * sizeof(char)); values[i_exec_name] = (char *) palloc(((T_EXEC_NAME_LEN + 3) * 20 + 2) * sizeof(char)); values[i_is_cash] = (char *) palloc(((SMALLINT_LEN + 1) * 20 + 2) * sizeof(char)); values[i_num_found] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char)); values[i_num_updated] = (char *) palloc((INTEGER_LEN + 1) * sizeof(char)); values[i_settlement_amount] = (char *) palloc(((VALUE_T_LEN + 1) * 20 + 2) * sizeof(char)); values[i_settlement_cash_due_date] = (char *) palloc(((MAXDATELEN + 1) * 20 + 2) * sizeof(char)); values[i_settlement_cash_type] = (char *) palloc(((SE_CASH_TYPE_LEN + 3) * 20 + 2) * sizeof(char)); values[i_trade_history_dts] = (char *) palloc((((MAXDATELEN + 2) * 3 + 2) * 20 + 5) * sizeof(char)); values[i_trade_history_status_id] = (char *) palloc((((ST_ID_LEN + 2) * 3 + 2) * 20 + 5) * sizeof(char)); values[i_trade_list] = (char *) palloc(((BIGINT_LEN + 1) * 20 + 2) * sizeof(char)); values[i_trade_price] = (char *) palloc(((S_PRICE_T_LEN + 1) * 20 + 2) * sizeof(char)); /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); funcctx->max_calls = 1; /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); SPI_connect(); plan_queries(TUF2_statements); #ifdef DEBUG sprintf(sql, SQLTUF2_1, acct_id, start_trade_dts, end_trade_dts, max_trades); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(acct_id); args[1] = TimestampGetDatum(start_trade_dts_ts); args[2] = TimestampGetDatum(end_trade_dts_ts); args[3] = Int32GetDatum(max_trades); ret = SPI_execute_plan(TUF2_1, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { tupdesc = SPI_tuptable->tupdesc; tuptable = SPI_tuptable; } num_found = SPI_processed; strcpy(values[i_bid_price], "{"); strcpy(values[i_exec_name], "{"); strcpy(values[i_is_cash], "{"); strcpy(values[i_trade_list], "{"); strcpy(values[i_trade_price], "{"); strcpy(values[i_settlement_amount], "{"); strcpy(values[i_settlement_cash_due_date], "{"); strcpy(values[i_settlement_cash_type], "{"); strcpy(values[i_cash_transaction_amount], "{"); strcpy(values[i_cash_transaction_dts], "{"); strcpy(values[i_cash_transaction_name], "{"); strcpy(values[i_trade_history_dts], "{"); strcpy(values[i_trade_history_status_id], "{"); for (i = 0; i < num_found; i++) { TupleDesc l_tupdesc; SPITupleTable *l_tuptable = NULL; HeapTuple l_tuple = NULL; char *is_cash_str; char *trade_list; char cash_type[41]; tuple = tuptable->vals[i]; if (i > 0) { strcat(values[i_bid_price], ","); strcat(values[i_exec_name], ","); strcat(values[i_is_cash], ","); strcat(values[i_trade_list], ","); strcat(values[i_trade_price], ","); strcat(values[i_settlement_amount], ","); strcat(values[i_settlement_cash_due_date], ","); strcat(values[i_settlement_cash_type], ","); strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } strcat(values[i_bid_price], SPI_getvalue(tuple, tupdesc, 1)); strcat(values[i_exec_name], "\""); strcat(values[i_exec_name], SPI_getvalue(tuple, tupdesc, 2)); strcat(values[i_exec_name], "\""); is_cash_str = SPI_getvalue(tuple, tupdesc, 3); strcat(values[i_is_cash], (is_cash_str[0] == 't' ? "0" : "1")); trade_list = SPI_getvalue(tuple, tupdesc, 4); strcat(values[i_trade_list], trade_list); strcat(values[i_trade_price], SPI_getvalue(tuple, tupdesc, 5)); if (num_updated < max_updates) { char *old_cash_type; #ifdef DEBUG sprintf(sql, SQLTUF2_2, trade_list); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(atoll(trade_list)); ret = SPI_execute_plan(TUF2_2, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { l_tupdesc = SPI_tuptable->tupdesc; l_tuptable = SPI_tuptable; l_tuple = l_tuptable->vals[0]; old_cash_type = SPI_getvalue(l_tuple, l_tupdesc, 1); } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF2_statements[1].sql); dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); continue; } #ifdef DEBUG elog(NOTICE, "cash_type = '%s'", old_cash_type); #endif /* DEBUG */ if (is_cash_str[0] == 't') { if (strcmp(old_cash_type, "Cash Account") == 0) { strcpy(cash_type, "Cash"); } else { strcpy(cash_type, "Cash Account"); } } else { if (strcmp(old_cash_type, "Margin Account") == 0) { strcpy(cash_type, "Margin"); } else { strcpy(cash_type, "Margin Account"); } } #ifdef DEBUG sprintf(sql, SQLTUF2_3, cash_type, trade_list); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = CStringGetTextDatum(cash_type); args[1] = Int64GetDatum(atoll(trade_list)); ret = SPI_execute_plan(TUF2_3, args, nulls, false, 0); if (ret != SPI_OK_UPDATE) { FAIL_FRAME_SET(&funcctx->max_calls, TUF2_statements[2].sql); dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); continue; } num_updated += SPI_processed; } #ifdef DEBUG sprintf(sql, SQLTUF2_4, trade_list); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ args[0] = Int64GetDatum(atoll(trade_list)); ret = SPI_execute_plan(TUF2_4, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { l_tupdesc = SPI_tuptable->tupdesc; l_tuptable = SPI_tuptable; l_tuple = l_tuptable->vals[0]; strcat(values[i_settlement_amount], SPI_getvalue(l_tuple, l_tupdesc, 1)); strcat(values[i_settlement_cash_due_date], SPI_getvalue(l_tuple, l_tupdesc, 2)); strcat(values[i_settlement_cash_type], "\""); strcat(values[i_settlement_cash_type], SPI_getvalue(l_tuple, l_tupdesc, 3)); strcat(values[i_settlement_cash_type], "\""); } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF2_statements[3].sql); dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); continue; } if (is_cash_str[0] == 't') { #ifdef DEBUG sprintf(sql, SQLTUF2_5, trade_list); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TUF2_5, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { l_tupdesc = SPI_tuptable->tupdesc; l_tuptable = SPI_tuptable; l_tuple = l_tuptable->vals[0]; if (num_cash > 0) { strcat(values[i_cash_transaction_amount], ","); strcat(values[i_cash_transaction_dts], ","); strcat(values[i_cash_transaction_name], ","); } strcat(values[i_cash_transaction_amount], SPI_getvalue(l_tuple, l_tupdesc, 1)); strcat(values[i_cash_transaction_dts], SPI_getvalue(l_tuple, l_tupdesc, 2)); strcat(values[i_cash_transaction_name], "\""); strcat(values[i_cash_transaction_name], SPI_getvalue(l_tuple, l_tupdesc, 3)); strcat(values[i_cash_transaction_name], "\""); ++num_cash; } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF2_statements[4].sql); dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); continue; } } else { if (num_cash > 0) { strcat(values[i_cash_transaction_amount], ","); strcat(values[i_cash_transaction_dts], ","); strcat(values[i_cash_transaction_name], ","); } strcat(values[i_cash_transaction_amount], "0"); strcat(values[i_cash_transaction_dts], "1970-1-1 0:0:0"); strcat(values[i_cash_transaction_name], "\"\""); ++num_cash; } #ifdef DEBUG sprintf(sql, SQLTUF2_6, trade_list); elog(NOTICE, "SQL\n%s", sql); #endif /* DEBUG */ ret = SPI_execute_plan(TUF2_6, args, nulls, true, 0); if (ret == SPI_OK_SELECT && SPI_processed > 0) { l_tupdesc = SPI_tuptable->tupdesc; l_tuptable = SPI_tuptable; } else { FAIL_FRAME_SET(&funcctx->max_calls, TUF2_statements[5].sql); dump_tuf2_inputs(acct_id, end_trade_dts, max_trades, max_updates, start_trade_dts); continue; } strcat(values[i_trade_history_dts], "{"); strcat(values[i_trade_history_status_id], "{"); for (j = 0; j < SPI_processed; j ++) { if (j > 0) { strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } l_tuple = l_tuptable->vals[j]; strcat(values[i_trade_history_dts], SPI_getvalue(l_tuple, l_tupdesc, 1)); strcat(values[i_trade_history_status_id], "\""); strcat(values[i_trade_history_status_id], SPI_getvalue(l_tuple, l_tupdesc, 2)); strcat(values[i_trade_history_status_id], "\""); } for (j = SPI_processed; j < 3; j++) { if (j > 0) { strcat(values[i_trade_history_dts], ","); strcat(values[i_trade_history_status_id], ","); } strcat(values[i_trade_history_dts], "NULL"); strcat(values[i_trade_history_status_id], "\"\""); } strcat(values[i_trade_history_dts], "}"); strcat(values[i_trade_history_status_id], "}"); } strcat(values[i_bid_price], "}"); strcat(values[i_exec_name], "}"); strcat(values[i_is_cash], "}"); strcat(values[i_trade_list], "}"); strcat(values[i_trade_price], "}"); strcat(values[i_settlement_amount], "}"); strcat(values[i_settlement_cash_due_date], "}"); strcat(values[i_settlement_cash_type], "}"); strcat(values[i_cash_transaction_amount], "}"); strcat(values[i_cash_transaction_dts], "}"); strcat(values[i_cash_transaction_name], "}"); strcat(values[i_trade_history_dts], "}"); strcat(values[i_trade_history_status_id], "}"); sprintf(values[i_num_found], "%d", num_found); sprintf(values[i_num_updated], "%d", num_updated); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); } /* * generate attribute metadata needed later to produce tuples from raw * C strings */ attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) { /* do when there is more left to send */ HeapTuple tuple; Datum result; #ifdef DEBUG for (i = 0; i < 15; i++) { elog(NOTICE, "TUF2 OUT: %d %s", i, values[i]); } #endif /* DEBUG */ /* Build a tuple. */ tuple = BuildTupleFromCStrings(attinmeta, values); /* Make the tuple into a datum. */ result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { /* Do when there is no more left. */ SPI_finish(); SRF_RETURN_DONE(funcctx); } }
Datum gin_leafpage_items(PG_FUNCTION_ARGS) { bytea *raw_page = PG_GETARG_BYTEA_P(0); int raw_page_size; FuncCallContext *fctx; gin_leafpage_items_state *inter_call_data; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use raw page functions")))); raw_page_size = VARSIZE(raw_page) - VARHDRSZ; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext mctx; Page page; GinPageOpaque opaq; if (raw_page_size < BLCKSZ) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input page too small (%d bytes)", raw_page_size))); page = VARDATA(raw_page); if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData))) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input page is not a valid GIN data leaf page"), errdetail("Special size %d, expected %d", (int) PageGetSpecialSize(page), (int) MAXALIGN(sizeof(GinPageOpaqueData))))); opaq = (GinPageOpaque) PageGetSpecialPointer(page); if (opaq->flags != (GIN_DATA | GIN_LEAF | GIN_COMPRESSED)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input page is not a compressed GIN data leaf page"), errdetail("Flags %04X, expected %04X", opaq->flags, (GIN_DATA | GIN_LEAF | GIN_COMPRESSED)))); fctx = SRF_FIRSTCALL_INIT(); mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); inter_call_data = palloc(sizeof(gin_leafpage_items_state)); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); inter_call_data->tupd = tupdesc; inter_call_data->seg = GinDataLeafPageGetPostingList(page); inter_call_data->lastseg = (GinPostingList *) (((char *) inter_call_data->seg) + GinDataLeafPageGetPostingListSize(page)); fctx->user_fctx = inter_call_data; MemoryContextSwitchTo(mctx); } fctx = SRF_PERCALL_SETUP(); inter_call_data = fctx->user_fctx; if (inter_call_data->seg != inter_call_data->lastseg) { GinPostingList *cur = inter_call_data->seg; HeapTuple resultTuple; Datum result; Datum values[3]; bool nulls[3]; int ndecoded, i; ItemPointer tids; Datum *tids_datum; memset(nulls, 0, sizeof(nulls)); values[0] = ItemPointerGetDatum(&cur->first); values[1] = UInt16GetDatum(cur->nbytes); /* build an array of decoded item pointers */ tids = ginPostingListDecode(cur, &ndecoded); tids_datum = (Datum *) palloc(ndecoded * sizeof(Datum)); for (i = 0; i < ndecoded; i++) tids_datum[i] = ItemPointerGetDatum(&tids[i]); values[2] = PointerGetDatum(construct_array(tids_datum, ndecoded, TIDOID, sizeof(ItemPointerData), false, 's')); pfree(tids_datum); pfree(tids); /* Build and return the result tuple. */ resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls); result = HeapTupleGetDatum(resultTuple); inter_call_data->seg = GinNextPostingListSegment(cur); SRF_RETURN_NEXT(fctx, result); } else SRF_RETURN_DONE(fctx); }
PGDLLEXPORT Datum one_to_many_withPoints(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_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, PGR_DBG("Initializing arrays"); int64_t* end_pidsArr; size_t size_end_pidsArr; end_pidsArr = (int64_t*) pgr_get_bigIntArray(&size_end_pidsArr, PG_GETARG_ARRAYTYPE_P(3)); process( pgr_text2char(PG_GETARG_TEXT_P(0)), pgr_text2char(PG_GETARG_TEXT_P(1)), PG_GETARG_INT64(2), end_pidsArr, size_end_pidsArr, PG_GETARG_BOOL(4), pgr_text2char(PG_GETARG_TEXT_P(5)), PG_GETARG_BOOL(6), PG_GETARG_BOOL(7), &result_tuples, &result_count); PGR_DBG("Cleaning arrays"); free(end_pidsArr); /* */ /*******************************************************************************/ 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 = (uint32_t)funcctx->call_cntr; max_calls = (uint32_t)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 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(call_cntr + 1); values[1] = Int32GetDatum(result_tuples[call_cntr].seq); values[2] = Int64GetDatum(result_tuples[call_cntr].end_id); values[3] = Int64GetDatum(result_tuples[call_cntr].node); values[4] = Int64GetDatum(result_tuples[call_cntr].edge); values[5] = Float8GetDatum(result_tuples[call_cntr].cost); values[6] = 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); } }