Have CREATE TABLE LIKE add OID column if any LIKEd table has one
authorBruce Momjian <[email protected]>
Tue, 6 Oct 2015 01:19:16 +0000 (21:19 -0400)
committerBruce Momjian <[email protected]>
Tue, 6 Oct 2015 01:19:16 +0000 (21:19 -0400)
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
src/test/regress/expected/create_table.out
src/test/regress/expected/create_table_like.out
src/test/regress/sql/create_table.sql
src/test/regress/sql/create_table_like.sql

index 16d40c724065388a2384493e66ecb6bc847a2834..14384d58dbe7ccfb58eaa4ec7ea835922e7936d5 100644 (file)
@@ -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.
index 8ba7bbc1113ad207c91ac63c9e2d897330e40bb0..41ceb874e8f650f82f66ddc06b9c8b955474d61a 100644 (file)
@@ -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;
index a5fac7b10746a4c7621f5f1f5e9e8c5cb41f9b09..97edde17cf7fe6c622d72b3241eb177aee245025 100644 (file)
@@ -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;
index 03bb5ff704e494c5c70f29e5493bf4e0f6f341dc..78bdc8bf5e7d6e9d6078dcf75203d55a1ac3bb3d 100644 (file)
@@ -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;
index 2d017bc02b5b12f155e9147ef68eccb141394f96..6dded1fdefc0948f16900d30099b3690a32aaa8f 100644 (file)
@@ -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;