diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c index 1c2503f..029d3bc 100644 --- a/src/backend/utils/adt/tid.c +++ b/src/backend/utils/adt/tid.c @@ -21,12 +21,15 @@ #include #include "access/heapam.h" +#include "access/htup_details.h" #include "access/sysattr.h" #include "catalog/namespace.h" #include "catalog/pg_type.h" +#include "funcapi.h" #include "libpq/pqformat.h" #include "miscadmin.h" #include "parser/parsetree.h" +#include "storage/bufmgr.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/rel.h" @@ -398,3 +401,73 @@ currtid_byrelname(PG_FUNCTION_ARGS) PG_RETURN_ITEMPOINTER(result); } + +Datum +pg_tuple_header(PG_FUNCTION_ARGS) +{ + Oid reloid = PG_GETARG_OID(0); + ItemPointer tid = PG_GETARG_ITEMPOINTER(1); + Relation rel; + AclResult aclresult; + HeapTupleData tup; + Buffer buf; + TupleDesc tupdesc; + HeapTuple result = NULL; + Datum values[7]; + bool nulls[7]; + + /* + * Attempt to open the relation. + * + * We use try_relation_open() here and throw our own error message because + * relation_open() will elog() if the relation isn't found. + */ + rel = try_relation_open(reloid, AccessShareLock); + if (rel == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation with OID %u does not exist", reloid))); + + /* Check permissions and relkind. */ + aclresult = pg_class_aclcheck(reloid, GetUserId(), ACL_SELECT); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_CLASS, + RelationGetRelationName(rel)); + if (rel->rd_rel->relkind != RELKIND_RELATION && + rel->rd_rel->relkind != RELKIND_MATVIEW) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a table or materialized view", + RelationGetRelationName(rel)))); + + /* Fetch the tuple. */ + tup.t_self = *tid; + if (!heap_fetch(rel, GetActiveSnapshot(), &tup, &buf, false, NULL)) + { + relation_close(rel, AccessShareLock); + PG_RETURN_NULL(); + } + + /* 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"); + + /* Fill in the values. */ + values[0] = TransactionIdGetDatum(HeapTupleHeaderGetRawXmin(tup.t_data)); + values[1] = TransactionIdGetDatum(HeapTupleHeaderGetRawXmax(tup.t_data)); + values[2] = CommandIdGetDatum(HeapTupleHeaderGetRawCommandId(tup.t_data)); + values[3] = ItemPointerGetDatum(&tup.t_data->t_ctid); + values[4] = Int32GetDatum((int32) tup.t_data->t_infomask); + values[5] = Int32GetDatum((int32) tup.t_data->t_infomask2); + values[6] = Int16GetDatum((int16) tup.t_data->t_hoff); + + /* Build the tuple. */ + memset(nulls, 0, sizeof(nulls)); + result = heap_form_tuple(tupdesc, values, nulls); + + /* Release resources. */ + ReleaseBuffer(buf); + relation_close(rel, AccessShareLock); + + PG_RETURN_DATUM(HeapTupleGetDatum(result)); +} diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 0117500..d88898a 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -1371,6 +1371,8 @@ DATA(insert OID = 2795 ( tidlarger PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 DESCR("larger of two"); DATA(insert OID = 2796 ( tidsmaller PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 27 "27 27" _null_ _null_ _null_ _null_ tidsmaller _null_ _null_ _null_ )); DESCR("smaller of two"); +DATA(insert OID = 3195 ( pg_tuple_header PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2249 "2205 27" "{2205,27,28,28,29,27,23,23,21}" "{i,i,o,o,o,o,o,o,o}" "{tableoid,tid,xmin,xmax,cid,ctid,infomask,infomask2,hoff}" _null_ pg_tuple_header _null_ _null_ _null_ )); +DESCR("tuple header fields"); DATA(insert OID = 1296 ( timedate_pl PGNSP PGUID 14 1 0 0 0 f f f f t f i 2 0 1114 "1083 1082" _null_ _null_ _null_ _null_ "select ($2 + $1)" _null_ _null_ _null_ )); DATA(insert OID = 1297 ( datetimetz_pl PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1184 "1082 1266" _null_ _null_ _null_ _null_ datetimetz_timestamptz _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 1bfd145..4d573d4 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -695,6 +695,7 @@ extern Datum tidlarger(PG_FUNCTION_ARGS); extern Datum tidsmaller(PG_FUNCTION_ARGS); extern Datum currtid_byreloid(PG_FUNCTION_ARGS); extern Datum currtid_byrelname(PG_FUNCTION_ARGS); +extern Datum pg_tuple_header(PG_FUNCTION_ARGS); /* varchar.c */ extern Datum bpcharin(PG_FUNCTION_ARGS);