/* * CreateTupleDescCopyConstr * This function creates a new TupleDesc by copying from an existing * TupleDesc (including its constraints and defaults). */ TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc) { TupleDesc desc; TupleConstr *constr = tupdesc->constr; int i; desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid); for (i = 0; i < desc->natts; i++) { memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_FIXED_PART_SIZE); } if (constr) { TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr)); cpy->has_not_null = constr->has_not_null; if ((cpy->num_defval = constr->num_defval) > 0) { cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault)); memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault)); for (i = cpy->num_defval - 1; i >= 0; i--) { if (constr->defval[i].adbin) cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin); } } if ((cpy->num_check = constr->num_check) > 0) { cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck)); memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck)); for (i = cpy->num_check - 1; i >= 0; i--) { if (constr->check[i].ccname) cpy->check[i].ccname = pstrdup(constr->check[i].ccname); if (constr->check[i].ccbin) cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin); cpy->check[i].ccvalid = constr->check[i].ccvalid; cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit; } } desc->constr = cpy; } desc->tdtypeid = tupdesc->tdtypeid; desc->tdtypmod = tupdesc->tdtypmod; return desc; }
/* * BuildDescForRelation * * Given a relation schema (list of ColumnDef nodes), build a TupleDesc. * * Note: the default assumption is no OIDs; caller may modify the returned * TupleDesc if it wants OIDs. Also, tdtypeid will need to be filled in * later on. */ TupleDesc BuildDescForRelation(List *schema) { int natts; AttrNumber attnum; ListCell *l; TupleDesc desc; TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr)); char *attname; int32 atttypmod; int attdim; /* * allocate a new tuple descriptor */ natts = list_length(schema); desc = CreateTemplateTupleDesc(natts, false); constr->has_not_null = false; attnum = 0; foreach(l, schema) { ColumnDef *entry = lfirst(l); /* * for each entry in the list, get the name and type information from * the list and have TupleDescInitEntry fill in the attribute * information we need. */ attnum++; attname = entry->colname; atttypmod = entry->typname->typmod; attdim = list_length(entry->typname->arrayBounds); if (entry->typname->setof) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("column \"%s\" cannot be declared SETOF", attname))); TupleDescInitEntry(desc, attnum, attname, typenameTypeId(NULL, entry->typname), atttypmod, attdim); /* Fill in additional stuff not handled by TupleDescInitEntry */ if (entry->is_not_null) constr->has_not_null = true; desc->attrs[attnum - 1]->attnotnull = entry->is_not_null; desc->attrs[attnum - 1]->attislocal = entry->is_local; desc->attrs[attnum - 1]->attinhcount = entry->inhcount; }
/* * Count the number of all-visible and all-frozen pages in the visibility * map for a particular relation. */ Datum pg_visibility_map_summary(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); Relation rel; BlockNumber nblocks; BlockNumber blkno; Buffer vmbuffer = InvalidBuffer; int64 all_visible = 0; int64 all_frozen = 0; TupleDesc tupdesc; Datum values[2]; bool nulls[2]; rel = relation_open(relid, AccessShareLock); /* Only some relkinds have a visibility map */ check_relation_relkind(rel); nblocks = RelationGetNumberOfBlocks(rel); for (blkno = 0; blkno < nblocks; ++blkno) { int32 mapbits; /* Make sure we are interruptible. */ CHECK_FOR_INTERRUPTS(); /* Get map info. */ mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer); if ((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0) ++all_visible; if ((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0) ++all_frozen; } /* Clean up. */ if (vmbuffer != InvalidBuffer) ReleaseBuffer(vmbuffer); relation_close(rel, AccessShareLock); tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "all_visible", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "all_frozen", INT8OID, -1, 0); tupdesc = BlessTupleDesc(tupdesc); MemSet(nulls, 0, sizeof(nulls)); values[0] = Int64GetDatum(all_visible); values[1] = Int64GetDatum(all_frozen); PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); }
Datum pg_control_recovery(PG_FUNCTION_ARGS) { Datum values[5]; bool nulls[5]; 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(5); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "min_recovery_end_lsn", LSNOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "min_recovery_end_timeline", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "backup_start_lsn", LSNOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "backup_end_lsn", LSNOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "end_of_backup_record_required", BOOLOID, -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] = LSNGetDatum(ControlFile->minRecoveryPoint); nulls[0] = false; values[1] = Int32GetDatum(ControlFile->minRecoveryPointTLI); nulls[1] = false; values[2] = LSNGetDatum(ControlFile->backupStartPoint); nulls[2] = false; values[3] = LSNGetDatum(ControlFile->backupEndPoint); nulls[3] = false; values[4] = BoolGetDatum(ControlFile->backupEndRequired); nulls[4] = false; htup = heap_form_tuple(tupdesc, values, nulls); PG_RETURN_DATUM(HeapTupleGetDatum(htup)); }
void initGinState(GinState *state, Relation index) { int i; state->origTupdesc = index->rd_att; state->oneCol = (index->rd_att->natts == 1) ? true : false; for (i = 0; i < index->rd_att->natts; i++) { state->tupdesc[i] = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 1, NULL, INT2OID, -1, 0); TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 2, NULL, index->rd_att->attrs[i]->atttypid, index->rd_att->attrs[i]->atttypmod, index->rd_att->attrs[i]->attndims ); fmgr_info_copy(&(state->compareFn[i]), index_getprocinfo(index, i + 1, GIN_COMPARE_PROC), CurrentMemoryContext); fmgr_info_copy(&(state->extractValueFn[i]), index_getprocinfo(index, i + 1, GIN_EXTRACTVALUE_PROC), CurrentMemoryContext); fmgr_info_copy(&(state->extractQueryFn[i]), index_getprocinfo(index, i + 1, GIN_EXTRACTQUERY_PROC), CurrentMemoryContext); fmgr_info_copy(&(state->consistentFn[i]), index_getprocinfo(index, i + 1, GIN_CONSISTENT_PROC), CurrentMemoryContext); /* * Check opclass capability to do partial match. */ if (index_getprocid(index, i + 1, GIN_COMPARE_PARTIAL_PROC) != InvalidOid) { fmgr_info_copy(&(state->comparePartialFn[i]), index_getprocinfo(index, i + 1, GIN_COMPARE_PARTIAL_PROC), CurrentMemoryContext); state->canPartialMatch[i] = true; } else { state->canPartialMatch[i] = false; } } }
/* * pgstrom_debug_info * * shows user's debug information */ Datum pgstrom_debug_info(PG_FUNCTION_ARGS) { FuncCallContext *fncxt; MemoryContext oldcxt; ListCell *cell; DefElem *defel; Datum values[2]; bool isnull[2]; HeapTuple tuple; if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; List *debug_info_list = NIL; fncxt = SRF_FIRSTCALL_INIT(); oldcxt = MemoryContextSwitchTo(fncxt->multi_call_memory_ctx); tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "key", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "value", TEXTOID, -1, 0); debug_info_list = pgstrom_scan_debug_info(debug_info_list); fncxt->user_fctx = (void *) debug_info_list; fncxt->tuple_desc = BlessTupleDesc(tupdesc); MemoryContextSwitchTo(oldcxt); } fncxt = SRF_PERCALL_SETUP(); cell = list_head((List *)fncxt->user_fctx); if (!cell) SRF_RETURN_DONE(fncxt); defel = lfirst(cell); Assert(IsA(defel, DefElem)); memset(isnull, false, sizeof(isnull)); values[0] = CStringGetTextDatum(defel->defname); values[1] = CStringGetTextDatum(strVal(defel->arg)); tuple = heap_form_tuple(fncxt->tuple_desc, values, isnull); fncxt->user_fctx = list_delete_ptr((List *)fncxt->user_fctx, lfirst(cell)); SRF_RETURN_NEXT(fncxt, HeapTupleGetDatum(tuple)); }
/* * There should be only one. */ void EmptyPyPgTupleDesc_Initialize(void) { PG_TRY(); { TupleDesc td; td = CreateTemplateTupleDesc(0, false); EmptyPyPgTupleDesc = PyPgTupleDesc_FromCopy(td); FreeTupleDesc(td); } PG_CATCH(); { PyErr_SetPgError(true); } PG_END_TRY(); }
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)); }
/* * createInverseTupleDesc * Create a tuple descriptor for the record returned by gp_partition_inverse. * * The record has the following format: * Oid: child partition oid * typeOid: the date type for the low end of a range partition; * the data type for the value in a list partition * bool: whether to include the low end of a range partition; * always true for a list partition * typeOid: used by range partitions only; * represents the data type for the high end of a range partition * bool: used by range partitions only; * represents whether to include the high end of a range partition. */ static TupleDesc createInverseTupleDesc(Oid typeOid, int32 typeMod) { TupleDesc tupleDesc = CreateTemplateTupleDesc(PARTITION_INVERSE_RECORD_NUM_ATTRS, false); TupleDescInitEntry(tupleDesc, (AttrNumber) PARTITION_INVERSE_RECORD_PARCHILDRELID_ATTNO, "partchildrelid", OIDOID, -1, 0); TupleDescInitEntry(tupleDesc, (AttrNumber) PARTITION_INVERSE_RECORD_MINKEY_ATTNO, "minkey", typeOid, typeMod, 0); TupleDescInitEntry(tupleDesc, (AttrNumber) PARTITION_INVERSE_RECORD_MININCLUDED_ATTNO, "minincluded", BOOLOID, -1, 0); TupleDescInitEntry(tupleDesc, (AttrNumber) PARTITION_INVERSE_RECORD_MAXKEY_ATTNO, "maxkey", typeOid, typeMod, 0); TupleDescInitEntry(tupleDesc, (AttrNumber) PARTITION_INVERSE_RECORD_MAXINCLUDED_ATTNO, "maxincluded", BOOLOID, -1, 0); return tupleDesc; }
static void ts_setup_firstcall(FunctionCallInfo fcinfo, FuncCallContext *funcctx, TSVectorStat *stat) { TupleDesc tupdesc; MemoryContext oldcontext; StatEntry *node; funcctx->user_fctx = (void *) stat; oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); stat->stack = palloc0(sizeof(StatEntry *) * (stat->maxdepth + 1)); stat->stackpos = 0; node = stat->root; /* find leftmost value */ if (node == NULL) stat->stack[stat->stackpos] = NULL; else for (;;) { stat->stack[stat->stackpos] = node; if (node->left) { stat->stackpos++; node = node->left; } else break; } Assert(stat->stackpos <= stat->maxdepth); tupdesc = CreateTemplateTupleDesc(3, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "ndoc", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "nentry", INT4OID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); MemoryContextSwitchTo(oldcontext); }
void test__ReleaseTupleDesc__ref_count(void **state) { TupleDesc td = CreateTemplateTupleDesc(2, true); td->tdrefcount = 3; expect_any(ResourceOwnerForgetTupleDesc, owner); expect_value(ResourceOwnerForgetTupleDesc, tupdesc, td); will_be_called(ResourceOwnerForgetTupleDesc); /* should decrement refcount but not free */ ReleaseTupleDesc(td); assert_int_equal(2, td->tdrefcount); pfree(td); }
/* * Returns the fixed schema for error log tuple. */ static TupleDesc GetErrorTupleDesc(void) { static TupleDesc tupdesc = NULL, tmp; MemoryContext oldcontext; int natts = NUM_ERRORTABLE_ATTR; FormData_pg_attribute attrs[NUM_ERRORTABLE_ATTR] = { {0,{"cmdtime"},1184,-1,8,1,0,-1,-1,true,'p','d',false,false,false,true,0}, {0,{"relname"},25,-1,-1,2,0,-1,-1,false,'x','i',false,false,false,true,0}, {0,{"filename"},25,-1,-1,3,0,-1,-1,false,'x','i',false,false,false,true,0}, {0,{"linenum"},23,-1,4,4,0,-1,-1,true,'p','i',false,false,false,true,0}, {0,{"bytenum"},23,-1,4,5,0,-1,-1,true,'p','i',false,false,false,true,0}, {0,{"errmsg"},25,-1,-1,6,0,-1,-1,false,'x','i',false,false,false,true,0}, {0,{"rawdata"},25,-1,-1,7,0,-1,-1,false,'x','i',false,false,false,true,0}, {0,{"rawbytes"},17,-1,-1,8,0,-1,-1,false,'x','i',false,false,false,true,0} }; /* If we have created it, use it. */ if (tupdesc != NULL) return tupdesc; /* * Keep the tupdesc for long in the cache context. It should never * be scribbled. */ oldcontext = MemoryContextSwitchTo(CacheMemoryContext); tmp = CreateTemplateTupleDesc(natts, false); tmp->tdrefcount = 0; tmp->tdtypeid = RECORDOID; tmp->tdtypmod = -1; for (int i = 0; i < natts; i++) { memcpy(tmp->attrs[i], &attrs[i], ATTRIBUTE_FIXED_PART_SIZE); tmp->attrs[i]->attcacheoff = -1; } tmp->attrs[0]->attcacheoff = 0; tupdesc = tmp; MemoryContextSwitchTo(oldcontext); return tupdesc; }
Datum testfunc5(PG_FUNCTION_ARGS) { int64 i = PG_GETARG_INT64(0); FuncCallContext *funcctx; MemoryContext oldcontext; if (SRF_IS_FIRSTCALL()) { TupleDesc tupd; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); tupd = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupd, 1, "c1", INT8OID, -1, 0); TupleDescInitEntry(tupd, 2, "c2", INT8OID, -1, 0); funcctx->max_calls = 3; funcctx->user_fctx = tupd; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); if (funcctx->call_cntr < funcctx->max_calls) { TupleDesc tupd; HeapTupleData tupleData; HeapTuple tuple = &tupleData; char *values[2]; Datum result; tupd = (TupleDesc)funcctx->user_fctx; values[0] = palloc(32); sprintf(values[0], INT64_FORMAT, i+1+funcctx->call_cntr); values[1] = palloc(32); sprintf(values[1], INT64_FORMAT, i+2+funcctx->call_cntr); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupd), values); result = TupleGetDatum(TupleDescGetSlot(tuple), tuple); SRF_RETURN_NEXT(funcctx, result); } else { SRF_RETURN_DONE(funcctx); } }
/* * CreateTupleDescCopyExtend * This function creates a new TupleDesc by copying from an existing * TupleDesc, but adding space for more columns. The new tupdesc is * not regarded as the same record type as the old one (and therefore * does not inherit its typeid/typmod, which instead are left as an * anonymous record type). * * The additional column slots are not initialized in any way; * callers must do their own TupleDescInitEntry on each. * * !!! Constraints and defaults are not copied !!! */ TupleDesc CreateTupleDescCopyExtend(TupleDesc tupdesc, int moreatts) { TupleDesc desc; int i; int src_natts = tupdesc->natts; Assert(moreatts >= 0); desc = CreateTemplateTupleDesc(src_natts + moreatts, tupdesc->tdhasoid); for (i = 0; i < src_natts; i++) { memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_FIXED_PART_SIZE); desc->attrs[i]->attnotnull = false; desc->attrs[i]->atthasdef = false; } return desc; }
/* * CreateTupleDescCopy * This function creates a new TupleDesc by copying from an existing * TupleDesc. * * !!! Constraints and defaults are not copied !!! */ TupleDesc CreateTupleDescCopy(TupleDesc tupdesc) { TupleDesc desc; int i; desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid); for (i = 0; i < desc->natts; i++) { memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_FIXED_PART_SIZE); desc->attrs[i]->attnotnull = false; desc->attrs[i]->atthasdef = false; } desc->tdtypeid = tupdesc->tdtypeid; desc->tdtypmod = tupdesc->tdtypmod; return desc; }
/* * _bitmap_copyOneInTupleDesc() -- copy one attribute inside oldTupDesc * into newTupDesc, and return newTupDesc. * * If newTupDesc is not NULL, this function creates a new TupleDesc instance. * Otherwise, this function replaces its attribute to the appropriate one. */ TupleDesc _bitmap_copyOneInTupleDesc(TupleDesc newTupDesc, TupleDesc oldTupDesc, uint32 attno) { Assert (attno < oldTupDesc->natts); if (newTupDesc == NULL) { newTupDesc = CreateTemplateTupleDesc(1, false); newTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); } memcpy(newTupDesc->attrs[0], oldTupDesc->attrs[attno], ATTRIBUTE_TUPLE_SIZE); (newTupDesc->attrs[0])->attnum = 1; return newTupDesc; }
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)); }
void test__ReleaseTupleDesc__no_ref_count(void **state) { TupleDesc td = CreateTemplateTupleDesc(2, true); td->tdrefcount = -1; /* should not do anything */ ReleaseTupleDesc(td); assert_int_equal(-1, td->tdrefcount); td->tdrefcount = 0; /* should not do anything */ ReleaseTupleDesc(td); assert_int_equal(0, td->tdrefcount); pfree(td); }
/* * pgmpc_init_setof * Intilialize properly a function returning multiple tuples with a * tuplestore and a TupDesc. */ static void pgmpc_init_setof(FunctionCallInfo fcinfo, int argnum, Oid *argtypes, char **argnames, TupleDesc *tupdesc, Tuplestorestate **tupstore) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; MemoryContext per_query_ctx; MemoryContext oldcontext; int i; /* 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"))); per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); /* Build tuple descriptor */ *tupdesc = CreateTemplateTupleDesc(argnum, false); for (i = 0; i < argnum; i++) TupleDescInitEntry(*tupdesc, (AttrNumber) i + 1, argnames[i], argtypes[i], -1, 0); *tupstore = tuplestore_begin_heap(true, false, work_mem); rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = *tupstore; rsinfo->setDesc = *tupdesc; MemoryContextSwitchTo(oldcontext); }
/* * Helper function to construct whichever TupleDesc we need for a particular * call. */ static TupleDesc pg_visibility_tupdesc(bool include_blkno, bool include_pd) { TupleDesc tupdesc; AttrNumber maxattr = 2; AttrNumber a = 0; if (include_blkno) ++maxattr; if (include_pd) ++maxattr; tupdesc = CreateTemplateTupleDesc(maxattr, false); if (include_blkno) TupleDescInitEntry(tupdesc, ++a, "blkno", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, ++a, "all_visible", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, ++a, "all_frozen", BOOLOID, -1, 0); if (include_pd) TupleDescInitEntry(tupdesc, ++a, "pd_all_visible", BOOLOID, -1, 0); Assert(a == maxattr); return BlessTupleDesc(tupdesc); }
Datum testfunc3(PG_FUNCTION_ARGS) { TupleDesc tupd; HeapTupleData tupleData; HeapTuple tuple = &tupleData; char *values[2]; Datum result; int64 i = PG_GETARG_INT64(0); tupd = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupd, 1, "c1", INT8OID, -1, 0); TupleDescInitEntry(tupd, 2, "c2", INT8OID, -1, 0); values[0] = palloc(32); sprintf(values[0], INT64_FORMAT, i+1); values[1] = palloc(32); sprintf(values[1], INT64_FORMAT, i+2); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupd), values); result = TupleGetDatum(TupleDescGetSlot(tuple), tuple); PG_RETURN_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 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) { 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); }
/* * 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)); }
Datum pg_control_init(PG_FUNCTION_ARGS) { Datum values[13]; bool nulls[13]; TupleDesc tupdesc; HeapTuple htup; ControlFileData *ControlFile; /* * Construct a tuple descriptor for the result row. This must match this * function's pg_proc entry! */ tupdesc = CreateTemplateTupleDesc(13, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "max_data_alignment", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database_block_size", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "blocks_per_segment", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_block_size", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "bytes_per_wal_segment", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "max_identifier_length", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 7, "max_index_columns", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 8, "max_toast_chunk_size", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 9, "large_object_chunk_size", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 10, "bigint_timestamps", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 11, "float4_pass_by_value", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 12, "float8_pass_by_value", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 13, "data_page_checksum_version", INT4OID, -1, 0); tupdesc = BlessTupleDesc(tupdesc); /* read the control file */ ControlFile = get_controlfile(DataDir, NULL); values[0] = Int32GetDatum(ControlFile->maxAlign); nulls[0] = false; values[1] = Int32GetDatum(ControlFile->blcksz); nulls[1] = false; values[2] = Int32GetDatum(ControlFile->relseg_size); nulls[2] = false; values[3] = Int32GetDatum(ControlFile->xlog_blcksz); nulls[3] = false; values[4] = Int32GetDatum(ControlFile->xlog_seg_size); nulls[4] = false; values[5] = Int32GetDatum(ControlFile->nameDataLen); nulls[5] = false; values[6] = Int32GetDatum(ControlFile->indexMaxKeys); nulls[6] = false; values[7] = Int32GetDatum(ControlFile->toast_max_chunk_size); nulls[7] = false; values[8] = Int32GetDatum(ControlFile->loblksize); nulls[8] = false; values[9] = BoolGetDatum(ControlFile->enableIntTimes); nulls[9] = false; values[10] = BoolGetDatum(ControlFile->float4ByVal); nulls[10] = false; values[11] = BoolGetDatum(ControlFile->float8ByVal); nulls[11] = false; values[12] = Int32GetDatum(ControlFile->data_checksum_version); nulls[12] = false; htup = heap_form_tuple(tupdesc, values, nulls); PG_RETURN_DATUM(HeapTupleGetDatum(htup)); }
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)); }
/* * 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); } }
void AlterTableCreateAoSegTable(Oid relOid, bool is_part_child, bool is_part_parent) { TupleDesc tupdesc; Relation rel; const char *prefix; /* * Grab an exclusive lock on the target table, which we will NOT release * until end of transaction. (This is probably redundant in all present * uses...) */ if (is_part_child) rel = heap_open(relOid, NoLock); else rel = heap_open(relOid, AccessExclusiveLock); if(RelationIsAoRows(rel)) { prefix = "pg_aoseg"; /* this is pretty painful... need a tuple descriptor */ tupdesc = CreateTemplateTupleDesc(8, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "segno", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "eof", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "tupcount", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "varblockcount", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "eofuncompressed", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "modcount", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 7, "formatversion", INT2OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 8, "state", INT2OID, -1, 0); } else if (RelationIsAoCols(rel)) { prefix = "pg_aocsseg"; /* * XXX * At this moment, we hardwire the rel aocs info. * Essentially, we assume total vertical partition, and * we do not do datatype specific compression. * * In order to make things right, we need to first fix * the DefineRelation, so that we store the per column * info, then, we need to open the catalog, pull out * info here. */ /* * XXX We do not handle add/drop column etc nicely yet. */ /* * Assuming full vertical partition, we want to include * the following in the seg table. * * segno int, -- whatever purpose ao use it * tupcount bigint -- total tup * varblockcount bigint, -- total varblock * vpinfo varbinary(max) -- vertical partition info encoded in * binary. NEEDS TO BE REFACTORED * INTO MULTIPLE COLUMNS!! * state (smallint) -- state of the segment file */ tupdesc = CreateTemplateTupleDesc(7, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "segno", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "tupcount", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "varblockcount", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "vpinfo", BYTEAOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "modcount", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "formatversion", INT2OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 7, "state", INT2OID, -1, 0); } else { heap_close(rel, NoLock); return; } (void) CreateAOAuxiliaryTable(rel, prefix, RELKIND_AOSEGMENTS, tupdesc, NULL, NIL, NULL, NULL, is_part_parent); heap_close(rel, NoLock); }
/* 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); }
/* * 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(NUM_LOCK_STATUS_COLUMNS, 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); TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath", 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) { bool granted; LOCKMODE mode = 0; const char *locktypename; char tnbuf[32]; Datum values[NUM_LOCK_STATUS_COLUMNS]; bool nulls[NUM_LOCK_STATUS_COLUMNS]; HeapTuple tuple; Datum result; LockInstanceData *instance; instance = &(lockData->locks[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 (instance->holdMask) { for (mode = 0; mode < MAX_LOCKMODES; mode++) { if (instance->holdMask & LOCKBIT_ON(mode)) { granted = true; instance->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 (instance->waitLockMode != NoLock) { /* Yes, so report it with proper mode */ mode = instance->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 (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE) locktypename = LockTagTypeNames[instance->locktag.locktag_type]; else { snprintf(tnbuf, sizeof(tnbuf), "unknown %d", (int) instance->locktag.locktag_type); locktypename = tnbuf; } values[0] = CStringGetTextDatum(locktypename); switch ((LockTagType) instance->locktag.locktag_type) { case LOCKTAG_RELATION: case LOCKTAG_RELATION_EXTEND: values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1); values[2] = ObjectIdGetDatum(instance->locktag.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(instance->locktag.locktag_field1); values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2); values[3] = UInt32GetDatum(instance->locktag.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(instance->locktag.locktag_field1); values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2); values[3] = UInt32GetDatum(instance->locktag.locktag_field3); values[4] = UInt16GetDatum(instance->locktag.locktag_field4); nulls[5] = true; nulls[6] = true; nulls[7] = true; nulls[8] = true; nulls[9] = true; break; case LOCKTAG_TRANSACTION: values[6] = TransactionIdGetDatum(instance->locktag.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(instance->locktag.locktag_field1, instance->locktag.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(instance->locktag.locktag_field1); values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2); values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3); values[9] = Int16GetDatum(instance->locktag.locktag_field4); nulls[2] = true; nulls[3] = true; nulls[4] = true; nulls[5] = true; nulls[6] = true; break; } values[10] = VXIDGetDatum(instance->backend, instance->lxid); if (instance->pid != 0) values[11] = Int32GetDatum(instance->pid); else nulls[11] = true; values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode)); values[13] = BoolGetDatum(granted); values[14] = BoolGetDatum(instance->fastpath); 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[NUM_LOCK_STATUS_COLUMNS]; bool nulls[NUM_LOCK_STATUS_COLUMNS]; 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) and have no fast path */ values[12] = CStringGetTextDatum("SIReadLock"); values[13] = BoolGetDatum(true); values[14] = BoolGetDatum(false); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } SRF_RETURN_DONE(funcctx); }