Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gV2DV-0005s7-KR for pgsql-hackers@arkaria.postgresql.org; Thu, 06 Dec 2018 22:33:57 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1gV2DT-0003CL-Ot for pgsql-hackers@arkaria.postgresql.org; Thu, 06 Dec 2018 22:33:55 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gV27O-0005W4-Ot for pgsql-hackers@lists.postgresql.org; Thu, 06 Dec 2018 22:27:38 +0000 Received: from mail-it1-x141.google.com ([2607:f8b0:4864:20::141]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gV27L-0006QU-Dv for pgsql-hackers@postgresql.org; Thu, 06 Dec 2018 22:27:37 +0000 Received: by mail-it1-x141.google.com with SMTP id c9so4160077itj.1 for ; Thu, 06 Dec 2018 14:27:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=dQpz+9skpPY/4L/+yJK9GxIPFPGYZ/qAKlMzIgcj9/Q=; b=hibIqbAvQaNjl5FBZOiSO++pv85WsBORckrdHOZFxgOsUT55ABe3MVGyyc6nen9VUH XPcVIIb+rCkVkczy329DD6xTTbimqRiM3TE4QMQG/kuN/5Nx997HhtyXKdQNqxPYDJ1S DSJEZIeKPShrivK31U6e47568Y8/0zjBaPvQPiPC5+7iKcS9JTL5FIXZQ+TuSF7KDexu GlOMbwaEPuivvbY2OiWpnOKRtmPpsW8k+E9zQPlBEpMtjPTIkGiYx/XKm3Os351mHSOs 4QyRn0gxrzMWhbPHvvXzVAHpesNOJtgzqzzbOqcpIz3Tv/QQI/Alh3rQTGel9K5DjPic jIMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :mime-version:content-transfer-encoding; bh=dQpz+9skpPY/4L/+yJK9GxIPFPGYZ/qAKlMzIgcj9/Q=; b=ore5ByMnreDynTpXvG4n8OnQSPXHFZq/3Na7CTm7PdNEHrg7vYDvaVhmncm2FSXYXa F+XnoszDkU+sVWxWS0Yjtx63YxvIdyyczskXr+lsJPLqAWC38P+nZclZ4qZUWj//Ck/0 8OeREywx18FeNGv993Ruh6E7tmPvK2xtCM2Qo4wGzGp7Bp3j0THYvTa0l/aBNKSrNpKR sX1fWhbZ6kzSauOO1dZC68W6x45P7qtcgS+Zmogr3Pq0wjo4kNpVL72qcgQlRcpscTv0 uSZz+A5ZVrjs8mZHs8hkoIN0eAtp/EVklfZcSwaNnk7XOBOcCx3fNlHzKh/vqjv0PLsx /tdQ== X-Gm-Message-State: AA+aEWYe+IDZFjB6JzywK/YVR9vgdkaOlPM6vOI3q/eDTvE2MkG9Igqi O4nH6p/0QFV+cfFH1OFg3zEerMZ9 X-Google-Smtp-Source: AFSGD/U151bi9pMUNPZ+Rjh1lXsQJW3AMSP7WvYcD3ji52asIk8EEtwALDomr7Q4CW/mhRrnZ3lz0g== X-Received: by 2002:a24:6ac7:: with SMTP id l190mr152684itc.135.1544135254324; Thu, 06 Dec 2018 14:27:34 -0800 (PST) Received: from hammer.magicstack.net (toroon12-3096784575.sdsl.bell.ca. [184.149.46.191]) by smtp.gmail.com with ESMTPSA id 81sm1010992itz.15.2018.12.06.14.27.33 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 06 Dec 2018 14:27:33 -0800 (PST) Sender: Elvis Pranskevichus From: Elvis Pranskevichus To: pgsql-hackers@postgresql.org Subject: [PATCH] Allow anonymous rowtypes in function return column definition Date: Thu, 06 Dec 2018 17:27:32 -0500 Message-ID: <11038447.kQ5A9Uj5xi@hammer.magicstack.net> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart2796157.6Ql7vfLUHz" Content-Transfer-Encoding: 7Bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk This is a multi-part message in MIME format. --nextPart2796157.6Ql7vfLUHz Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" Currently, the following query SELECT q.b = row(2) FROM unnest(ARRAY[row(1, row(2))]) AS q(a int, b record); would fail with ERROR: column "b" has pseudo-type record This is due to CheckAttributeNamesTypes() being used on a function coldeflist as if it was a real relation definition. But in the context of a query there seems to be no harm in allowing this, as other ways of manipulating anonymous rowtypes work well, e.g.: SELECT (ARRAY[ROW(1, ROW(2))])[1]; Elvis --nextPart2796157.6Ql7vfLUHz Content-Disposition: attachment; filename="0001-Allow-anonymous-rowtypes-in-function-return-column-d.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="UTF-8"; name="0001-Allow-anonymous-rowtypes-in-function-return-column-d.patch" From 873ecd6b31abc28c787f398d78ba2511c6e712a2 Mon Sep 17 00:00:00 2001 From: Elvis Pranskevichus Date: Thu, 6 Dec 2018 17:16:28 -0500 Subject: [PATCH] Allow anonymous rowtypes in function return column definition Currently, the following query SELECT q.b = row(2) FROM unnest(ARRAY[row(1, row(2))]) AS q(a int, b record); would fail with ERROR: column "b" has pseudo-type record This is due to CheckAttributeNamesTypes() being used on a function coldeflist as if it was a real relation definition. But in the context of a query there seems to be no harm in allowing this, as other ways of manipulating anonymous rowtypes work well, e.g.: SELECT (ARRAY[ROW(1, ROW(2))])[1]; --- src/backend/catalog/heap.c | 23 +++++++++++++++-------- src/backend/catalog/index.c | 2 +- src/backend/commands/tablecmds.c | 4 ++-- src/backend/parser/parse_relation.c | 2 +- src/include/catalog/heap.h | 6 ++++-- src/test/regress/expected/rowtypes.out | 7 +++++++ src/test/regress/sql/rowtypes.sql | 2 ++ 7 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 8c52a1543d..ab9cb600f1 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -412,7 +412,8 @@ heap_create(const char *relname, */ void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, - bool allow_system_table_mods) + bool allow_system_table_mods, + bool allow_anonymous_records) { int i; int j; @@ -471,7 +472,8 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, TupleDescAttr(tupdesc, i)->atttypid, TupleDescAttr(tupdesc, i)->attcollation, NIL, /* assume we're creating a new rowtype */ - allow_system_table_mods); + allow_system_table_mods, + allow_anonymous_records); } } @@ -494,7 +496,8 @@ void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, - bool allow_system_table_mods) + bool allow_system_table_mods, + bool allow_anonymous_records) { char att_typtype = get_typtype(atttypid); Oid att_typelem; @@ -507,7 +510,8 @@ CheckAttributeType(const char *attname, * catalogs (this allows creating pg_statistic and cloning it during * VACUUM FULL) */ - if (atttypid != ANYARRAYOID || !allow_system_table_mods) + if (!((atttypid == ANYARRAYOID && allow_system_table_mods) || + (atttypid == RECORDOID && allow_anonymous_records))) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("column \"%s\" has pseudo-type %s", @@ -520,7 +524,8 @@ CheckAttributeType(const char *attname, */ CheckAttributeType(attname, getBaseType(atttypid), attcollation, containing_rowtypes, - allow_system_table_mods); + allow_system_table_mods, + allow_anonymous_records); } else if (att_typtype == TYPTYPE_COMPOSITE) { @@ -558,7 +563,8 @@ CheckAttributeType(const char *attname, CheckAttributeType(NameStr(attr->attname), attr->atttypid, attr->attcollation, containing_rowtypes, - allow_system_table_mods); + allow_system_table_mods, + allow_anonymous_records); } relation_close(relation, AccessShareLock); @@ -572,7 +578,8 @@ CheckAttributeType(const char *attname, */ CheckAttributeType(attname, att_typelem, attcollation, containing_rowtypes, - allow_system_table_mods); + allow_system_table_mods, + allow_anonymous_records); } /* @@ -1063,7 +1070,7 @@ heap_create_with_catalog(const char *relname, */ Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode()); - CheckAttributeNamesTypes(tupdesc, relkind, allow_system_table_mods); + CheckAttributeNamesTypes(tupdesc, relkind, allow_system_table_mods, false); /* * This would fail later on anyway, if the relation already exists. But diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 44625a507b..ac5a285be7 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -435,7 +435,7 @@ ConstructTupleDescriptor(Relation heapRelation, */ CheckAttributeType(NameStr(to->attname), to->atttypid, to->attcollation, - NIL, false); + NIL, false, false); } /* diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 357c73073d..0a19209519 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -5488,7 +5488,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, /* make sure datatype is legal for a column */ CheckAttributeType(colDef->colname, typeOid, collOid, list_make1_oid(rel->rd_rel->reltype), - false); + false, false); /* construct new attribute's pg_attribute entry */ attribute.attrelid = myrelid; @@ -9126,7 +9126,7 @@ ATPrepAlterColumnType(List **wqueue, /* make sure datatype is legal for a column */ CheckAttributeType(colName, targettype, targetcollid, list_make1_oid(rel->rd_rel->reltype), - false); + false, false); if (tab->relkind == RELKIND_RELATION || tab->relkind == RELKIND_PARTITIONED_TABLE) diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index bf5df26009..0f224e7718 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -1567,7 +1567,7 @@ addRangeTableEntryForFunction(ParseState *pstate, * Ensure that the coldeflist defines a legal set of names (no * duplicates) and datatypes (no pseudo-types, for instance). */ - CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE, false); + CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE, false, true); } else ereport(ERROR, diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index c5e40ff017..9ee4824af8 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -133,12 +133,14 @@ extern Form_pg_attribute SystemAttributeByName(const char *attname, bool relhasoids); extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, - bool allow_system_table_mods); + bool allow_system_table_mods, + bool allow_anonymous_records); extern void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, - bool allow_system_table_mods); + bool allow_system_table_mods, + bool allow_anonymous_records); /* pg_partitioned_table catalog manipulation functions */ extern void StorePartitionKey(Relation rel, diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out index 30053d07df..0a98725d98 100644 --- a/src/test/regress/expected/rowtypes.out +++ b/src/test/regress/expected/rowtypes.out @@ -668,6 +668,13 @@ select row(1, '(1,2)')::testtype6 *<> row(1, '(1,3)')::testtype6; (1 row) drop type testtype1, testtype2, testtype3, testtype4, testtype5, testtype6; +-- Test anonymous rowtype in coldeflist +SELECT q.b = row(2) FROM unnest(ARRAY[row(1, row(2))]) AS q(a int, b record); + ?column? +---------- + t +(1 row) + -- -- Test case derived from bug #5716: check multiple uses of a rowtype result -- diff --git a/src/test/regress/sql/rowtypes.sql b/src/test/regress/sql/rowtypes.sql index faf2e108d6..08d320426a 100644 --- a/src/test/regress/sql/rowtypes.sql +++ b/src/test/regress/sql/rowtypes.sql @@ -261,6 +261,8 @@ select row(1, '(1,2)')::testtype6 *<> row(1, '(1,3)')::testtype6; drop type testtype1, testtype2, testtype3, testtype4, testtype5, testtype6; +-- Test anonymous rowtype in coldeflist +SELECT q.b = row(2) FROM unnest(ARRAY[row(1, row(2))]) AS q(a int, b record); -- -- Test case derived from bug #5716: check multiple uses of a rowtype result -- 2.19.2 --nextPart2796157.6Ql7vfLUHz--