Switch some system functions to use get_call_result_type()
authorMichael Paquier <michael@paquier.xyz>
Wed, 21 Dec 2022 01:11:22 +0000 (10:11 +0900)
committerMichael Paquier <michael@paquier.xyz>
Wed, 21 Dec 2022 01:11:22 +0000 (10:11 +0900)
This shaves some code by replacing the combinations of
CreateTemplateTupleDesc()/TupleDescInitEntry() hardcoding a mapping of
the attributes listed in pg_proc.dat by get_call_result_type() to build
the TupleDesc needed for the rows generated.

get_call_result_type() is more expensive than the former style, but this
removes some duplication with the lists of OUT parameters (pg_proc.dat
and the attributes hardcoded in these code paths).  This is applied to
functions that are not considered as critical (aka that could be called
repeatedly for monitoring purposes).

Author: Bharath Rupireddy
Reviewed-by: Robert Haas, Álvaro Herrera, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/CALj2ACV23HW5HP5hFjd89FNS-z5X8r2jNXdMXcpN2BgTtKd87w@mail.gmail.com

12 files changed:
contrib/old_snapshot/time_mapping.c
contrib/pg_visibility/pg_visibility.c
src/backend/access/transam/commit_ts.c
src/backend/access/transam/multixact.c
src/backend/catalog/objectaddress.c
src/backend/commands/sequence.c
src/backend/tsearch/wparser.c
src/backend/utils/adt/datetime.c
src/backend/utils/adt/misc.c
src/backend/utils/adt/partitionfuncs.c
src/backend/utils/adt/tsvector_op.c
src/backend/utils/misc/pg_controldata.c

index 2d8cb742c34c524eefefcba98953e6cc1dfa2383..aa4901fa1c438bbb9295442b6c0456ee885f72a7 100644 (file)
@@ -38,7 +38,6 @@ PG_MODULE_MAGIC;
 PG_FUNCTION_INFO_V1(pg_old_snapshot_time_mapping);
 
 static OldSnapshotTimeMapping *GetOldSnapshotTimeMapping(void);
-static TupleDesc MakeOldSnapshotTimeMappingTupleDesc(void);
 static HeapTuple MakeOldSnapshotTimeMappingTuple(TupleDesc tupdesc,
                                                 OldSnapshotTimeMapping *mapping);
 
@@ -54,12 +53,15 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext oldcontext;
+       TupleDesc   tupdesc;
 
        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
        mapping = GetOldSnapshotTimeMapping();
        funcctx->user_fctx = mapping;
-       funcctx->tuple_desc = MakeOldSnapshotTimeMappingTupleDesc();
+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+           elog(ERROR, "return type must be a row type");
+       funcctx->tuple_desc = tupdesc;
        MemoryContextSwitchTo(oldcontext);
    }
 
@@ -101,26 +103,6 @@ GetOldSnapshotTimeMapping(void)
    return mapping;
 }
 
-/*
- * Build a tuple descriptor for the pg_old_snapshot_time_mapping() SRF.
- */
-static TupleDesc
-MakeOldSnapshotTimeMappingTupleDesc(void)
-{
-   TupleDesc   tupdesc;
-
-   tupdesc = CreateTemplateTupleDesc(NUM_TIME_MAPPING_COLUMNS);
-
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "array_offset",
-                      INT4OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "end_timestamp",
-                      TIMESTAMPTZOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 3, "newest_xmin",
-                      XIDOID, -1, 0);
-
-   return BlessTupleDesc(tupdesc);
-}
-
 /*
  * Convert one entry from the old snapshot time mapping to a HeapTuple.
  */
index a95f73ec7960073e1c7d6d25ef118694b535c0ed..81f262a5f46f4525ac593b4360c095aa614b066c 100644 (file)
@@ -291,10 +291,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
        ReleaseBuffer(vmbuffer);
    relation_close(rel, AccessShareLock);
 
-   tupdesc = CreateTemplateTupleDesc(2);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "all_visible", INT8OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "all_frozen", INT8OID, -1, 0);
-   tupdesc = BlessTupleDesc(tupdesc);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    values[0] = Int64GetDatum(all_visible);
    values[1] = Int64GetDatum(all_frozen);
index 9aa4675cb7927e48601f80fff3797d90c73afefa..5c30de57ac84dc0f3ed8e5aadd6adde226bc1ee7 100644 (file)
@@ -422,18 +422,8 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
    /* and construct a tuple with our data */
    xid = GetLatestCommitTsData(&ts, &nodeid);
 
-   /*
-    * Construct a tuple descriptor for the result row.  This must match this
-    * function's pg_proc entry!
-    */
-   tupdesc = CreateTemplateTupleDesc(3);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "xid",
-                      XIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "timestamp",
-                      TIMESTAMPTZOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 3, "roident",
-                      OIDOID, -1, 0);
-   tupdesc = BlessTupleDesc(tupdesc);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    if (!TransactionIdIsNormal(xid))
    {
@@ -476,16 +466,8 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
    found = TransactionIdGetCommitTsData(xid, &ts, &nodeid);
 
-   /*
-    * Construct a tuple descriptor for the result row.  This must match this
-    * function's pg_proc entry!
-    */
-   tupdesc = CreateTemplateTupleDesc(2);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "timestamp",
-                      TIMESTAMPTZOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "roident",
-                      OIDOID, -1, 0);
-   tupdesc = BlessTupleDesc(tupdesc);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    if (!found)
    {
index e1191a7564cbde3e804b72f2954002db1bded14d..19b95b82412832d268ffd37182a7ea69b1c0c6a6 100644 (file)
@@ -3373,12 +3373,9 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
                                                false);
        multi->iter = 0;
 
-       tupdesc = CreateTemplateTupleDesc(2);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "xid",
-                          XIDOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "mode",
-                          TEXTOID, -1, 0);
-
+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+           elog(ERROR, "return type must be a row type");
+       funccxt->tuple_desc = tupdesc;
        funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
        funccxt->user_fctx = multi;
 
index fe97fbf79dcdda2b49839a829357bb035172c54c..109bdfb33f6214e2a503c7606ffadd3c97e00e78 100644 (file)
@@ -2397,14 +2397,8 @@ pg_get_object_address(PG_FUNCTION_ARGS)
    if (relation)
        relation_close(relation, AccessShareLock);
 
-   tupdesc = CreateTemplateTupleDesc(3);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "classid",
-                      OIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "objid",
-                      OIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 3, "objsubid",
-                      INT4OID, -1, 0);
-   tupdesc = BlessTupleDesc(tupdesc);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    values[0] = ObjectIdGetDatum(addr.classId);
    values[1] = ObjectIdGetDatum(addr.objectId);
@@ -4244,21 +4238,8 @@ pg_identify_object(PG_FUNCTION_ARGS)
    address.objectId = objid;
    address.objectSubId = objsubid;
 
-   /*
-    * Construct a tuple descriptor for the result row.  This must match this
-    * function's pg_proc entry!
-    */
-   tupdesc = CreateTemplateTupleDesc(4);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
-                      TEXTOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema",
-                      TEXTOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name",
-                      TEXTOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity",
-                      TEXTOID, -1, 0);
-
-   tupdesc = BlessTupleDesc(tupdesc);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    if (is_objectclass_supported(address.classId))
    {
@@ -4374,19 +4355,8 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
    address.objectId = objid;
    address.objectSubId = objsubid;
 
-   /*
-    * Construct a tuple descriptor for the result row.  This must match this
-    * function's pg_proc entry!
-    */
-   tupdesc = CreateTemplateTupleDesc(3);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
-                      TEXTOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "object_names",
-                      TEXTARRAYOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 3, "object_args",
-                      TEXTARRAYOID, -1, 0);
-
-   tupdesc = BlessTupleDesc(tupdesc);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    /* object type, which can never be NULL */
    values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
index 99c9f91cba5da0e6894fa925abb8644c96a85f31..c31c9b891a5264d5238f28c054af1a8f4c00e377 100644 (file)
@@ -1762,23 +1762,8 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
                 errmsg("permission denied for sequence %s",
                        get_rel_name(relid))));
 
-   tupdesc = CreateTemplateTupleDesc(7);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "start_value",
-                      INT8OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "minimum_value",
-                      INT8OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 3, "maximum_value",
-                      INT8OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 4, "increment",
-                      INT8OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 5, "cycle_option",
-                      BOOLOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 6, "cache_size",
-                      INT8OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 7, "data_type",
-                      OIDOID, -1, 0);
-
-   BlessTupleDesc(tupdesc);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    memset(isnull, 0, sizeof(isnull));
 
index 14bb60534f2967d1d03d6e991282f13ffdd8bec6..3ef043ac0e85da01c73b174b7eb32b205c73c43b 100644 (file)
@@ -46,7 +46,8 @@ typedef struct HeadlineJsonState
 static text *headline_json_value(void *_state, char *elem_value, int elem_len);
 
 static void
-tt_setup_firstcall(FuncCallContext *funcctx, Oid prsid)
+tt_setup_firstcall(FuncCallContext *funcctx, FunctionCallInfo fcinfo,
+                  Oid prsid)
 {
    TupleDesc   tupdesc;
    MemoryContext oldcontext;
@@ -66,15 +67,11 @@ tt_setup_firstcall(FuncCallContext *funcctx, Oid prsid)
                                                             (Datum) 0));
    funcctx->user_fctx = (void *) st;
 
-   tupdesc = CreateTemplateTupleDesc(3);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid",
-                      INT4OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "alias",
-                      TEXTOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description",
-                      TEXTOID, -1, 0);
-
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
+   funcctx->tuple_desc = tupdesc;
    funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
+
    MemoryContextSwitchTo(oldcontext);
 }
 
@@ -116,7 +113,7 @@ ts_token_type_byid(PG_FUNCTION_ARGS)
    if (SRF_IS_FIRSTCALL())
    {
        funcctx = SRF_FIRSTCALL_INIT();
-       tt_setup_firstcall(funcctx, PG_GETARG_OID(0));
+       tt_setup_firstcall(funcctx, fcinfo, PG_GETARG_OID(0));
    }
 
    funcctx = SRF_PERCALL_SETUP();
@@ -139,7 +136,7 @@ ts_token_type_byname(PG_FUNCTION_ARGS)
 
        funcctx = SRF_FIRSTCALL_INIT();
        prsId = get_ts_parser_oid(textToQualifiedNameList(prsname), false);
-       tt_setup_firstcall(funcctx, prsId);
+       tt_setup_firstcall(funcctx, fcinfo, prsId);
    }
 
    funcctx = SRF_PERCALL_SETUP();
@@ -164,7 +161,8 @@ typedef struct
 
 
 static void
-prs_setup_firstcall(FuncCallContext *funcctx, Oid prsid, text *txt)
+prs_setup_firstcall(FuncCallContext *funcctx, FunctionCallInfo fcinfo,
+                   Oid prsid, text *txt)
 {
    TupleDesc   tupdesc;
    MemoryContext oldcontext;
@@ -209,12 +207,9 @@ prs_setup_firstcall(FuncCallContext *funcctx, Oid prsid, text *txt)
    st->cur = 0;
 
    funcctx->user_fctx = (void *) st;
-   tupdesc = CreateTemplateTupleDesc(2);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "tokid",
-                      INT4OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "token",
-                      TEXTOID, -1, 0);
-
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
+   funcctx->tuple_desc = tupdesc;
    funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
    MemoryContextSwitchTo(oldcontext);
 }
@@ -256,7 +251,7 @@ ts_parse_byid(PG_FUNCTION_ARGS)
        text       *txt = PG_GETARG_TEXT_PP(1);
 
        funcctx = SRF_FIRSTCALL_INIT();
-       prs_setup_firstcall(funcctx, PG_GETARG_OID(0), txt);
+       prs_setup_firstcall(funcctx, fcinfo, PG_GETARG_OID(0), txt);
        PG_FREE_IF_COPY(txt, 1);
    }
 
@@ -281,7 +276,7 @@ ts_parse_byname(PG_FUNCTION_ARGS)
 
        funcctx = SRF_FIRSTCALL_INIT();
        prsId = get_ts_parser_oid(textToQualifiedNameList(prsname), false);
-       prs_setup_firstcall(funcctx, prsId, txt);
+       prs_setup_firstcall(funcctx, fcinfo, prsId, txt);
    }
 
    funcctx = SRF_PERCALL_SETUP();
index b5b117a8ca796a5b8cac9da1b3e28e43e921ab17..8afda0e5d22498cdde6af7eb378824d99581c010 100644 (file)
@@ -4983,19 +4983,10 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
        *pindex = 0;
        funcctx->user_fctx = (void *) pindex;
 
-       /*
-        * build tupdesc for result tuples. This must match this function's
-        * pg_proc entry!
-        */
-       tupdesc = CreateTemplateTupleDesc(3);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "abbrev",
-                          TEXTOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "utc_offset",
-                          INTERVALOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_dst",
-                          BOOLOID, -1, 0);
-
-       funcctx->tuple_desc = BlessTupleDesc(tupdesc);
+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+           elog(ERROR, "return type must be a row type");
+       funcctx->tuple_desc = tupdesc;
+
        MemoryContextSwitchTo(oldcontext);
    }
 
index d678d286009ef2d2611746064103f09b3ceda102..7808fbd4486235ed538c732573b9040fbb9d07f8 100644 (file)
@@ -427,18 +427,9 @@ pg_get_keywords(PG_FUNCTION_ARGS)
        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
-       tupdesc = CreateTemplateTupleDesc(5);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
-                          TEXTOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode",
-                          CHAROID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "barelabel",
-                          BOOLOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 4, "catdesc",
-                          TEXTOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 5, "baredesc",
-                          TEXTOID, -1, 0);
-
+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+           elog(ERROR, "return type must be a row type");
+       funcctx->tuple_desc = tupdesc;
        funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
 
        MemoryContextSwitchTo(oldcontext);
@@ -515,20 +506,8 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
-       tupdesc = CreateTemplateTupleDesc(6);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "fktable",
-                          REGCLASSOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "fkcols",
-                          TEXTARRAYOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "pktable",
-                          REGCLASSOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pkcols",
-                          TEXTARRAYOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_array",
-                          BOOLOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 6, "is_opt",
-                          BOOLOID, -1, 0);
-
+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+           elog(ERROR, "return type must be a row type");
        funcctx->tuple_desc = BlessTupleDesc(tupdesc);
 
        /*
index 96b5ae52d27e46cc690ebdc591a9d4746aa6a0a7..84518630a562a331145780034a6bd67c8fff484f 100644 (file)
@@ -88,17 +88,9 @@ pg_partition_tree(PG_FUNCTION_ARGS)
         */
        partitions = find_all_inheritors(rootrelid, AccessShareLock, NULL);
 
-       tupdesc = CreateTemplateTupleDesc(PG_PARTITION_TREE_COLS);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relid",
-                          REGCLASSOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "parentid",
-                          REGCLASSOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "isleaf",
-                          BOOLOID, -1, 0);
-       TupleDescInitEntry(tupdesc, (AttrNumber) 4, "level",
-                          INT4OID, -1, 0);
-
-       funcctx->tuple_desc = BlessTupleDesc(tupdesc);
+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+           elog(ERROR, "return type must be a row type");
+       funcctx->tuple_desc = tupdesc;
 
        /* The only state we need is the partition list */
        funcctx->user_fctx = (void *) partitions;
index f7c1e3d6d65df96515bf5766e7ab894381e5a206..caeb85b4ca18ad277341594880ad739e6ff8628b 100644 (file)
@@ -647,7 +647,9 @@ tsvector_unnest(PG_FUNCTION_ARGS)
                           INT2ARRAYOID, -1, 0);
        TupleDescInitEntry(tupdesc, (AttrNumber) 3, "weights",
                           TEXTARRAYOID, -1, 0);
-       funcctx->tuple_desc = BlessTupleDesc(tupdesc);
+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+           elog(ERROR, "return type must be a row type");
+       funcctx->tuple_desc = tupdesc;
 
        funcctx->user_fctx = PG_GETARG_TSVECTOR_COPY(0);
 
@@ -2302,14 +2304,9 @@ ts_setup_firstcall(FunctionCallInfo fcinfo, FuncCallContext *funcctx,
        }
    Assert(stat->stackpos <= stat->maxdepth);
 
-   tupdesc = CreateTemplateTupleDesc(3);
-   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);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
+   funcctx->tuple_desc = tupdesc;
    funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
 
    MemoryContextSwitchTo(oldcontext);
index 781f8b8758097da122d5c4d3689c113fb8406d8e..0703892ed4a28abacb3e0afe2126e1890654d5b8 100644 (file)
@@ -38,20 +38,8 @@ pg_control_system(PG_FUNCTION_ARGS)
    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);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    /* read the control file */
    ControlFile = get_controlfile(DataDir, &crc_ok);
@@ -88,48 +76,8 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
    char        xlogfilename[MAXFNAMELEN];
    bool        crc_ok;
 
-   /*
-    * Construct a tuple descriptor for the result row.  This must match this
-    * function's pg_proc entry!
-    */
-   tupdesc = CreateTemplateTupleDesc(18);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "checkpoint_lsn",
-                      PG_LSNOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "redo_lsn",
-                      PG_LSNOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 3, "redo_wal_file",
-                      TEXTOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 4, "timeline_id",
-                      INT4OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 5, "prev_timeline_id",
-                      INT4OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 6, "full_page_writes",
-                      BOOLOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 7, "next_xid",
-                      TEXTOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 8, "next_oid",
-                      OIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 9, "next_multixact_id",
-                      XIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 10, "next_multi_offset",
-                      XIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 11, "oldest_xid",
-                      XIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 12, "oldest_xid_dbid",
-                      OIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 13, "oldest_active_xid",
-                      XIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 14, "oldest_multi_xid",
-                      XIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 15, "oldest_multi_dbid",
-                      OIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 16, "oldest_commit_ts_xid",
-                      XIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 17, "newest_commit_ts_xid",
-                      XIDOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 18, "checkpoint_time",
-                      TIMESTAMPTZOID, -1, 0);
-   tupdesc = BlessTupleDesc(tupdesc);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    /* Read the control file. */
    ControlFile = get_controlfile(DataDir, &crc_ok);
@@ -217,22 +165,8 @@ pg_control_recovery(PG_FUNCTION_ARGS)
    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",
-                      PG_LSNOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "min_recovery_end_timeline",
-                      INT4OID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 3, "backup_start_lsn",
-                      PG_LSNOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 4, "backup_end_lsn",
-                      PG_LSNOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 5, "end_of_backup_record_required",
-                      BOOLOID, -1, 0);
-   tupdesc = BlessTupleDesc(tupdesc);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    /* read the control file */
    ControlFile = get_controlfile(DataDir, &crc_ok);
@@ -270,34 +204,8 @@ pg_control_init(PG_FUNCTION_ARGS)
    ControlFileData *ControlFile;
    bool        crc_ok;
 
-   /*
-    * Construct a tuple descriptor for the result row.  This must match this
-    * function's pg_proc entry!
-    */
-   tupdesc = CreateTemplateTupleDesc(11);
-   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, "float8_pass_by_value",
-                      BOOLOID, -1, 0);
-   TupleDescInitEntry(tupdesc, (AttrNumber) 11, "data_page_checksum_version",
-                      INT4OID, -1, 0);
-   tupdesc = BlessTupleDesc(tupdesc);
+   if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
 
    /* read the control file */
    ControlFile = get_controlfile(DataDir, &crc_ok);