Allow CREATE FOREIGN TABLE to include SERIAL columns.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 15 May 2013 23:03:29 +0000 (19:03 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 15 May 2013 23:03:29 +0000 (19:03 -0400)
The behavior is that the required sequence is created locally, which is
appropriate because the default expression will be evaluated locally.
Per gripe from Brad Nicholson that this case was refused with a confusing
error message.  We could have improved the error message but it seems
better to just allow the case.

Also, remove ALTER TABLE's arbitrary prohibition against being applied to
foreign tables, which was pretty inconsistent considering we allow it for
views, sequences, and other relation types that aren't even called tables.
This is needed to avoid breaking pg_dump, which sometimes emits column
defaults using separate ALTER TABLE commands.  (I think this can happen
even when the default is not associated with a sequence, so that was a
pre-existing bug once we allowed column defaults for foreign tables.)

contrib/postgres_fdw/expected/postgres_fdw.out
contrib/postgres_fdw/sql/postgres_fdw.sql
src/backend/commands/sequence.c
src/backend/commands/tablecmds.c

index cb007cd58d6acc1e3e333058b835f2e323f05e69..e53530a69a9d0d79caf35f47db70978b193073b6 100644 (file)
@@ -2339,3 +2339,37 @@ select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
  407 |   100
 (13 rows)
 
+-- ===================================================================
+-- test serial columns (ie, sequence-based defaults)
+-- ===================================================================
+create table loc1 (f1 serial, f2 text);
+create foreign table rem1 (f1 serial, f2 text)
+  server loopback options(table_name 'loc1');
+select pg_catalog.setval('rem1_f1_seq', 10, false);
+ setval 
+--------
+     10
+(1 row)
+
+insert into loc1(f2) values('hi');
+insert into rem1(f2) values('hi remote');
+insert into loc1(f2) values('bye');
+insert into rem1(f2) values('bye remote');
+select * from loc1;
+ f1 |     f2     
+----+------------
+  1 | hi
+ 10 | hi remote
+  2 | bye
+ 11 | bye remote
+(4 rows)
+
+select * from rem1;
+ f1 |     f2     
+----+------------
+  1 | hi
+ 10 | hi remote
+  2 | bye
+ 11 | bye remote
+(4 rows)
+
index 670d769a80d76deea062a3f66c847a5591b177dc..7ebd9504d6fad706de2e51a5ebc52fbc1fb2846c 100644 (file)
@@ -369,3 +369,17 @@ select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
 commit;
 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
 select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
+
+-- ===================================================================
+-- test serial columns (ie, sequence-based defaults)
+-- ===================================================================
+create table loc1 (f1 serial, f2 text);
+create foreign table rem1 (f1 serial, f2 text)
+  server loopback options(table_name 'loc1');
+select pg_catalog.setval('rem1_f1_seq', 10, false);
+insert into loc1(f2) values('hi');
+insert into rem1(f2) values('hi remote');
+insert into loc1(f2) values('bye');
+insert into rem1(f2) values('bye remote');
+select * from loc1;
+select * from rem1;
index ff855d60e5d8606c2f1359114a0e1483a0d0d7c9..49e409a5eed05924ac332df7781e544912f3480e 100644 (file)
@@ -1440,11 +1440,12 @@ process_owned_by(Relation seqrel, List *owned_by)
                rel = makeRangeVarFromNameList(relname);
                tablerel = relation_openrv(rel, AccessShareLock);
 
-               /* Must be a regular table */
-               if (tablerel->rd_rel->relkind != RELKIND_RELATION)
+               /* Must be a regular or foreign table */
+               if (!(tablerel->rd_rel->relkind == RELKIND_RELATION ||
+                         tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE))
                        ereport(ERROR,
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                                        errmsg("referenced relation \"%s\" is not a table",
+                                        errmsg("referenced relation \"%s\" is not a table or foreign table",
                                                        RelationGetRelationName(tablerel))));
 
                /* We insist on same owner and schema */
index cd2c9610085a8455feb4db03992cbfc9efeb3322..fe32834953380f88444e868cc2becb14b94fff2a 100644 (file)
@@ -10518,19 +10518,16 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
                                 errmsg("\"%s\" is a composite type", rv->relname),
                                 errhint("Use ALTER TYPE instead.")));
 
-       if (reltype != OBJECT_FOREIGN_TABLE && relkind == RELKIND_FOREIGN_TABLE)
-               ereport(ERROR,
-                               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                                errmsg("\"%s\" is a foreign table", rv->relname),
-                                errhint("Use ALTER FOREIGN TABLE instead.")));
-
        /*
         * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
         * to a different schema, such as indexes and TOAST tables.
         */
-       if (IsA(stmt, AlterObjectSchemaStmt) && relkind != RELKIND_RELATION
-               && relkind != RELKIND_VIEW && relkind != RELKIND_MATVIEW
-               && relkind != RELKIND_SEQUENCE && relkind != RELKIND_FOREIGN_TABLE)
+       if (IsA(stmt, AlterObjectSchemaStmt) &&
+               relkind != RELKIND_RELATION &&
+               relkind != RELKIND_VIEW &&
+               relkind != RELKIND_MATVIEW &&
+               relkind != RELKIND_SEQUENCE &&
+               relkind != RELKIND_FOREIGN_TABLE)
                ereport(ERROR,
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                        errmsg("\"%s\" is not a table, view, sequence, or foreign table",