From 7fc8a88b725090b8365e9df036e34c0a8689cde0 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Thu, 18 Mar 2021 12:20:00 -0400 Subject: [PATCH v39] Invent HeapTupleGetRawDatum and friends. HeapTupleGetRawDatum, HeapTupleHeaderGetRawDatum, and PG_RETURN_HEAPTUPLEHEADER_RAW, and heap_copy_tuple_as_raw_datum are just like HeapTupleGetDatum, HeapTupleHeaderGetDatum, PG_RETURN_HEAPTUPLEHEADER, and heap_copy_tuple_as_datum, except that they don't check that the returned tuple is free of external datums. Instead, the caller must guarantee that this is the case. The overarching idea here is that it's usually more efficient for the caller to make sure to build the tuple originally without any external datums, rather than building a tuple that may contain external datums and then invoking a function which will possibly deform that tuple, detoast those fields, and build a replacement tuple. Fortunately, very few places are relying on this behavior of the above functions, which means that this patch can safely change practically all the calls to the existing functions to use the "raw" variants. In the places that continue to use the non-raw variants after this patch, there is an opportunity to improve performance by fixing them so that they can. That work is planned for a follow-up patch. That said, the main motivation for this patch is actually to cut down on the number of places that depend on HeapTupleHasExternal tests to avoid performance problems, and to make it clear where the remaining places are. New features - such as configurable TOAST compression - will not have the luxury of consuming an infomask bit to indicate whether or not they are in use somewhere inside a tuple. Dilip Kumar, based on an idea by me. Documentation changes also by me. Discussion: http://postgr.es/m/CAFiTN-u3jrRDiuyGxGvNSGDXLhG4=U2orHnjk4B6WBy9Eo9kMQ@mail.gmail.com Discussion: http://postgr.es/m/CAFiTN-s8SsWs2zCZL3TFxXwi4VE35J%3D4aKpduKVrTaL%2B3wnB0A%40mail.gmail.com --- contrib/dblink/dblink.c | 2 +- contrib/hstore/hstore_io.c | 4 +-- contrib/hstore/hstore_op.c | 2 +- contrib/old_snapshot/time_mapping.c | 2 +- contrib/pageinspect/brinfuncs.c | 2 +- contrib/pageinspect/btreefuncs.c | 6 ++--- contrib/pageinspect/ginfuncs.c | 6 ++--- contrib/pageinspect/gistfuncs.c | 2 +- contrib/pageinspect/hashfuncs.c | 8 +++--- contrib/pageinspect/heapfuncs.c | 6 ++--- contrib/pageinspect/rawpage.c | 2 +- contrib/pg_buffercache/pg_buffercache_pages.c | 2 +- .../pg_stat_statements/pg_stat_statements.c | 3 ++- contrib/pg_visibility/pg_visibility.c | 13 ++++++---- contrib/pgcrypto/pgp-pgsql.c | 2 +- contrib/pgstattuple/pgstatapprox.c | 2 +- contrib/pgstattuple/pgstatindex.c | 6 ++--- contrib/pgstattuple/pgstattuple.c | 2 +- contrib/sslinfo/sslinfo.c | 2 +- doc/src/sgml/xfunc.sgml | 8 ++++-- src/backend/access/common/heaptuple.c | 26 +++++++++++++++---- src/backend/access/transam/commit_ts.c | 4 +-- src/backend/access/transam/multixact.c | 2 +- src/backend/access/transam/twophase.c | 2 +- src/backend/access/transam/xlogfuncs.c | 2 +- src/backend/catalog/objectaddress.c | 6 ++--- src/backend/commands/sequence.c | 2 +- src/backend/executor/execExprInterp.c | 15 +++++++---- src/backend/replication/slotfuncs.c | 8 +++--- src/backend/replication/walreceiver.c | 3 ++- src/backend/statistics/mcv.c | 2 +- src/backend/tsearch/wparser.c | 4 +-- src/backend/utils/adt/acl.c | 2 +- src/backend/utils/adt/datetime.c | 2 +- src/backend/utils/adt/genfile.c | 2 +- src/backend/utils/adt/lockfuncs.c | 4 +-- src/backend/utils/adt/misc.c | 4 +-- src/backend/utils/adt/partitionfuncs.c | 2 +- src/backend/utils/adt/pgstatfuncs.c | 6 +++-- src/backend/utils/adt/rowtypes.c | 4 +-- src/backend/utils/adt/tsvector_op.c | 4 +-- src/backend/utils/misc/guc.c | 2 +- src/backend/utils/misc/pg_controldata.c | 8 +++--- src/include/access/htup_details.h | 1 + src/include/fmgr.h | 8 ++++++ src/include/funcapi.h | 14 ++++++++++ src/pl/plperl/plperl.c | 4 +-- src/pl/tcl/pltcl.c | 4 +-- .../modules/test_predtest/test_predtest.c | 3 ++- 49 files changed, 144 insertions(+), 88 deletions(-) diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 3a0beaa88e..5a41116e8e 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c index b3304ff844..cc7a8e0eef 100644 --- a/contrib/hstore/hstore_io.c +++ b/contrib/hstore/hstore_io.c @@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS) * check domain constraints before deciding we're done. */ if (argtype != tupdesc->tdtypeid) - domain_check(HeapTupleGetDatum(rettuple), false, + domain_check(HeapTupleGetRawDatum(rettuple), false, argtype, &my_extra->domain_info, fcinfo->flinfo->fn_mcxt); ReleaseTupleDesc(tupdesc); - PG_RETURN_DATUM(HeapTupleGetDatum(rettuple)); + PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data); } diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c index dd79d01cac..d466f6cc46 100644 --- a/contrib/hstore/hstore_op.c +++ b/contrib/hstore/hstore_op.c @@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS) } tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls); - res = HeapTupleGetDatum(tuple); + res = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, PointerGetDatum(res)); } diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c index 3df07177ed..5d517c8afc 100644 --- a/contrib/old_snapshot/time_mapping.c +++ b/contrib/old_snapshot/time_mapping.c @@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS) tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping); ++mapping->current_index; - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple)); } SRF_RETURN_DONE(funcctx); diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c index 0e3c2deb66..626294685a 100644 --- a/contrib/pageinspect/brinfuncs.c +++ b/contrib/pageinspect/brinfuncs.c @@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS) htup = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(htup)); + PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data); } /* diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c index b7725b572f..f0028e4cc4 100644 --- a/contrib/pageinspect/btreefuncs.c +++ b/contrib/pageinspect/btreefuncs.c @@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version) tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); PG_RETURN_DATUM(result); } @@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs) /* Build and return the result tuple */ tuple = heap_form_tuple(uargs->tupd, values, nulls); - return HeapTupleGetDatum(tuple); + return HeapTupleGetRawDatum(tuple); } /*------------------------------------------------------- @@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); UnlockReleaseBuffer(buffer); relation_close(rel, AccessShareLock); diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c index e425cbcdb8..77dd559c7e 100644 --- a/contrib/pageinspect/ginfuncs.c +++ b/contrib/pageinspect/ginfuncs.c @@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS) /* Build and return the result tuple. */ resultTuple = heap_form_tuple(tupdesc, values, nulls); - return HeapTupleGetDatum(resultTuple); + return HeapTupleGetRawDatum(resultTuple); } @@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS) /* Build and return the result tuple. */ resultTuple = heap_form_tuple(tupdesc, values, nulls); - return HeapTupleGetDatum(resultTuple); + return HeapTupleGetRawDatum(resultTuple); } typedef struct gin_leafpage_items_state @@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS) /* Build and return the result tuple. */ resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls); - result = HeapTupleGetDatum(resultTuple); + result = HeapTupleGetRawDatum(resultTuple); inter_call_data->seg = GinNextPostingListSegment(cur); diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c index eb9f6303df..dbf34f87d4 100644 --- a/contrib/pageinspect/gistfuncs.c +++ b/contrib/pageinspect/gistfuncs.c @@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS) /* Build and return the result tuple. */ resultTuple = heap_form_tuple(tupdesc, values, nulls); - return HeapTupleGetDatum(resultTuple); + return HeapTupleGetRawDatum(resultTuple); } Datum diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c index ff01119474..957ee5bc14 100644 --- a/contrib/pageinspect/hashfuncs.c +++ b/contrib/pageinspect/hashfuncs.c @@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS) tuple = heap_form_tuple(tupleDesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); + PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data); } /* @@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS) values[j] = Int64GetDatum((int64) hashkey); tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); uargs->offset = uargs->offset + 1; @@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS) tuple = heap_form_tuple(tupleDesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); + PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data); } /* ------------------------------------------------ @@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS) tuple = heap_form_tuple(tupleDesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); + PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data); } diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c index f6760eb31e..3a050ee88c 100644 --- a/contrib/pageinspect/heapfuncs.c +++ b/contrib/pageinspect/heapfuncs.c @@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS) /* Build and return the result tuple. */ resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls); - result = HeapTupleGetDatum(resultTuple); + result = HeapTupleGetRawDatum(resultTuple); inter_call_data->offset++; @@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS) values[0] = PointerGetDatum(construct_empty_array(TEXTOID)); values[1] = PointerGetDatum(construct_empty_array(TEXTOID)); tuple = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); + PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data); } /* build set of raw flags */ @@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS) /* Returns the record as Datum */ tuple = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); + PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data); } diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c index 7272b21016..e7aab866b8 100644 --- a/contrib/pageinspect/rawpage.c +++ b/contrib/pageinspect/rawpage.c @@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS) memset(nulls, 0, sizeof(nulls)); tuple = heap_form_tuple(tupdesc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); PG_RETURN_DATUM(result); } diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 1bd579fcbb..1fd405e5df 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) /* Build and return the tuple. */ tuple = heap_form_tuple(fctx->tupdesc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 62cccbfa44..7eb80d5b78 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS) values[0] = Int64GetDatum(stats.dealloc); values[1] = TimestampTzGetDatum(stats.stats_reset); - PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); + PG_RETURN_HEAPTUPLEHEADER_RAW( + heap_form_tuple(tupdesc, values, nulls)->t_data); } /* diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index dd0c124e62..43bb2ab852 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS) relation_close(rel, AccessShareLock); - PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); + PG_RETURN_HEAPTUPLEHEADER_RAW( + heap_form_tuple(tupdesc, values, nulls)->t_data); } /* @@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS) relation_close(rel, AccessShareLock); - PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); + PG_RETURN_HEAPTUPLEHEADER_RAW( + heap_form_tuple(tupdesc, values, nulls)->t_data); } /* @@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS) info->next++; tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple)); } SRF_RETURN_DONE(funcctx); @@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS) info->next++; tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple)); } SRF_RETURN_DONE(funcctx); @@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS) values[0] = Int64GetDatum(all_visible); values[1] = Int64GetDatum(all_frozen); - PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); + PG_RETURN_HEAPTUPLEHEADER_RAW( + heap_form_tuple(tupdesc, values, nulls)->t_data); } /* diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c index 0536bfb892..333f7fd391 100644 --- a/contrib/pgcrypto/pgp-pgsql.c +++ b/contrib/pgcrypto/pgp-pgsql.c @@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS) /* build a tuple */ tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple)); } } diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c index 1fe193bb25..147c8d22eb 100644 --- a/contrib/pgstattuple/pgstatapprox.c +++ b/contrib/pgstattuple/pgstatapprox.c @@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo) values[i++] = Float8GetDatum(stat.free_percent); ret = heap_form_tuple(tupdesc, values, nulls); - return HeapTupleGetDatum(ret); + return HeapTupleGetRawDatum(ret); } diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c index 5368bb30f0..7d74c316c7 100644 --- a/contrib/pgstattuple/pgstatindex.c +++ b/contrib/pgstattuple/pgstatindex.c @@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo) tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); } return result; @@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo) * Build and return the tuple */ tuple = heap_form_tuple(tupleDesc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); return result; } @@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS) values[7] = Float8GetDatum(free_percent); tuple = heap_form_tuple(tupleDesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); + PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data); } /* ------------------------------------------------- diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index 21fdeff8af..70b8bf0855 100644 --- a/contrib/pgstattuple/pgstattuple.c +++ b/contrib/pgstattuple/pgstattuple.c @@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - return HeapTupleGetDatum(tuple); + return HeapTupleGetRawDatum(tuple); } /* ---------- diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c index 30cae0bb98..53801e92cd 100644 --- a/contrib/sslinfo/sslinfo.c +++ b/contrib/sslinfo/sslinfo.c @@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS) /* Build tuple */ tuple = heap_form_tuple(fctx->tupdesc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); if (BIO_free(membuf) != 1) elog(ERROR, "could not free OpenSSL BIO structure"); diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index 41bcc5b79d..7707400c42 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -2923,14 +2923,18 @@ HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) Once you have built a tuple to return from your function, it - must be converted into a Datum. Use: + must be converted into a Datum. Use one of the following: HeapTupleGetDatum(HeapTuple tuple) +HeapTupleGetRawDatum(HeapTuple tuple) to convert a HeapTuple into a valid Datum. This Datum can be returned directly if you intend to return just a single row, or it can be used as the current return value - in a set-returning function. + in a set-returning function. HeapTupleGetRawDatum + is more efficient and is preferred for new code, but the caller must + ensure that the tuple contains no external TOAST pointers. If this + is not certain, use HeapTupleGetDatum. diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 0b56b0fa5a..06479f5f76 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc) Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc) { - HeapTupleHeader td; - /* * If the tuple contains any external TOAST pointers, we have to inline * those fields to meet the conventions for composite-type Datums. @@ -993,11 +991,29 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc) return toast_flatten_tuple_to_datum(tuple->t_data, tuple->t_len, tupleDesc); + else + return heap_copy_tuple_as_raw_datum(tuple, tupleDesc); +} + +/* ---------------- + * heap_copy_tuple_as_raw_datum + * + * copy a tuple as a composite-type Datum, but the input tuple should not + * contain any external data. + * ---------------- + */ +Datum +heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc) +{ + HeapTupleHeader td; + + /* The tuple should not contains any external TOAST pointers. */ + Assert(!HeapTupleHasExternal(tuple)); /* - * Fast path for easy case: just make a palloc'd copy and insert the - * correct composite-Datum header fields (since those may not be set if - * the given tuple came from disk, rather than from heap_form_tuple). + * Just make a palloc'd copy and insert the correct composite-Datum + * header fields (since those may not be set if the given tuple came + * from disk, rather than from heap_form_tuple). */ td = (HeapTupleHeader) palloc(tuple->t_len); memcpy((char *) td, (char *) tuple->t_data, tuple->t_len); diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c index 48e8d66286..015c84179e 100644 --- a/src/backend/access/transam/commit_ts.c +++ b/src/backend/access/transam/commit_ts.c @@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS) htup = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(htup)); + PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data); } /* @@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS) htup = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(htup)); + PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data); } /* diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 1f9f1a1fa1..b44066a4eb 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS) multi->iter++; pfree(values[0]); - SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple)); + SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple)); } SRF_RETURN_DONE(funccxt); diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 6023e7c16f..3f48597c2a 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS) values[4] = ObjectIdGetDatum(proc->databaseId); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index f363a4c639..f60d6f1496 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS) */ resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull); - result = HeapTupleGetDatum(resultHeapTuple); + result = HeapTupleGetRawDatum(resultHeapTuple); PG_RETURN_DATUM(result); } diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 6d88b690d8..7cd62e70b8 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS) htup = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(htup)); + PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data); } /* @@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS) htup = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(htup)); + PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data); } /* @@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS) htup = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(htup)); + PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data); } /* diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 0415df9ccb..f566e1e0a5 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS) ReleaseSysCache(pgstuple); - return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull)); + return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull)); } /* diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 6308286d8c..e47ab1ec15 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext { /* Full conversion with attribute rearrangement needed */ result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map); - /* Result already has appropriate composite-datum header fields */ - *op->resvalue = HeapTupleGetDatum(result); + + /* + * Result already has appropriate composite-datum header fields. The + * input was a composite type so we aren't expecting to have to + * flatten any toasted fields so directly call HeapTupleGetRawDatum. + */ + *op->resvalue = HeapTupleGetRawDatum(result); } else { @@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext * for this since it will both make the physical copy and insert the * correct composite header fields. Note that we aren't expecting to * have to flatten any toasted fields: the input was a composite - * datum, so it shouldn't contain any. So heap_copy_tuple_as_datum() - * is overkill here, but its check for external fields is cheap. + * datum, so it shouldn't contain any. So we can directly call + * heap_copy_tuple_as_raw_datum(). */ - *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc); + *op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc); } } diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c index 9817b44113..f92628bc59 100644 --- a/src/backend/replication/slotfuncs.c +++ b/src/backend/replication/slotfuncs.c @@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS) nulls[1] = true; tuple = heap_form_tuple(tupdesc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); ReplicationSlotRelease(); @@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS) memset(nulls, 0, sizeof(nulls)); tuple = heap_form_tuple(tupdesc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); /* ok, slot is now fully created, mark it as persistent if needed */ if (!temporary) @@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS) nulls[1] = false; tuple = heap_form_tuple(tupdesc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); PG_RETURN_DATUM(result); } @@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot) nulls[1] = true; tuple = heap_form_tuple(tupdesc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); ReplicationSlotRelease(); diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 8532296f26..f5425a385c 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -1423,5 +1423,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS) } /* Returns the record as Datum */ - PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); + PG_RETURN_HEAPTUPLEHEADER_RAW( + heap_form_tuple(tupdesc, values, nulls)->t_data); } diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c index abbc1f1ba8..115131c707 100644 --- a/src/backend/statistics/mcv.c +++ b/src/backend/statistics/mcv.c @@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS) tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls); /* make the tuple into a datum */ - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c index 71882dced9..633c90d08d 100644 --- a/src/backend/tsearch/wparser.c +++ b/src/backend/tsearch/wparser.c @@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx) values[2] = st->list[st->cur].descr; tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); pfree(values[1]); pfree(values[2]); @@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx) sprintf(tid, "%d", st->list[st->cur].type); values[1] = st->list[st->cur].lexeme; tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); pfree(values[1]); st->cur++; diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index c7f029e218..5871c0b404 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS) MemSet(nulls, 0, sizeof(nulls)); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 350b0c55ea..ce11554b3b 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS) (*pindex)++; tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index 7cf9a0efbe..711a094ddc 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS) pfree(filename); - PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); + PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data); } /* diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 97f0265c12..081844939b 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS) nulls[15] = true; tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } @@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS) nulls[15] = true; tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 634f574d7e..57e0ea09a3 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple)); } SRF_RETURN_DONE(funcctx); @@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS) tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple)); } SRF_RETURN_DONE(funcctx); diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c index 03660d5db6..6915939f43 100644 --- a/src/backend/utils/adt/partitionfuncs.c +++ b/src/backend/utils/adt/partitionfuncs.c @@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS) values[3] = Int32GetDatum(level); tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 5102227a60..b93ad73241 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS) values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp); /* Returns the record as Datum */ - PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); + PG_RETURN_HEAPTUPLEHEADER_RAW( + heap_form_tuple(tupdesc, values, nulls)->t_data); } /* @@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS) values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp); /* Returns the record as Datum */ - PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); + PG_RETURN_HEAPTUPLEHEADER_RAW( + heap_form_tuple(tupdesc, values, nulls)->t_data); } /* Get the statistics for the replication slots */ diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c index 23787a6ae7..079a5af5fb 100644 --- a/src/backend/utils/adt/rowtypes.c +++ b/src/backend/utils/adt/rowtypes.c @@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS) pfree(nulls); ReleaseTupleDesc(tupdesc); - PG_RETURN_HEAPTUPLEHEADER(result); + PG_RETURN_HEAPTUPLEHEADER_RAW(result); } /* @@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS) pfree(nulls); ReleaseTupleDesc(tupdesc); - PG_RETURN_HEAPTUPLEHEADER(result); + PG_RETURN_HEAPTUPLEHEADER_RAW(result); } /* diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c index 9236ebcc8f..6679493247 100644 --- a/src/backend/utils/adt/tsvector_op.c +++ b/src/backend/utils/adt/tsvector_op.c @@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS) } tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple)); } else { @@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx) values[2] = nentry; tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); pfree(values[0]); diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index b263e3493b..6b2d9d6693 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -9805,7 +9805,7 @@ show_all_settings(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - result = HeapTupleGetDatum(tuple); + result = HeapTupleGetRawDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c index 209a20a882..195c127739 100644 --- a/src/backend/utils/misc/pg_controldata.c +++ b/src/backend/utils/misc/pg_controldata.c @@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS) htup = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(htup)); + PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data); } Datum @@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS) htup = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(htup)); + PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data); } Datum @@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS) htup = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(htup)); + PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data); } Datum @@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS) htup = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM(HeapTupleGetDatum(htup)); + PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data); } diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index 7c62852e7f..7ac3c2382d 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc, extern HeapTuple heap_copytuple(HeapTuple tuple); extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest); extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc); +extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc); extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull); extern HeapTuple heap_modify_tuple(HeapTuple tuple, diff --git a/src/include/fmgr.h b/src/include/fmgr.h index ab7b85c86e..89eec7275a 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -372,7 +372,15 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum); #define PG_RETURN_TEXT_P(x) PG_RETURN_POINTER(x) #define PG_RETURN_BPCHAR_P(x) PG_RETURN_POINTER(x) #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x) + +/* + * A composite-type Datum must not contain external fields. To return a tuple + * that might, use PG_RETURN_HEAPTUPLEHEADER, which will build a replacement + * tuple without such fields if any are present. Otherwise, use + * PG_RETURN_HEAPTUPLEHEADER_RAW, which is slightly faster. + */ #define PG_RETURN_HEAPTUPLEHEADER(x) return HeapTupleHeaderGetDatum(x) +#define PG_RETURN_HEAPTUPLEHEADER_RAW(x) return HeapTupleHeaderGetRawDatum(x) /*------------------------------------------------------------------------- diff --git a/src/include/funcapi.h b/src/include/funcapi.h index 83e6bc2a1f..92cc7bdf04 100644 --- a/src/include/funcapi.h +++ b/src/include/funcapi.h @@ -207,6 +207,8 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple); * * Macro declarations: * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum. + * HeapTupleGetRawDatum(HeapTuple tuple) - same, but must have no external + * TOAST pointer * * Obsolete routines and macros: * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a @@ -219,6 +221,7 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple); */ #define HeapTupleGetDatum(tuple) HeapTupleHeaderGetDatum((tuple)->t_data) +#define HeapTupleGetRawDatum(tuple) HeapTupleHeaderGetRawDatum((tuple)->t_data) /* obsolete version of above */ #define TupleGetDatum(_slot, _tuple) HeapTupleGetDatum(_tuple) @@ -231,6 +234,17 @@ extern AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc); extern HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values); extern Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple); +/* + * This is a faster version of HeapTupleHeaderGetDatum which can be used + * when it is known that no external TOAST pointers are present. + */ +static inline Datum +HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) +{ + Assert(!HeapTupleHeaderHasExternal(tuple)); + return PointerGetDatum(tuple); +} + /*---------- * Support for Set Returning Functions (SRFs) diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 6299adf71a..cdf79f78e8 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td) { HeapTuple tup = plperl_build_tuple_result((HV *) SvRV(src), td); - return HeapTupleGetDatum(tup); + return HeapTupleGetRawDatum(tup); } /* @@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv) current_call_data->ret_tdesc); if (OidIsValid(current_call_data->cdomain_oid)) - domain_check(HeapTupleGetDatum(tuple), false, + domain_check(HeapTupleGetRawDatum(tuple), false, current_call_data->cdomain_oid, ¤t_call_data->cdomain_info, rsi->econtext->ecxt_per_query_memory); diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index e11837559d..b4e710a22a 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc, call_state); - retval = HeapTupleGetDatum(tup); + retval = HeapTupleGetRawDatum(tup); } else retval = InputFunctionCall(&prodesc->result_in_func, @@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc, /* if result type is domain-over-composite, check domain constraints */ if (call_state->prodesc->fn_retisdomain) - domain_check(HeapTupleGetDatum(tuple), false, + domain_check(HeapTupleGetRawDatum(tuple), false, call_state->prodesc->result_typid, &call_state->prodesc->domain_info, call_state->prodesc->fn_cxt); diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c index 9c0aadd61c..ec83645bbe 100644 --- a/src/test/modules/test_predtest/test_predtest.c +++ b/src/test/modules/test_predtest/test_predtest.c @@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS) values[6] = BoolGetDatum(s_r_holds); values[7] = BoolGetDatum(w_r_holds); - PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); + PG_RETURN_HEAPTUPLEHEADER_RAW( + heap_form_tuple(tupdesc, values, nulls)->t_data); } -- 2.24.3 (Apple Git-128)