From b59ca98209d45f5689fe9de22a7429d4cf09d40c Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 3 Mar 2012 16:03:05 +0200 Subject: [PATCH] Allow CREATE TABLE (LIKE ...) from composite type The only reason this didn't work before was that parserOpenTable() rejects composite types. So use relation_openrv() directly and manually do the errposition() setup that parserOpenTable() does. --- doc/src/sgml/ref/create_table.sgml | 2 +- src/backend/parser/parse_utilcmd.c | 34 ++++++++++++++----- .../regress/expected/create_table_like.out | 14 ++++---- src/test/regress/sql/create_table_like.sql | 4 ++- 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index f55a0010de..bb93214210 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -370,7 +370,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI The LIKE clause can also be used to copy columns from - views or foreign tables. Inapplicable options (e.g., INCLUDING + views, foreign tables, or composite types. Inapplicable options (e.g., INCLUDING INDEXES from a view) are ignored. diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index f1a108a982..43f5634d16 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -636,26 +636,42 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla TupleConstr *constr; AclResult aclresult; char *comment; + ParseCallbackState pcbstate; - relation = parserOpenTable(cxt->pstate, table_like_clause->relation, - AccessShareLock); + setup_parser_errposition_callback(&pcbstate, cxt->pstate, table_like_clause->relation->location); + + relation = relation_openrv(table_like_clause->relation, AccessShareLock); if (relation->rd_rel->relkind != RELKIND_RELATION && relation->rd_rel->relkind != RELKIND_VIEW - && relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE) + && relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE + && relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("LIKE source relation \"%s\" is not a table, view, or foreign table", + errmsg("\"%s\" is not a table, view, composite type, or foreign table", table_like_clause->relation->relname))); + cancel_parser_errposition_callback(&pcbstate); + /* - * Check for SELECT privileges + * Check for privileges */ - aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(), + if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) + { + aclresult = pg_type_aclcheck(relation->rd_rel->reltype, GetUserId(), + ACL_USAGE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_TYPE, + RelationGetRelationName(relation)); + } + else + { + aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(), ACL_SELECT); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_CLASS, - RelationGetRelationName(relation)); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_CLASS, + RelationGetRelationName(relation)); + } tupleDesc = RelationGetDescr(relation); constr = tupleDesc->constr; diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out index 40b6766892..8bec55c3ca 100644 --- a/src/test/regress/expected/create_table_like.out +++ b/src/test/regress/expected/create_table_like.out @@ -8,6 +8,10 @@ CREATE TABLE inhx (xx text DEFAULT 'text'); */ CREATE TABLE ctla (aa TEXT); CREATE TABLE ctlb (bb TEXT) INHERITS (ctla); +CREATE TABLE foo (LIKE nonexistent); +ERROR: relation "nonexistent" does not exist +LINE 1: CREATE TABLE foo (LIKE nonexistent); + ^ CREATE TABLE inhe (ee text, LIKE inhx) inherits (ctlb); INSERT INTO inhe VALUES ('ee-col1', 'ee-col2', DEFAULT, 'ee-col4'); SELECT * FROM inhe; /* Columns aa, bb, xx value NULL, ee */ @@ -224,18 +228,16 @@ NOTICE: drop cascades to table inhe CREATE TABLE ctlt4 (a int, b text); CREATE SEQUENCE ctlseq1; CREATE TABLE ctlt10 (LIKE ctlseq1); -- fail -ERROR: LIKE source relation "ctlseq1" is not a table, view, or foreign table +ERROR: "ctlseq1" is not a table, view, composite type, or foreign table +LINE 1: CREATE TABLE ctlt10 (LIKE ctlseq1); + ^ CREATE VIEW ctlv1 AS SELECT * FROM ctlt4; CREATE TABLE ctlt11 (LIKE ctlv1); CREATE TABLE ctlt11a (LIKE ctlv1 INCLUDING ALL); CREATE TYPE ctlty1 AS (a int, b text); -CREATE TABLE ctlt12 (LIKE ctlty1); -- currently fails -ERROR: "ctlty1" is a composite type -LINE 1: CREATE TABLE ctlt12 (LIKE ctlty1); - ^ +CREATE TABLE ctlt12 (LIKE ctlty1); DROP SEQUENCE ctlseq1; DROP TYPE ctlty1; DROP VIEW ctlv1; DROP TABLE IF EXISTS ctlt4, ctlt10, ctlt11, ctlt11a, ctlt12; NOTICE: table "ctlt10" does not exist, skipping -NOTICE: table "ctlt12" does not exist, skipping diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql index db66e48d45..2d017bc02b 100644 --- a/src/test/regress/sql/create_table_like.sql +++ b/src/test/regress/sql/create_table_like.sql @@ -10,6 +10,8 @@ CREATE TABLE inhx (xx text DEFAULT 'text'); CREATE TABLE ctla (aa TEXT); CREATE TABLE ctlb (bb TEXT) INHERITS (ctla); +CREATE TABLE foo (LIKE nonexistent); + CREATE TABLE inhe (ee text, LIKE inhx) inherits (ctlb); INSERT INTO inhe VALUES ('ee-col1', 'ee-col2', DEFAULT, 'ee-col4'); SELECT * FROM inhe; /* Columns aa, bb, xx value NULL, ee */ @@ -111,7 +113,7 @@ CREATE TABLE ctlt11 (LIKE ctlv1); CREATE TABLE ctlt11a (LIKE ctlv1 INCLUDING ALL); CREATE TYPE ctlty1 AS (a int, b text); -CREATE TABLE ctlt12 (LIKE ctlty1); -- currently fails +CREATE TABLE ctlt12 (LIKE ctlty1); DROP SEQUENCE ctlseq1; DROP TYPE ctlty1; -- 2.40.0