From b943f502b788a3708ca660785fd14a4ee938fdcd Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Mon, 5 Oct 2015 21:19:16 -0400 Subject: [PATCH] Have CREATE TABLE LIKE add OID column if any LIKEd table has one Also, process constraints for LIKEd tables at the end so an OID column can be referenced in a constraint. Report by Tom Lane --- src/backend/parser/parse_utilcmd.c | 44 ++++++++++++++++--- src/test/regress/expected/create_table.out | 3 ++ .../regress/expected/create_table_like.out | 27 ++++++++++++ src/test/regress/sql/create_table.sql | 4 ++ src/test/regress/sql/create_table_like.sql | 13 ++++++ 5 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 16d40c7240..14384d58db 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -56,6 +56,7 @@ #include "rewrite/rewriteManip.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -150,6 +151,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) Oid namespaceid; Oid existing_relid; ParseCallbackState pcbstate; + bool like_found = false; /* * We must not scribble on the passed-in CreateStmt, so copy it. (This is @@ -242,7 +244,10 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) /* * Run through each primary element in the table creation clause. Separate - * column defs from constraints, and do preliminary analysis. + * column defs from constraints, and do preliminary analysis. We have to + * process column-defining clauses first because it can control the + * presence of columns which are referenced by columns referenced by + * constraints. */ foreach(elements, stmt->tableElts) { @@ -254,14 +259,19 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) transformColumnDefinition(&cxt, (ColumnDef *) element); break; - case T_Constraint: - transformTableConstraint(&cxt, (Constraint *) element); - break; - case T_TableLikeClause: + if (!like_found) + { + cxt.hasoids = false; + like_found = true; + } transformTableLikeClause(&cxt, (TableLikeClause *) element); break; + case T_Constraint: + /* process later */ + break; + default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(element)); @@ -269,6 +279,27 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) } } + if (like_found) + { + /* + * To match INHERITS, the existance of any LIKE table with OIDs + * causes the new table to have oids. For the same reason, + * WITH/WITHOUT OIDs is also ignored with LIKE. We prepend + * because the first oid option list entry is honored. Our + * prepended WITHOUT OIDS clause will be overridden if an + * inherited table has oids. + */ + stmt->options = lcons(makeDefElem("oids", + (Node *)makeInteger(cxt.hasoids)), stmt->options); + } + + foreach(elements, stmt->tableElts) + { + Node *element = lfirst(elements); + + if (nodeTag(element) == T_Constraint) + transformTableConstraint(&cxt, (Constraint *) element); + } /* * transformIndexConstraints wants cxt.alist to contain only index * statements, so transfer anything we already have into save_alist. @@ -860,6 +891,9 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla } } + /* We use oids if at least one LIKE'ed table has oids. */ + cxt->hasoids = cxt->hasoids || relation->rd_rel->relhasoids; + /* * Copy CHECK constraints if requested, being careful to adjust attribute * numbers so they match the child. diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 8ba7bbc111..41ceb874e8 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -250,3 +250,6 @@ ERROR: relation "as_select1" already exists CREATE TABLE IF NOT EXISTS as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r'; NOTICE: relation "as_select1" already exists, skipping DROP TABLE as_select1; +-- check that the oid column is added before the primary key is checked +CREATE TABLE oid_pk (f1 INT, PRIMARY KEY(oid)) WITH OIDS; +DROP TABLE oid_pk; diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out index a5fac7b107..97edde17cf 100644 --- a/src/test/regress/expected/create_table_like.out +++ b/src/test/regress/expected/create_table_like.out @@ -228,3 +228,30 @@ DROP TYPE ctlty1; DROP VIEW ctlv1; DROP TABLE IF EXISTS ctlt4, ctlt10, ctlt11, ctlt11a, ctlt12; NOTICE: table "ctlt10" does not exist, skipping +/* LIKE WITH OIDS */ +CREATE TABLE has_oid (x INTEGER) WITH OIDS; +CREATE TABLE no_oid (y INTEGER); +CREATE TABLE like_test (z INTEGER, LIKE has_oid); +SELECT oid FROM like_test; + oid +----- +(0 rows) + +CREATE TABLE like_test2 (z INTEGER, LIKE no_oid); +SELECT oid FROM like_test2; -- fail +ERROR: column "oid" does not exist +LINE 1: SELECT oid FROM like_test2; + ^ +CREATE TABLE like_test3 (z INTEGER, LIKE has_oid, LIKE no_oid); +SELECT oid FROM like_test3; + oid +----- +(0 rows) + +CREATE TABLE like_test4 (z INTEGER, PRIMARY KEY(oid), LIKE has_oid); +SELECT oid FROM like_test4; + oid +----- +(0 rows) + +DROP TABLE has_oid, no_oid, like_test, like_test2, like_test3, like_test4; diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index 03bb5ff704..78bdc8bf5e 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -265,3 +265,7 @@ CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r'; CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r'; CREATE TABLE IF NOT EXISTS as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r'; DROP TABLE as_select1; + +-- check that the oid column is added before the primary key is checked +CREATE TABLE oid_pk (f1 INT, PRIMARY KEY(oid)) WITH OIDS; +DROP TABLE oid_pk; diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql index 2d017bc02b..6dded1fdef 100644 --- a/src/test/regress/sql/create_table_like.sql +++ b/src/test/regress/sql/create_table_like.sql @@ -119,3 +119,16 @@ DROP SEQUENCE ctlseq1; DROP TYPE ctlty1; DROP VIEW ctlv1; DROP TABLE IF EXISTS ctlt4, ctlt10, ctlt11, ctlt11a, ctlt12; + +/* LIKE WITH OIDS */ +CREATE TABLE has_oid (x INTEGER) WITH OIDS; +CREATE TABLE no_oid (y INTEGER); +CREATE TABLE like_test (z INTEGER, LIKE has_oid); +SELECT oid FROM like_test; +CREATE TABLE like_test2 (z INTEGER, LIKE no_oid); +SELECT oid FROM like_test2; -- fail +CREATE TABLE like_test3 (z INTEGER, LIKE has_oid, LIKE no_oid); +SELECT oid FROM like_test3; +CREATE TABLE like_test4 (z INTEGER, PRIMARY KEY(oid), LIKE has_oid); +SELECT oid FROM like_test4; +DROP TABLE has_oid, no_oid, like_test, like_test2, like_test3, like_test4; -- 2.40.0