Datum HASHAPI_Hash_1_timestamptz(PG_FUNCTION_ARGS) { int32 num_segs; /* number of segments */ TimestampTz val1; /* varchar value */ unsigned int targetbucket; /* 0-based */ int16 algorithm; /* hashing algorithm */ Datum d1; Oid oid; /* Get number of segments */ num_segs = PG_GETARG_INT32(0); /* Get hashing algoriithm */ algorithm = PG_GETARG_INT16(1); /* Get the value to hash */ val1 = PG_GETARG_TIMESTAMPTZ(2); d1 = TimestampTzGetDatum(val1); /* create a CdbHash for this hash test. */ h = makeCdbHash(num_segs, algorithm); /* init cdb hash */ cdbhashinit(h); oid = TIMESTAMPTZOID; cdbhash(h, d1, oid); /* reduce the result hash value */ targetbucket = cdbhashreduce(h); PG_RETURN_INT32(targetbucket); /* return target bucket (segID) */ }
static HeapTuple FormErrorTuple(CdbSreh *cdbsreh) { bool nulls[NUM_ERRORTABLE_ATTR]; Datum values[NUM_ERRORTABLE_ATTR]; MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(cdbsreh->badrowcontext); /* Initialize all values for row to NULL */ MemSet(values, 0, NUM_ERRORTABLE_ATTR * sizeof(Datum)); MemSet(nulls, true, NUM_ERRORTABLE_ATTR * sizeof(bool)); /* command start time */ values[errtable_cmdtime - 1] = TimestampTzGetDatum(GetCurrentStatementStartTimestamp()); nulls[errtable_cmdtime - 1] = false; /* line number */ if (cdbsreh->linenumber > 0) { values[errtable_linenum - 1] = Int64GetDatum(cdbsreh->linenumber); nulls[errtable_linenum - 1] = false; } if(cdbsreh->is_server_enc) { /* raw data */ values[errtable_rawdata - 1] = DirectFunctionCall1(textin, CStringGetDatum(cdbsreh->rawdata)); nulls[errtable_rawdata - 1] = false; } else { /* raw bytes */ PreprocessByteaData(cdbsreh->rawdata); values[errtable_rawbytes - 1] = DirectFunctionCall1(byteain, CStringGetDatum(cdbsreh->rawdata)); nulls[errtable_rawbytes - 1] = false; } /* file name */ values[errtable_filename - 1] = DirectFunctionCall1(textin, CStringGetDatum(cdbsreh->filename)); nulls[errtable_filename - 1] = false; /* relation name */ values[errtable_relname - 1] = DirectFunctionCall1(textin, CStringGetDatum(cdbsreh->relname)); nulls[errtable_relname - 1] = false; /* error message */ values[errtable_errmsg - 1] = DirectFunctionCall1(textin, CStringGetDatum(cdbsreh->errmsg)); nulls[errtable_errmsg - 1] = false; MemoryContextSwitchTo(oldcontext); /* * And now we can form the input tuple. */ return heap_form_tuple(GetErrorTupleDesc(), values, nulls); }
/* * get_current_transaction_id returns a tuple with (databaseId, processId, * initiatorNodeIdentifier, transactionNumber, timestamp) that exists in the * shared memory associated with this backend. Note that if the backend * is not in a transaction, the function returns uninitialized data where * transactionNumber equals to 0. */ Datum get_current_transaction_id(PG_FUNCTION_ARGS) { TupleDesc tupleDescriptor = NULL; HeapTuple heapTuple = NULL; Datum values[5]; bool isNulls[5]; DistributedTransactionId *distributedTransctionId = NULL; CheckCitusVersion(ERROR); /* build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupleDescriptor) != TYPEFUNC_COMPOSITE) { elog(ERROR, "return type must be a row type"); } /* MyBackendData should always be avaliable, just out of paranoia */ if (!MyBackendData) { ereport(ERROR, (errmsg("backend is not ready for distributed transactions"))); } distributedTransctionId = GetCurrentDistributedTransactionId(); memset(values, 0, sizeof(values)); memset(isNulls, false, sizeof(isNulls)); /* first two fields do not change for this backend, so get directly */ values[0] = ObjectIdGetDatum(MyDatabaseId); values[1] = Int32GetDatum(MyProcPid); values[2] = Int32GetDatum(distributedTransctionId->initiatorNodeIdentifier); values[3] = UInt64GetDatum(distributedTransctionId->transactionNumber); /* provide a better output */ if (distributedTransctionId->initiatorNodeIdentifier != 0) { values[4] = TimestampTzGetDatum(distributedTransctionId->timestamp); } else { isNulls[4] = true; } heapTuple = heap_form_tuple(tupleDescriptor, values, isNulls); PG_RETURN_DATUM(HeapTupleGetDatum(heapTuple)); }
Datum pg_control_system(PG_FUNCTION_ARGS) { Datum values[4]; bool nulls[4]; TupleDesc tupdesc; HeapTuple htup; ControlFileData *ControlFile; bool crc_ok; /* * Construct a tuple descriptor for the result row. This must match this * function's pg_proc entry! */ tupdesc = CreateTemplateTupleDesc(4); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pg_control_version", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catalog_version_no", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "system_identifier", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pg_control_last_modified", TIMESTAMPTZOID, -1, 0); tupdesc = BlessTupleDesc(tupdesc); /* read the control file */ ControlFile = get_controlfile(DataDir, NULL, &crc_ok); if (!crc_ok) ereport(ERROR, (errmsg("calculated CRC checksum does not match value stored in file"))); values[0] = Int32GetDatum(ControlFile->pg_control_version); nulls[0] = false; values[1] = Int32GetDatum(ControlFile->catalog_version_no); nulls[1] = false; values[2] = Int64GetDatum(ControlFile->system_identifier); nulls[2] = false; values[3] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->time)); nulls[3] = false; htup = heap_form_tuple(tupdesc, values, nulls); PG_RETURN_DATUM(HeapTupleGetDatum(htup)); }
Datum orafce_sysdate(PG_FUNCTION_ARGS) { Datum sysdate; Datum sysdate_scaled; sysdate = DirectFunctionCall2(timestamptz_zone, CStringGetTextDatum(orafce_timezone), TimestampTzGetDatum(GetCurrentStatementStartTimestamp())); /* necessary to cast to timestamp(0) to emulate Oracle's date */ sysdate_scaled = DirectFunctionCall2(timestamp_scale, sysdate, Int32GetDatum(0)); PG_RETURN_DATUM(sysdate_scaled); }
static char * timeval_to_cstring(struct timeval tp) { TimestampTz tz; char *str; tz = (TimestampTz) tp.tv_sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY); #ifdef HAVE_INT64_TIMESTAMP tz = (tz * USECS_PER_SEC) + tp.tv_usec; #else tz = tz + (tp.tv_usec / 1000000.0); #endif str = DatumGetCString(DirectFunctionCall1(timestamptz_out, TimestampTzGetDatum(tz))); return str; }
Datum pg_last_committed_xact(PG_FUNCTION_ARGS) { TransactionId xid; TimestampTz ts; Datum values[2]; bool nulls[2]; TupleDesc tupdesc; HeapTuple htup; /* and construct a tuple with our data */ xid = GetLatestCommitTsData(&ts, NULL); /* * Construct a tuple descriptor for the result row. This must match this * function's pg_proc entry! */ tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "xid", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "timestamp", TIMESTAMPTZOID, -1, 0); tupdesc = BlessTupleDesc(tupdesc); if (!TransactionIdIsNormal(xid)) { memset(nulls, true, sizeof(nulls)); } else { values[0] = TransactionIdGetDatum(xid); nulls[0] = false; values[1] = TimestampTzGetDatum(ts); nulls[1] = false; } htup = heap_form_tuple(tupdesc, values, nulls); PG_RETURN_DATUM(HeapTupleGetDatum(htup)); }
/* * stat a file */ Datum pg_stat_file(PG_FUNCTION_ARGS) { text *filename_t = PG_GETARG_TEXT_P(0); char *filename; struct stat fst; Datum values[6]; bool isnull[6]; HeapTuple tuple; TupleDesc tupdesc; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to get file information")))); filename = convert_and_check_filename(filename_t); if (stat(filename, &fst) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat file \"%s\": %m", filename))); /* * This record type had better match the output parameters declared for me * in pg_proc.h. */ tupdesc = CreateTemplateTupleDesc(6, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "size", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "access", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "modification", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "change", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "creation", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "isdir", BOOLOID, -1, 0); BlessTupleDesc(tupdesc); memset(isnull, false, sizeof(isnull)); values[0] = Int64GetDatum((int64) fst.st_size); values[1] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_atime)); values[2] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_mtime)); /* Unix has file status change time, while Win32 has creation time */ #if !defined(WIN32) && !defined(__CYGWIN__) values[3] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime)); isnull[4] = true; #else isnull[3] = true; values[4] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime)); #endif values[5] = BoolGetDatum(S_ISDIR(fst.st_mode)); tuple = heap_form_tuple(tupdesc, values, isnull); pfree(filename); PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); }
/* * Returns activity of PG backends. */ Datum pg_stat_get_activity(PG_FUNCTION_ARGS) { #define PG_STAT_GET_ACTIVITY_COLS 22 int num_backends = pgstat_fetch_stat_numbackends(); int curr_backend; int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0); ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; Tuplestorestate *tupstore; MemoryContext per_query_ctx; MemoryContext oldcontext; /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not " \ "allowed in this context"))); /* 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"); per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); tupstore = tuplestore_begin_heap(true, false, work_mem); rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = tupstore; rsinfo->setDesc = tupdesc; MemoryContextSwitchTo(oldcontext); /* 1-based index */ for (curr_backend = 1; curr_backend <= num_backends; curr_backend++) { /* for each row */ Datum values[PG_STAT_GET_ACTIVITY_COLS]; bool nulls[PG_STAT_GET_ACTIVITY_COLS]; LocalPgBackendStatus *local_beentry; PgBackendStatus *beentry; MemSet(values, 0, sizeof(values)); MemSet(nulls, 0, sizeof(nulls)); if (pid != -1) { /* Skip any which are not the one we're looking for. */ PgBackendStatus *be = pgstat_fetch_stat_beentry(curr_backend); if (!be || be->st_procpid != pid) continue; } /* Get the next one in the list */ local_beentry = pgstat_fetch_stat_local_beentry(curr_backend); if (!local_beentry) continue; beentry = &local_beentry->backendStatus; if (!beentry) { int i; for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++) nulls[i] = true; nulls[5] = false; values[5] = CStringGetTextDatum("<backend information not available>"); tuplestore_putvalues(tupstore, tupdesc, values, nulls); continue; } /* 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; if (TransactionIdIsValid(local_beentry->backend_xid)) values[14] = TransactionIdGetDatum(local_beentry->backend_xid); else nulls[14] = true; if (TransactionIdIsValid(local_beentry->backend_xmin)) values[15] = TransactionIdGetDatum(local_beentry->backend_xmin); else nulls[15] = true; if (beentry->st_ssl) { values[16] = BoolGetDatum(true); /* ssl */ values[17] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version); values[18] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher); values[19] = Int32GetDatum(beentry->st_sslstatus->ssl_bits); values[20] = BoolGetDatum(beentry->st_sslstatus->ssl_compression); values[21] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn); } else { values[16] = BoolGetDatum(false); /* ssl */ nulls[17] = nulls[18] = nulls[19] = nulls[20] = nulls[21] = true; } /* Values only available to role member */ if (has_privs_of_role(GetUserId(), beentry->st_userid)) { SockAddr zero_clientaddr; switch (beentry->st_state) { case STATE_IDLE: values[4] = CStringGetTextDatum("idle"); break; case STATE_RUNNING: values[4] = CStringGetTextDatum("active"); break; case STATE_IDLEINTRANSACTION: values[4] = CStringGetTextDatum("idle in transaction"); break; case STATE_FASTPATH: values[4] = CStringGetTextDatum("fastpath function call"); break; case STATE_IDLEINTRANSACTION_ABORTED: values[4] = CStringGetTextDatum("idle in transaction (aborted)"); break; case STATE_DISABLED: values[4] = CStringGetTextDatum("disabled"); break; case STATE_UNDEFINED: nulls[4] = true; break; } values[5] = CStringGetTextDatum(beentry->st_activity); values[6] = BoolGetDatum(beentry->st_waiting); if (beentry->st_xact_start_timestamp != 0) values[7] = TimestampTzGetDatum(beentry->st_xact_start_timestamp); else nulls[7] = true; if (beentry->st_activity_start_timestamp != 0) values[8] = TimestampTzGetDatum(beentry->st_activity_start_timestamp); else nulls[8] = true; if (beentry->st_proc_start_timestamp != 0) values[9] = TimestampTzGetDatum(beentry->st_proc_start_timestamp); else nulls[9] = true; if (beentry->st_state_start_timestamp != 0) values[10] = TimestampTzGetDatum(beentry->st_state_start_timestamp); else nulls[10] = 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[11] = true; nulls[12] = true; nulls[13] = 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[11] = DirectFunctionCall1(inet_in, CStringGetDatum(remote_host)); if (beentry->st_clienthostname && beentry->st_clienthostname[0]) values[12] = CStringGetTextDatum(beentry->st_clienthostname); else nulls[12] = true; values[13] = Int32GetDatum(atoi(remote_port)); } else { nulls[11] = true; nulls[12] = true; nulls[13] = 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[11] = true; nulls[12] = true; values[13] = DatumGetInt32(-1); } else { /* Unknown address type, should never happen */ nulls[11] = true; nulls[12] = true; nulls[13] = true; } } } else { /* No permissions to view data about this session */ values[5] = CStringGetTextDatum("<insufficient privilege>"); nulls[4] = true; nulls[6] = true; nulls[7] = true; nulls[8] = true; nulls[9] = true; nulls[10] = true; nulls[11] = true; nulls[12] = true; nulls[13] = true; } tuplestore_putvalues(tupstore, tupdesc, values, nulls); /* If only a single backend was requested, and we found it, break. */ if (pid != -1) break; } /* clean up and return the tuplestore */ tuplestore_donestoring(tupstore); return (Datum) 0; }
/* * update segment configuration in catalog and shared memory */ static bool probeUpdateConfig(FtsSegmentStatusChange *changes, int changeCount) { Relation configrel; Relation histrel; SysScanDesc sscan; ScanKeyData scankey; HeapTuple configtuple; HeapTuple newtuple; HeapTuple histtuple; Datum configvals[Natts_gp_segment_configuration]; bool confignulls[Natts_gp_segment_configuration] = { false }; bool repls[Natts_gp_segment_configuration] = { false }; Datum histvals[Natts_gp_configuration_history]; bool histnulls[Natts_gp_configuration_history] = { false }; bool valid; bool primary; bool changelogging; int i; char desc[SQL_CMD_BUF_SIZE]; /* * Commit/abort transaction below will destroy * CurrentResourceOwner. We need it for catalog reads. */ ResourceOwner save = CurrentResourceOwner; StartTransactionCommand(); elog(LOG, "probeUpdateConfig called for %d changes", changeCount); histrel = heap_open(GpConfigHistoryRelationId, RowExclusiveLock); configrel = heap_open(GpSegmentConfigRelationId, RowExclusiveLock); for (i = 0; i < changeCount; i++) { FtsSegmentStatusChange *change = &changes[i]; valid = (changes[i].newStatus & FTS_STATUS_ALIVE); primary = (changes[i].newStatus & FTS_STATUS_PRIMARY); changelogging = (changes[i].newStatus & FTS_STATUS_CHANGELOGGING); if (changelogging) { Assert(failover_strategy == 'f'); Assert(primary && valid); } Assert((valid || !primary) && "Primary cannot be down"); /* * Insert new tuple into gp_configuration_history catalog. */ histvals[Anum_gp_configuration_history_time-1] = TimestampTzGetDatum(GetCurrentTimestamp()); histvals[Anum_gp_configuration_history_dbid-1] = Int16GetDatum(changes[i].dbid); snprintf(desc, sizeof(desc), "FTS: content %d fault marking status %s%s role %c", change->segindex, valid ? "UP" : "DOWN", (changelogging) ? " mode: change-tracking" : "", primary ? 'p' : 'm'); histvals[Anum_gp_configuration_history_desc-1] = CStringGetTextDatum(desc); histtuple = heap_form_tuple(RelationGetDescr(histrel), histvals, histnulls); simple_heap_insert(histrel, histtuple); CatalogUpdateIndexes(histrel, histtuple); /* * Find and update gp_segment_configuration tuple. */ ScanKeyInit(&scankey, Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(changes[i].dbid)); sscan = systable_beginscan(configrel, GpSegmentConfigDbidIndexId, true, SnapshotNow, 1, &scankey); configtuple = systable_getnext(sscan); if (!HeapTupleIsValid(configtuple)) { elog(ERROR, "FTS cannot find dbid=%d in %s", changes[i].dbid, RelationGetRelationName(configrel)); } configvals[Anum_gp_segment_configuration_role-1] = CharGetDatum(primary ? 'p' : 'm'); repls[Anum_gp_segment_configuration_role-1] = true; configvals[Anum_gp_segment_configuration_status-1] = CharGetDatum(valid ? 'u' : 'd'); repls[Anum_gp_segment_configuration_status-1] = true; if (changelogging) { configvals[Anum_gp_segment_configuration_mode-1] = CharGetDatum('c'); } repls[Anum_gp_segment_configuration_mode-1] = changelogging; newtuple = heap_modify_tuple(configtuple, RelationGetDescr(configrel), configvals, confignulls, repls); simple_heap_update(configrel, &configtuple->t_self, newtuple); CatalogUpdateIndexes(configrel, newtuple); systable_endscan(sscan); pfree(newtuple); /* * Update shared memory */ ftsProbeInfo->fts_status[changes[i].dbid] = changes[i].newStatus; } heap_close(histrel, RowExclusiveLock); heap_close(configrel, RowExclusiveLock); SIMPLE_FAULT_INJECTOR(FtsWaitForShutdown); /* * Do not block shutdown. We will always get a change to update * gp_segment_configuration in subsequent probes upon database * restart. */ if (shutdown_requested) { elog(LOG, "Shutdown in progress, ignoring FTS prober updates."); return false; } CommitTransactionCommand(); CurrentResourceOwner = save; return true; }
Datum pg_control_checkpoint(PG_FUNCTION_ARGS) { Datum values[19]; bool nulls[19]; TupleDesc tupdesc; HeapTuple htup; ControlFileData *ControlFile; XLogSegNo segno; char xlogfilename[MAXFNAMELEN]; /* * Construct a tuple descriptor for the result row. This must match this * function's pg_proc entry! */ tupdesc = CreateTemplateTupleDesc(19, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "checkpoint_location", LSNOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "prior_location", LSNOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "redo_location", LSNOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "redo_wal_file", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "timeline_id", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "prev_timeline_id", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 7, "full_page_writes", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 8, "next_xid", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 9, "next_oid", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 10, "next_multixact_id", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 11, "next_multi_offset", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 12, "oldest_xid", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 13, "oldest_xid_dbid", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 14, "oldest_active_xid", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 15, "oldest_multi_xid", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 16, "oldest_multi_dbid", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 17, "oldest_commit_ts_xid", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 18, "newest_commit_ts_xid", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 19, "checkpoint_time", TIMESTAMPTZOID, -1, 0); tupdesc = BlessTupleDesc(tupdesc); /* Read the control file. */ ControlFile = get_controlfile(DataDir, NULL); /* * Calculate name of the WAL file containing the latest checkpoint's REDO * start point. */ XLByteToSeg(ControlFile->checkPointCopy.redo, segno); XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID, segno); /* Populate the values and null arrays */ values[0] = LSNGetDatum(ControlFile->checkPoint); nulls[0] = false; values[1] = LSNGetDatum(ControlFile->prevCheckPoint); nulls[1] = false; values[2] = LSNGetDatum(ControlFile->checkPointCopy.redo); nulls[2] = false; values[3] = CStringGetTextDatum(xlogfilename); nulls[3] = false; values[4] = Int32GetDatum(ControlFile->checkPointCopy.ThisTimeLineID); nulls[4] = false; values[5] = Int32GetDatum(ControlFile->checkPointCopy.PrevTimeLineID); nulls[5] = false; values[6] = BoolGetDatum(ControlFile->checkPointCopy.fullPageWrites); nulls[6] = false; values[7] = CStringGetTextDatum(psprintf("%u:%u", ControlFile->checkPointCopy.nextXidEpoch, ControlFile->checkPointCopy.nextXid)); nulls[7] = false; values[8] = ObjectIdGetDatum(ControlFile->checkPointCopy.nextOid); nulls[8] = false; values[9] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMulti); nulls[9] = false; values[10] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMultiOffset); nulls[10] = false; values[11] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestXid); nulls[11] = false; values[12] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestXidDB); nulls[12] = false; values[13] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestActiveXid); nulls[13] = false; values[14] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestMulti); nulls[14] = false; values[15] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestMultiDB); nulls[15] = false; values[16] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestCommitTsXid); nulls[16] = false; values[17] = TransactionIdGetDatum(ControlFile->checkPointCopy.newestCommitTsXid); nulls[17] = false; values[18] = TimestampTzGetDatum( time_t_to_timestamptz(ControlFile->checkPointCopy.time)); nulls[18] = false; htup = heap_form_tuple(tupdesc, values, nulls); PG_RETURN_DATUM(HeapTupleGetDatum(htup)); }
/* Generic function to return a directory listing of files */ static Datum pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir) { FuncCallContext *funcctx; struct dirent *de; directory_fctx *fctx; 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(3, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "size", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "modification", TIMESTAMPTZOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); fctx->location = pstrdup(dir); fctx->dirdesc = AllocateDir(fctx->location); if (!fctx->dirdesc) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open 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) { Datum values[3]; bool nulls[3]; char path[MAXPGPATH * 2]; struct stat attrib; HeapTuple tuple; /* Skip hidden files */ if (de->d_name[0] == '.') continue; /* Get the file info */ snprintf(path, sizeof(path), "%s/%s", fctx->location, de->d_name); if (stat(path, &attrib) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat directory \"%s\": %m", dir))); /* Ignore anything but regular files */ if (!S_ISREG(attrib.st_mode)) continue; values[0] = CStringGetTextDatum(de->d_name); values[1] = Int64GetDatum((int64) attrib.st_size); values[2] = TimestampTzGetDatum(time_t_to_timestamptz(attrib.st_mtime)); memset(nulls, 0, sizeof(nulls)); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); } FreeDir(fctx->dirdesc); SRF_RETURN_DONE(funcctx); }
/* * get_all_active_transactions returns all the avaliable information about all * the active backends. */ Datum get_all_active_transactions(PG_FUNCTION_ARGS) { ReturnSetInfo *returnSetInfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupleDescriptor = NULL; Tuplestorestate *tupleStore = NULL; MemoryContext perQueryContext = NULL; MemoryContext oldContext = NULL; int backendIndex = 0; Datum values[5]; bool isNulls[5]; CheckCitusVersion(ERROR); /* check to see if caller supports us returning a tuplestore */ if (returnSetInfo == NULL || !IsA(returnSetInfo, ReturnSetInfo)) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context " \ "that cannot accept a set"))); } if (!(returnSetInfo->allowedModes & SFRM_Materialize)) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not " \ "allowed in this context"))); } /* build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupleDescriptor) != TYPEFUNC_COMPOSITE) { elog(ERROR, "return type must be a row type"); } perQueryContext = returnSetInfo->econtext->ecxt_per_query_memory; oldContext = MemoryContextSwitchTo(perQueryContext); tupleStore = tuplestore_begin_heap(true, false, work_mem); returnSetInfo->returnMode = SFRM_Materialize; returnSetInfo->setResult = tupleStore; returnSetInfo->setDesc = tupleDescriptor; MemoryContextSwitchTo(oldContext); /* * We don't want to initialize memory while spinlock is held so we * prefer to do it here. This initialization is done only for the first * row. */ memset(values, 0, sizeof(values)); memset(isNulls, false, sizeof(isNulls)); /* we're reading all distributed transactions, prevent new backends */ LockBackendSharedMemory(LW_SHARED); for (backendIndex = 0; backendIndex < MaxBackends; ++backendIndex) { BackendData *currentBackend = &backendManagementShmemData->backends[backendIndex]; SpinLockAcquire(¤tBackend->mutex); /* we're only interested in active backends */ if (currentBackend->transactionId.transactionNumber == 0) { SpinLockRelease(¤tBackend->mutex); continue; } values[0] = ObjectIdGetDatum(currentBackend->databaseId); values[1] = Int32GetDatum(ProcGlobal->allProcs[backendIndex].pid); values[2] = Int32GetDatum(currentBackend->transactionId.initiatorNodeIdentifier); values[3] = UInt64GetDatum(currentBackend->transactionId.transactionNumber); values[4] = TimestampTzGetDatum(currentBackend->transactionId.timestamp); SpinLockRelease(¤tBackend->mutex); tuplestore_putvalues(tupleStore, tupleDescriptor, values, isNulls); /* * We don't want to initialize memory while spinlock is held so we * prefer to do it here. This initialization is done for the rows * starting from the second one. */ memset(values, 0, sizeof(values)); memset(isNulls, false, sizeof(isNulls)); } UnlockBackendSharedMemory(); /* clean up and return the tuplestore */ tuplestore_donestoring(tupleStore); PG_RETURN_VOID(); }
static Datum dbms_pipe_unpack_message(PG_FUNCTION_ARGS, message_data_type dtype) { Oid tupType; void *ptr; message_data_type type; int32 size; Datum result; message_data_type next_type; if (input_buffer == NULL || input_buffer->items_count <= 0 || input_buffer->next == NULL || input_buffer->next->type == IT_NO_MORE_ITEMS) PG_RETURN_NULL(); next_type = input_buffer->next->type; if (next_type != dtype) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("datatype mismatch"), errdetail("unpack unexpected type: %d", next_type))); ptr = unpack_field(input_buffer, &type, &size, &tupType); Assert(ptr != NULL); switch (type) { case IT_TIMESTAMPTZ: result = TimestampTzGetDatum(*(TimestampTz*)ptr); break; case IT_DATE: result = DateADTGetDatum(*(DateADT*)ptr); break; case IT_VARCHAR: case IT_NUMBER: case IT_BYTEA: result = PointerGetDatum(cstring_to_text_with_len(ptr, size)); break; case IT_RECORD: { #if PG_VERSION_NUM >= 120000 LOCAL_FCINFO(info, 3); #else FunctionCallInfoData info_data; FunctionCallInfo info = &info_data; #endif StringInfoData buf; text *data = cstring_to_text_with_len(ptr, size); buf.data = VARDATA(data); buf.len = VARSIZE(data) - VARHDRSZ; buf.maxlen = buf.len; buf.cursor = 0; /* * Normally one would call record_recv() using DirectFunctionCall3, * but that does not work since record_recv wants to cache some data * using fcinfo->flinfo->fn_extra. So we need to pass it our own * flinfo parameter. */ InitFunctionCallInfoData(*info, fcinfo->flinfo, 3, InvalidOid, NULL, NULL); init_args_3(info, PointerGetDatum(&buf), ObjectIdGetDatum(tupType), Int32GetDatum(-1)); result = record_recv(info); break; } default: elog(ERROR, "unexpected type: %d", type); result = (Datum) 0; /* keep compiler quiet */ } if (input_buffer->items_count == 0) { pfree(input_buffer); input_buffer = NULL; } PG_RETURN_DATUM(result); }
/* * pg_prepared_xact * Produce a view with one row per prepared transaction. * * This function is here so we don't have to export the * GlobalTransactionData struct definition. */ Datum pg_prepared_xact(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; Working_State *status; 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, "transaction", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "gid", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepared", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "ownerid", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "dbid", OIDOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); /* * Collect all the 2PC status information that we will format and send * out as a result set. */ status = (Working_State *) palloc(sizeof(Working_State)); funcctx->user_fctx = (void *) status; status->ngxacts = GetPreparedTransactionList(&status->array); status->currIdx = 0; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); status = (Working_State *) funcctx->user_fctx; while (status->array != NULL && status->currIdx < status->ngxacts) { GlobalTransaction gxact = &status->array[status->currIdx++]; Datum values[5]; bool nulls[5]; HeapTuple tuple; Datum result; if (!gxact->valid) continue; /* * Form tuple with appropriate data. */ MemSet(values, 0, sizeof(values)); MemSet(nulls, 0, sizeof(nulls)); values[0] = TransactionIdGetDatum(gxact->proc.xid); values[1] = CStringGetTextDatum(gxact->gid); values[2] = TimestampTzGetDatum(gxact->prepared_at); values[3] = ObjectIdGetDatum(gxact->owner); values[4] = ObjectIdGetDatum(gxact->proc.databaseId); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } 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(13, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid", OIDOID, -1, 0); 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_port", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 12, "sess_id", INT4OID, -1, 0); /* GPDB */ TupleDescInitEntry(tupdesc, (AttrNumber) 13, "waiting_resource", BOOLOID, -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[13]; bool nulls[13]; 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; } 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) { nulls[9] = true; nulls[10] = true; } else { clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host); values[9] = DirectFunctionCall1(inet_in, CStringGetDatum(remote_host)); values[10] = Int32GetDatum(atoi(remote_port)); } } 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; values[10] = DatumGetInt32(-1); } else { /* Unknown address type, should never happen */ nulls[9] = true; nulls[10] = true; } } values[12] = BoolGetDatum(beentry->st_waiting_resource); } 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[12] = true; } values[11] = Int32GetDatum(beentry->st_session_id); /* GPDB */ tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); } else { /* nothing left */ SRF_RETURN_DONE(funcctx); } }
/* * Function returning all workfile cache entries for one segment */ Datum gp_workfile_mgr_cache_entries(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int32 *crtIndexPtr; if (SRF_IS_FIRSTCALL()) { /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* Switch to memory context appropriate for multiple function calls */ MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* * Build a tuple descriptor for our result type * The number and type of attributes have to match the definition of the * view gp_workfile_mgr_cache_entries */ TupleDesc tupdesc = CreateTemplateTupleDesc(NUM_CACHE_ENTRIES_ELEM, false); Assert(NUM_CACHE_ENTRIES_ELEM == 12); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "segid", INT4OID, -1 /* typmod */, 0 /* attdim */); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "path", TEXTOID, -1 /* typmod */, 0 /* attdim */); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "hash", INT4OID, -1 /* typmod */, 0 /* attdim */); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "size", INT8OID, -1 /* typmod */, 0 /* attdim */); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "state", INT4OID, -1 /* typmod */, 0 /* attdim */); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "workmem", INT4OID, -1 /* typmod */, 0 /* attdim */); TupleDescInitEntry(tupdesc, (AttrNumber) 7, "optype", TEXTOID, -1 /* typmod */, 0 /* attdim */); TupleDescInitEntry(tupdesc, (AttrNumber) 8, "slice", INT4OID, -1 /* typmod */, 0 /* attdim */); TupleDescInitEntry(tupdesc, (AttrNumber) 9, "sessionid", INT4OID, -1 /* typmod */, 0 /* attdim */); TupleDescInitEntry(tupdesc, (AttrNumber) 10, "commandid", INT4OID, -1 /* typmod */, 0 /* attdim */); TupleDescInitEntry(tupdesc, (AttrNumber) 11, "query_start", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 12, "numfiles", INT4OID, -1 /* typmod */, 0 /* attdim */); funcctx->tuple_desc = BlessTupleDesc(tupdesc); crtIndexPtr = (int32 *) palloc(sizeof(*crtIndexPtr)); *crtIndexPtr = 0; funcctx->user_fctx = crtIndexPtr; MemoryContextSwitchTo(oldcontext); } Cache *cache = workfile_mgr_get_cache(); funcctx = SRF_PERCALL_SETUP(); crtIndexPtr = (int32 *) funcctx->user_fctx; while (true) { CacheEntry *crtEntry = next_entry_to_list(cache, crtIndexPtr); if (!crtEntry) { /* Reached the end of the entry array, we're done */ SRF_RETURN_DONE(funcctx); } Datum values[NUM_CACHE_ENTRIES_ELEM]; bool nulls[NUM_CACHE_ENTRIES_ELEM]; MemSet(nulls, 0, sizeof(nulls)); workfile_set *work_set = CACHE_ENTRY_PAYLOAD(crtEntry); char work_set_path[MAXPGPATH] = ""; char *work_set_operator_name = NULL; /* * Lock entry in order to read its payload * Don't call any functions that can get interrupted or * that palloc memory while holding this lock. */ Cache_LockEntry(cache, crtEntry); if (!should_list_entry(crtEntry)) { Cache_UnlockEntry(cache, crtEntry); continue; } values[0] = Int32GetDatum(GpIdentity.segindex); strlcpy(work_set_path, work_set->path, MAXPGPATH); values[2] = UInt32GetDatum(crtEntry->hashvalue); int64 work_set_size = work_set->size; if (crtEntry->state == CACHE_ENTRY_ACQUIRED) { /* * work_set->size is not updated until the entry is cached. * For in-progress queries, the up-to-date size is stored in * work_set->in_progress_size. */ work_set_size = work_set->in_progress_size; } values[3] = Int64GetDatum(work_set_size); values[4] = UInt32GetDatum(crtEntry->state); values[5] = UInt32GetDatum(work_set->metadata.operator_work_mem); work_set_operator_name = gp_workfile_operator_name(work_set->node_type); values[7] = UInt32GetDatum(work_set->slice_id); values[8] = UInt32GetDatum(work_set->session_id); values[9] = UInt32GetDatum(work_set->command_count); values[10] = TimestampTzGetDatum(work_set->session_start_time); values[11] = UInt32GetDatum(work_set->no_files); /* Done reading from the payload of the entry, release lock */ Cache_UnlockEntry(cache, crtEntry); /* * Fill in the rest of the entries of the tuple with data copied * from the descriptor. * CStringGetTextDatum calls palloc so we cannot do this while * holding the lock above. */ values[1] = CStringGetTextDatum(work_set_path); values[6] = CStringGetTextDatum(work_set_operator_name); HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); Datum result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } }
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))); }
/** * Marks the given db as in-sync in the segment configuration. */ void FtsMarkSegmentsInSync(CdbComponentDatabaseInfo *primary, CdbComponentDatabaseInfo *mirror) { if (!FTS_STATUS_ISALIVE(primary->dbid, ftsProbeInfo->fts_status) || !FTS_STATUS_ISALIVE(mirror->dbid, ftsProbeInfo->fts_status) || !FTS_STATUS_ISPRIMARY(primary->dbid, ftsProbeInfo->fts_status) || FTS_STATUS_ISPRIMARY(mirror->dbid, ftsProbeInfo->fts_status) || FTS_STATUS_IS_SYNCED(primary->dbid, ftsProbeInfo->fts_status) || FTS_STATUS_IS_SYNCED(mirror->dbid, ftsProbeInfo->fts_status) || FTS_STATUS_IS_CHANGELOGGING(primary->dbid, ftsProbeInfo->fts_status) || FTS_STATUS_IS_CHANGELOGGING(mirror->dbid, ftsProbeInfo->fts_status)) { FtsRequestPostmasterShutdown(primary, mirror); } if (ftsProbeInfo->fts_pauseProbes) { return; } uint8 segStatus=0; Relation configrel; Relation histrel; ScanKeyData scankey; SysScanDesc sscan; HeapTuple configtuple; HeapTuple newtuple; HeapTuple histtuple; Datum configvals[Natts_gp_segment_configuration]; bool confignulls[Natts_gp_segment_configuration] = { false }; bool repls[Natts_gp_segment_configuration] = { false }; Datum histvals[Natts_gp_configuration_history]; bool histnulls[Natts_gp_configuration_history] = { false }; char *desc = "FTS: changed segment to insync from resync."; /* * Commit/abort transaction below will destroy * CurrentResourceOwner. We need it for catalog reads. */ ResourceOwner save = CurrentResourceOwner; StartTransactionCommand(); /* update primary */ segStatus = ftsProbeInfo->fts_status[primary->dbid]; segStatus |= FTS_STATUS_SYNCHRONIZED; ftsProbeInfo->fts_status[primary->dbid] = segStatus; /* update mirror */ segStatus = ftsProbeInfo->fts_status[mirror->dbid]; segStatus |= FTS_STATUS_SYNCHRONIZED; ftsProbeInfo->fts_status[mirror->dbid] = segStatus; histrel = heap_open(GpConfigHistoryRelationId, RowExclusiveLock); configrel = heap_open(GpSegmentConfigRelationId, RowExclusiveLock); /* update gp_segment_configuration to insync */ ScanKeyInit(&scankey, Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(primary->dbid)); sscan = systable_beginscan(configrel, GpSegmentConfigDbidIndexId, true, SnapshotNow, 1, &scankey); configtuple = systable_getnext(sscan); if (!HeapTupleIsValid(configtuple)) { elog(ERROR,"FTS cannot find dbid (%d, %d) in %s", primary->dbid, mirror->dbid, RelationGetRelationName(configrel)); } configvals[Anum_gp_segment_configuration_mode-1] = CharGetDatum('s'); repls[Anum_gp_segment_configuration_mode-1] = true; newtuple = heap_modify_tuple(configtuple, RelationGetDescr(configrel), configvals, confignulls, repls); simple_heap_update(configrel, &configtuple->t_self, newtuple); CatalogUpdateIndexes(configrel, newtuple); systable_endscan(sscan); ScanKeyInit(&scankey, Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(mirror->dbid)); sscan = systable_beginscan(configrel, GpSegmentConfigDbidIndexId, true, SnapshotNow, 1, &scankey); configtuple = systable_getnext(sscan); if (!HeapTupleIsValid(configtuple)) { elog(ERROR,"FTS cannot find dbid (%d, %d) in %s", primary->dbid, mirror->dbid, RelationGetRelationName(configrel)); } newtuple = heap_modify_tuple(configtuple, RelationGetDescr(configrel), configvals, confignulls, repls); simple_heap_update(configrel, &configtuple->t_self, newtuple); CatalogUpdateIndexes(configrel, newtuple); systable_endscan(sscan); /* update configuration history */ histvals[Anum_gp_configuration_history_time-1] = TimestampTzGetDatum(GetCurrentTimestamp()); histvals[Anum_gp_configuration_history_dbid-1] = Int16GetDatum(primary->dbid); histvals[Anum_gp_configuration_history_desc-1] = CStringGetTextDatum(desc); histtuple = heap_form_tuple(RelationGetDescr(histrel), histvals, histnulls); simple_heap_insert(histrel, histtuple); CatalogUpdateIndexes(histrel, histtuple); histvals[Anum_gp_configuration_history_dbid-1] = Int16GetDatum(mirror->dbid); histtuple = heap_form_tuple(RelationGetDescr(histrel), histvals, histnulls); simple_heap_insert(histrel, histtuple); CatalogUpdateIndexes(histrel, histtuple); ereport(LOG, (errmsg("FTS: resynchronization of mirror (dbid=%d, content=%d) on %s:%d has completed.", mirror->dbid, mirror->segindex, mirror->address, mirror->port ), errSendAlert(true))); heap_close(histrel, RowExclusiveLock); heap_close(configrel, RowExclusiveLock); /* * Do not block shutdown. We will always get a change to update * gp_segment_configuration in subsequent probes upon database * restart. */ if (shutdown_requested) { elog(LOG, "Shutdown in progress, ignoring FTS prober updates."); return; } CommitTransactionCommand(); CurrentResourceOwner = save; }