From 2f1d558bcb7d41f185d33cefeae68edaac2671ff Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 21 Aug 2015 11:19:33 -0400
Subject: [PATCH] Allow record_in() and record_recv() to work for transient
 record types.

If we have the typmod that identifies a registered record type, there's no
reason that record_in() should refuse to perform input conversion for it.
Now, in direct SQL usage, record_in() will always be passed typmod = -1
with type OID RECORDOID, because no typmodin exists for type RECORD, so the
case can't arise.  However, some InputFunctionCall users such as PLs may be
able to supply the right typmod, so we should allow this to support them.

Note: the previous coding and comment here predate commit 59c016aa9f490b53.
There has been no case since 8.1 in which the passed type OID wouldn't be
valid; and if it weren't, this error message wouldn't be apropos anyway.
Better to let lookup_rowtype_tupdesc complain about it.

Back-patch to 9.1, as this is necessary for my upcoming plpython fix.
I'm committing it separately just to make it a bit more visible in the
commit history.
---
 src/backend/utils/adt/rowtypes.c | 39 ++++++++++++++------------------
 1 file changed, 17 insertions(+), 22 deletions(-)

diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 63a629fa335..dd22ef5586f 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -71,12 +71,8 @@ record_in(PG_FUNCTION_ARGS)
 {
 	char	   *string = PG_GETARG_CSTRING(0);
 	Oid			tupType = PG_GETARG_OID(1);
-
-#ifdef NOT_USED
-	int32		typmod = PG_GETARG_INT32(2);
-#endif
+	int32		tupTypmod = PG_GETARG_INT32(2);
 	HeapTupleHeader result;
-	int32		tupTypmod;
 	TupleDesc	tupdesc;
 	HeapTuple	tuple;
 	RecordIOData *my_extra;
@@ -89,16 +85,17 @@ record_in(PG_FUNCTION_ARGS)
 	StringInfoData buf;
 
 	/*
-	 * Use the passed type unless it's RECORD; we can't support input of
-	 * anonymous types, mainly because there's no good way to figure out which
-	 * anonymous type is wanted.  Note that for RECORD, what we'll probably
-	 * actually get is RECORD's typelem, ie, zero.
+	 * Give a friendly error message if we did not get enough info to identify
+	 * the target record type.  (lookup_rowtype_tupdesc would fail anyway, but
+	 * with a non-user-friendly message.)  In ordinary SQL usage, we'll get -1
+	 * for typmod, since composite types and RECORD have no type modifiers at
+	 * the SQL level, and thus must fail for RECORD.  However some callers can
+	 * supply a valid typmod, and then we can do something useful for RECORD.
 	 */
-	if (tupType == InvalidOid || tupType == RECORDOID)
+	if (tupType == RECORDOID && tupTypmod < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		   errmsg("input of anonymous composite types is not implemented")));
-	tupTypmod = -1;				/* for all non-anonymous types */
 
 	/*
 	 * This comes from the composite type's pg_type.oid and stores system oids
@@ -447,12 +444,8 @@ record_recv(PG_FUNCTION_ARGS)
 {
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	Oid			tupType = PG_GETARG_OID(1);
-
-#ifdef NOT_USED
-	int32		typmod = PG_GETARG_INT32(2);
-#endif
+	int32		tupTypmod = PG_GETARG_INT32(2);
 	HeapTupleHeader result;
-	int32		tupTypmod;
 	TupleDesc	tupdesc;
 	HeapTuple	tuple;
 	RecordIOData *my_extra;
@@ -464,16 +457,18 @@ record_recv(PG_FUNCTION_ARGS)
 	bool	   *nulls;
 
 	/*
-	 * Use the passed type unless it's RECORD; we can't support input of
-	 * anonymous types, mainly because there's no good way to figure out which
-	 * anonymous type is wanted.  Note that for RECORD, what we'll probably
-	 * actually get is RECORD's typelem, ie, zero.
+	 * Give a friendly error message if we did not get enough info to identify
+	 * the target record type.  (lookup_rowtype_tupdesc would fail anyway, but
+	 * with a non-user-friendly message.)  In ordinary SQL usage, we'll get -1
+	 * for typmod, since composite types and RECORD have no type modifiers at
+	 * the SQL level, and thus must fail for RECORD.  However some callers can
+	 * supply a valid typmod, and then we can do something useful for RECORD.
 	 */
-	if (tupType == InvalidOid || tupType == RECORDOID)
+	if (tupType == RECORDOID && tupTypmod < 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		   errmsg("input of anonymous composite types is not implemented")));
-	tupTypmod = -1;				/* for all non-anonymous types */
+
 	tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
 	ncolumns = tupdesc->natts;
 
-- 
GitLab