On Wed, Sep 15, 2021 at 5:20 PM Alvaro Herrera <alvhe...@alvh.no-ip.org> wrote: > > On 2021-Sep-15, Amit Kapila wrote: > > > On Mon, Sep 6, 2021 at 11:21 PM Alvaro Herrera <alvhe...@alvh.no-ip.org> > > wrote: > > > > > > I pushed the clerical part of this -- namely the addition of > > > PublicationTable node and PublicationRelInfo struct. > > > > One point to note here is that we are developing a generic grammar for > > publications where not only tables but other objects like schema, > > sequences, etc. can be specified, see [1]. So, there is some overlap > > in the grammar modifications being made by this patch and the work > > being done in that other thread. > > Oh rats. I was not aware of that thread, or indeed of the fact that > adding multiple object types to publications was being considered. > > I do see that 0002 there contains gram.y changes, but AFAICS those > changes don't allow specifying a column list for a table, so there are > some changes needed in that patch for that either way. > > I agree that it's better to move forward in unison. > > I noticed that 0002 in that other patch uses a void * pointer in > PublicationObjSpec that "could be either RangeVar or String", which > strikes me as a really bad idea. (Already discussed in some other > thread recently, maybe this one or the row filtering one.)
I have extracted the parser code and attached it here, so that it will be easy to go through. We wanted to support the following syntax as in [1]: CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2, SEQUENCE seq1,seq2, ALL SEQUENCES IN SCHEMA s3,s4; Columns can be added to PublicationObjSpec data structure. The patch Generic_object_type_parser_002_table_schema_publication.patch has the changes that were used to handle the parsing. Schema and Relation both are different objects, schema is of string type and relation is of RangeVar type. While parsing, schema name is parsed in string format and relation is parsed and converted to rangevar type, these objects will be then handled accordingly during post processing. That is the reason it used void * type which could hold both RangeVar and String. Thoughts? [1] - https://www.postgresql.org/message-id/877603.1629120678%40sss.pgh.pa.us Regards, Vignesh
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index d6fddd6efe..2a2fe03c13 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -141,14 +141,14 @@ pg_relation_is_publishable(PG_FUNCTION_ARGS) * Insert new publication / relation mapping. */ ObjectAddress -publication_add_relation(Oid pubid, PublicationRelInfo *targetrel, +publication_add_relation(Oid pubid, Relation targetrel, bool if_not_exists) { Relation rel; HeapTuple tup; Datum values[Natts_pg_publication_rel]; bool nulls[Natts_pg_publication_rel]; - Oid relid = RelationGetRelid(targetrel->relation); + Oid relid = RelationGetRelid(targetrel); Oid prrelid; Publication *pub = GetPublication(pubid); ObjectAddress myself, @@ -172,10 +172,10 @@ publication_add_relation(Oid pubid, PublicationRelInfo *targetrel, ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("relation \"%s\" is already member of publication \"%s\"", - RelationGetRelationName(targetrel->relation), pub->name))); + RelationGetRelationName(targetrel), pub->name))); } - check_publication_add_relation(targetrel->relation); + check_publication_add_relation(targetrel); /* Form a tuple. */ memset(values, 0, sizeof(values)); @@ -209,7 +209,7 @@ publication_add_relation(Oid pubid, PublicationRelInfo *targetrel, table_close(rel, RowExclusiveLock); /* Invalidate relcache so that publication info is rebuilt. */ - CacheInvalidateRelcache(targetrel->relation); + CacheInvalidateRelcache(targetrel); return myself; } diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index 30929da1f5..f5fd463c15 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -34,6 +34,7 @@ #include "commands/publicationcmds.h" #include "funcapi.h" #include "miscadmin.h" +#include "nodes/makefuncs.h" #include "utils/acl.h" #include "utils/array.h" #include "utils/builtins.h" @@ -138,6 +139,34 @@ parse_publication_options(ParseState *pstate, } } +/* + * Convert the PublicationObjSpecType list into rangevar list. + */ +static void +ObjectsInPublicationToOids(List *pubobjspec_list, ParseState *pstate, + List **rels) +{ + ListCell *cell; + PublicationObjSpec *pubobj; + + if (!pubobjspec_list) + return; + + foreach(cell, pubobjspec_list) + { + Node *node; + + pubobj = (PublicationObjSpec *) lfirst(cell); + node = (Node *) pubobj->object; + + if (pubobj->pubobjtype == PUBLICATIONOBJ_TABLE) + { + if (IsA(node, RangeVar)) + *rels = lappend(*rels, (RangeVar *) node); + } + } +} + /* * Create new publication. */ @@ -155,6 +184,7 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) bool publish_via_partition_root_given; bool publish_via_partition_root; AclResult aclresult; + List *relations = NIL; /* must have CREATE privilege on database */ aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CREATE); @@ -224,13 +254,14 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) /* Make the changes visible. */ CommandCounterIncrement(); - if (stmt->tables) + ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations); + if (relations != NIL) { List *rels; - Assert(list_length(stmt->tables) > 0); + Assert(list_length(relations) > 0); - rels = OpenTableList(stmt->tables); + rels = OpenTableList(relations); PublicationAddTables(puboid, rels, true, NULL); CloseTableList(rels); } @@ -360,7 +391,7 @@ AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt, */ static void AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel, - HeapTuple tup) + HeapTuple tup, List *tables) { List *rels = NIL; Form_pg_publication pubform = (Form_pg_publication) GETSTRUCT(tup); @@ -374,13 +405,13 @@ AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel, NameStr(pubform->pubname)), errdetail("Tables cannot be added to or dropped from FOR ALL TABLES publications."))); - Assert(list_length(stmt->tables) > 0); + Assert(list_length(tables) > 0); - rels = OpenTableList(stmt->tables); + rels = OpenTableList(tables); - if (stmt->tableAction == DEFELEM_ADD) + if (stmt->action == DEFELEM_ADD) PublicationAddTables(pubid, rels, false, stmt); - else if (stmt->tableAction == DEFELEM_DROP) + else if (stmt->action == DEFELEM_DROP) PublicationDropTables(pubid, rels, false); else /* DEFELEM_SET */ { @@ -398,10 +429,9 @@ AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel, foreach(newlc, rels) { - PublicationRelInfo *newpubrel; + Relation newrel = (Relation) lfirst(newlc); - newpubrel = (PublicationRelInfo *) lfirst(newlc); - if (RelationGetRelid(newpubrel->relation) == oldrelid) + if (RelationGetRelid(newrel) == oldrelid) { found = true; break; @@ -410,16 +440,10 @@ AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel, /* Not yet in the list, open it and add to the list */ if (!found) { - Relation oldrel; - PublicationRelInfo *pubrel; - - /* Wrap relation into PublicationRelInfo */ - oldrel = table_open(oldrelid, ShareUpdateExclusiveLock); + Relation oldrel = table_open(oldrelid, + ShareUpdateExclusiveLock); - pubrel = palloc(sizeof(PublicationRelInfo)); - pubrel->relation = oldrel; - - delrels = lappend(delrels, pubrel); + delrels = lappend(delrels, oldrel); } } @@ -450,6 +474,7 @@ AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt) Relation rel; HeapTuple tup; Form_pg_publication pubform; + List *relations = NIL; rel = table_open(PublicationRelationId, RowExclusiveLock); @@ -469,10 +494,12 @@ AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_PUBLICATION, stmt->pubname); + ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations); + if (stmt->options) AlterPublicationOptions(pstate, stmt, rel, tup); else - AlterPublicationTables(stmt, rel, tup); + AlterPublicationTables(stmt, rel, tup, relations); /* Cleanup. */ heap_freetuple(tup); @@ -540,7 +567,7 @@ RemovePublicationById(Oid pubid) /* * Open relations specified by a PublicationTable list. - * In the returned list of PublicationRelInfo, tables are locked + * In the returned list of Relation, tables are locked * in ShareUpdateExclusiveLock mode in order to add them to a publication. */ static List * @@ -555,16 +582,15 @@ OpenTableList(List *tables) */ foreach(lc, tables) { - PublicationTable *t = lfirst_node(PublicationTable, lc); - bool recurse = t->relation->inh; + RangeVar *rv = lfirst_node(RangeVar, lc); + bool recurse = rv->inh; Relation rel; Oid myrelid; - PublicationRelInfo *pub_rel; /* Allow query cancel in case this takes a long time */ CHECK_FOR_INTERRUPTS(); - rel = table_openrv(t->relation, ShareUpdateExclusiveLock); + rel = table_openrv(rv, ShareUpdateExclusiveLock); myrelid = RelationGetRelid(rel); /* @@ -580,9 +606,7 @@ OpenTableList(List *tables) continue; } - pub_rel = palloc(sizeof(PublicationRelInfo)); - pub_rel->relation = rel; - rels = lappend(rels, pub_rel); + rels = lappend(rels, rel); relids = lappend_oid(relids, myrelid); /* @@ -615,9 +639,7 @@ OpenTableList(List *tables) /* find_all_inheritors already got lock */ rel = table_open(childrelid, NoLock); - pub_rel = palloc(sizeof(PublicationRelInfo)); - pub_rel->relation = rel; - rels = lappend(rels, pub_rel); + rels = lappend(rels, rel); relids = lappend_oid(relids, childrelid); } } @@ -638,10 +660,9 @@ CloseTableList(List *rels) foreach(lc, rels) { - PublicationRelInfo *pub_rel; + Relation rel = (Relation) lfirst(lc); - pub_rel = (PublicationRelInfo *) lfirst(lc); - table_close(pub_rel->relation, NoLock); + table_close(rel, NoLock); } } @@ -658,8 +679,7 @@ PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, foreach(lc, rels) { - PublicationRelInfo *pub_rel = (PublicationRelInfo *) lfirst(lc); - Relation rel = pub_rel->relation; + Relation rel = (Relation) lfirst(lc); ObjectAddress obj; /* Must be owner of the table or superuser. */ @@ -667,7 +687,7 @@ PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind), RelationGetRelationName(rel)); - obj = publication_add_relation(pubid, pub_rel, if_not_exists); + obj = publication_add_relation(pubid, rel, if_not_exists); if (stmt) { EventTriggerCollectSimpleCommand(obj, InvalidObjectAddress, @@ -691,8 +711,7 @@ PublicationDropTables(Oid pubid, List *rels, bool missing_ok) foreach(lc, rels) { - PublicationRelInfo *pubrel = (PublicationRelInfo *) lfirst(lc); - Relation rel = pubrel->relation; + Relation rel = (Relation) lfirst(lc); Oid relid = RelationGetRelid(rel); prid = GetSysCacheOid2(PUBLICATIONRELMAP, Anum_pg_publication_rel_oid, diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 228387eaee..ade93023b8 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -4817,7 +4817,7 @@ _copyCreatePublicationStmt(const CreatePublicationStmt *from) COPY_STRING_FIELD(pubname); COPY_NODE_FIELD(options); - COPY_NODE_FIELD(tables); + COPY_NODE_FIELD(pubobjects); COPY_SCALAR_FIELD(for_all_tables); return newnode; @@ -4830,9 +4830,9 @@ _copyAlterPublicationStmt(const AlterPublicationStmt *from) COPY_STRING_FIELD(pubname); COPY_NODE_FIELD(options); - COPY_NODE_FIELD(tables); + COPY_NODE_FIELD(pubobjects); COPY_SCALAR_FIELD(for_all_tables); - COPY_SCALAR_FIELD(tableAction); + COPY_SCALAR_FIELD(action); return newnode; } @@ -4958,12 +4958,14 @@ _copyForeignKeyCacheInfo(const ForeignKeyCacheInfo *from) return newnode; } -static PublicationTable * -_copyPublicationTable(const PublicationTable *from) +static PublicationObjSpec * +_copyPublicationObject(const PublicationObjSpec *from) { - PublicationTable *newnode = makeNode(PublicationTable); + PublicationObjSpec *newnode = makeNode(PublicationObjSpec); - COPY_NODE_FIELD(relation); + COPY_SCALAR_FIELD(pubobjtype); + COPY_NODE_FIELD(object); + COPY_LOCATION_FIELD(location); return newnode; } @@ -5887,8 +5889,8 @@ copyObjectImpl(const void *from) case T_PartitionCmd: retval = _copyPartitionCmd(from); break; - case T_PublicationTable: - retval = _copyPublicationTable(from); + case T_PublicationObjSpec: + retval = _copyPublicationObject(from); break; /* diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 800f588b5c..06917598f4 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -2302,7 +2302,7 @@ _equalCreatePublicationStmt(const CreatePublicationStmt *a, { COMPARE_STRING_FIELD(pubname); COMPARE_NODE_FIELD(options); - COMPARE_NODE_FIELD(tables); + COMPARE_NODE_FIELD(pubobjects); COMPARE_SCALAR_FIELD(for_all_tables); return true; @@ -2314,9 +2314,9 @@ _equalAlterPublicationStmt(const AlterPublicationStmt *a, { COMPARE_STRING_FIELD(pubname); COMPARE_NODE_FIELD(options); - COMPARE_NODE_FIELD(tables); + COMPARE_NODE_FIELD(pubobjects); COMPARE_SCALAR_FIELD(for_all_tables); - COMPARE_SCALAR_FIELD(tableAction); + COMPARE_SCALAR_FIELD(action); return true; } @@ -3134,9 +3134,9 @@ _equalBitString(const BitString *a, const BitString *b) } static bool -_equalPublicationTable(const PublicationTable *a, const PublicationTable *b) +_equalPublicationObject(const PublicationObjSpec *a, const PublicationObjSpec *b) { - COMPARE_NODE_FIELD(relation); + COMPARE_NODE_FIELD(object); return true; } @@ -3894,8 +3894,8 @@ equal(const void *a, const void *b) case T_PartitionCmd: retval = _equalPartitionCmd(a, b); break; - case T_PublicationTable: - retval = _equalPublicationTable(a, b); + case T_PublicationObjSpec: + retval = _equalPublicationObject(a, b); break; default: diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e3068a374e..d3d7683511 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -256,6 +256,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); PartitionSpec *partspec; PartitionBoundSpec *partboundspec; RoleSpec *rolespec; + PublicationObjSpec *publicationobjectspec; struct SelectLimit *selectlimit; SetQuantifier setquantifier; struct GroupClause *groupclause; @@ -425,14 +426,13 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); transform_element_list transform_type_list TriggerTransitions TriggerReferencing vacuum_relation_list opt_vacuum_relation_list - drop_option_list publication_table_list + drop_option_list pub_obj_list %type <node> opt_routine_body %type <groupclause> group_clause %type <list> group_by_list %type <node> group_by_item empty_grouping_set rollup_clause cube_clause %type <node> grouping_sets_clause -%type <node> opt_publication_for_tables publication_for_tables publication_table %type <list> opt_fdw_options fdw_options %type <defelt> fdw_option @@ -554,6 +554,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <node> var_value zone_value %type <rolespec> auth_ident RoleSpec opt_granted_by +%type <publicationobjectspec> PublicationObjSpec %type <keyword> unreserved_keyword type_func_name_keyword %type <keyword> col_name_keyword reserved_keyword %type <keyword> bare_label_keyword @@ -9591,69 +9592,75 @@ AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec /***************************************************************************** * - * CREATE PUBLICATION name [ FOR TABLE ] [ WITH options ] + * CREATE PUBLICATION name [WITH options] + * + * CREATE PUBLICATION FOR ALL TABLES [WITH options] + * + * CREATE PUBLICATION FOR pub_obj [, pub_obj2] [WITH options] + * + * pub_obj is one of: + * + * TABLE table [, table2] + * ALL TABLES IN SCHEMA schema [, schema2] * *****************************************************************************/ CreatePublicationStmt: - CREATE PUBLICATION name opt_publication_for_tables opt_definition + CREATE PUBLICATION name opt_definition { CreatePublicationStmt *n = makeNode(CreatePublicationStmt); n->pubname = $3; - n->options = $5; - if ($4 != NULL) - { - /* FOR TABLE */ - if (IsA($4, List)) - n->tables = (List *)$4; - /* FOR ALL TABLES */ - else - n->for_all_tables = true; - } + n->options = $4; $$ = (Node *)n; } - ; - -opt_publication_for_tables: - publication_for_tables { $$ = $1; } - | /* EMPTY */ { $$ = NULL; } - ; - -publication_for_tables: - FOR TABLE publication_table_list + | CREATE PUBLICATION name FOR ALL TABLES opt_definition { - $$ = (Node *) $3; + CreatePublicationStmt *n = makeNode(CreatePublicationStmt); + n->pubname = $3; + n->options = $7; + n->for_all_tables = true; + $$ = (Node *)n; } - | FOR ALL TABLES + | CREATE PUBLICATION name FOR TABLE pub_obj_list opt_definition { - $$ = (Node *) makeInteger(true); + CreatePublicationStmt *n = makeNode(CreatePublicationStmt); + n->pubname = $3; + n->options = $7; + n->pubobjects = (List *)$6; + $$ = (Node *)n; } ; -publication_table_list: - publication_table - { $$ = list_make1($1); } - | publication_table_list ',' publication_table - { $$ = lappend($1, $3); } +/* FOR TABLE and FOR ALL TABLES IN SCHEMA specifications */ +PublicationObjSpec: relation_expr + { + PublicationObjSpec *n = makeNode(PublicationObjSpec); + n->object = (Node*)$1; + n->pubobjtype = PUBLICATIONOBJ_TABLE; + $$ = n; + } ; -publication_table: relation_expr - { - PublicationTable *n = makeNode(PublicationTable); - n->relation = $1; - $$ = (Node *) n; - } +pub_obj_list: PublicationObjSpec + { $$ = list_make1($1); } + | pub_obj_list ',' PublicationObjSpec + { $$ = lappend($1, $3); } ; /***************************************************************************** * * ALTER PUBLICATION name SET ( options ) * - * ALTER PUBLICATION name ADD TABLE table [, table2] + * ALTER PUBLICATION name ADD pub_obj [, pub_obj ...] + * + * ALTER PUBLICATION name DROP pub_obj [, pub_obj ...] + * + * ALTER PUBLICATION name SET pub_obj [, pub_obj ...] * - * ALTER PUBLICATION name DROP TABLE table [, table2] + * pub_obj is one of: * - * ALTER PUBLICATION name SET TABLE table [, table2] + * TABLE table_name [, table_name ...] + * ALL TABLES IN SCHEMA schema_name [, schema_name ...] * *****************************************************************************/ @@ -9665,28 +9672,28 @@ AlterPublicationStmt: n->options = $5; $$ = (Node *)n; } - | ALTER PUBLICATION name ADD_P TABLE publication_table_list + | ALTER PUBLICATION name ADD_P TABLE pub_obj_list { AlterPublicationStmt *n = makeNode(AlterPublicationStmt); n->pubname = $3; - n->tables = $6; - n->tableAction = DEFELEM_ADD; + n->pubobjects = $6; + n->action = DEFELEM_ADD; $$ = (Node *)n; } - | ALTER PUBLICATION name SET TABLE publication_table_list + | ALTER PUBLICATION name SET TABLE pub_obj_list { AlterPublicationStmt *n = makeNode(AlterPublicationStmt); n->pubname = $3; - n->tables = $6; - n->tableAction = DEFELEM_SET; + n->pubobjects = $6; + n->action = DEFELEM_SET; $$ = (Node *)n; } - | ALTER PUBLICATION name DROP TABLE publication_table_list + | ALTER PUBLICATION name DROP TABLE pub_obj_list { AlterPublicationStmt *n = makeNode(AlterPublicationStmt); n->pubname = $3; - n->tables = $6; - n->tableAction = DEFELEM_DROP; + n->pubobjects = $6; + n->action = DEFELEM_DROP; $$ = (Node *)n; } ; diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h index 561266aa3e..f332bad4d4 100644 --- a/src/include/catalog/pg_publication.h +++ b/src/include/catalog/pg_publication.h @@ -83,11 +83,6 @@ typedef struct Publication PublicationActions pubactions; } Publication; -typedef struct PublicationRelInfo -{ - Relation relation; -} PublicationRelInfo; - extern Publication *GetPublication(Oid pubid); extern Publication *GetPublicationByName(const char *pubname, bool missing_ok); extern List *GetRelationPublications(Oid relid); @@ -113,7 +108,7 @@ extern List *GetAllTablesPublications(void); extern List *GetAllTablesPublicationRelations(bool pubviaroot); extern bool is_publishable_relation(Relation rel); -extern ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *targetrel, +extern ObjectAddress publication_add_relation(Oid pubid, Relation targetrel, bool if_not_exists); extern Oid get_publication_oid(const char *pubname, bool missing_ok); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index b3ee4194d3..40aadb37d9 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -487,7 +487,7 @@ typedef enum NodeTag T_PartitionRangeDatum, T_PartitionCmd, T_VacuumRelation, - T_PublicationTable, + T_PublicationObjSpec, /* * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 45e4f2a16e..3e88965316 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -353,6 +353,26 @@ typedef struct RoleSpec int location; /* token location, or -1 if unknown */ } RoleSpec; +/* + * Publication object type + */ +typedef enum PublicationObjSpecType +{ + PUBLICATIONOBJ_TABLE, /* Table type */ + PUBLICATIONOBJ_REL_IN_SCHEMA, /* Relations in schema type */ + PUBLICATIONOBJ_UNKNOWN /* Unknown type */ +} PublicationObjSpecType; + +typedef struct PublicationObjSpec +{ + NodeTag type; + PublicationObjSpecType pubobjtype; /* type of this publication object */ + Node *object; /* publication object could be: + * RangeVar - table object + * String - tablename or schemaname */ + int location; /* token location, or -1 if unknown */ +} PublicationObjSpec; + /* * FuncCall - a function or aggregate invocation * @@ -3636,18 +3656,12 @@ typedef struct AlterTSConfigurationStmt bool missing_ok; /* for DROP - skip error if missing? */ } AlterTSConfigurationStmt; -typedef struct PublicationTable -{ - NodeTag type; - RangeVar *relation; /* relation to be published */ -} PublicationTable; - typedef struct CreatePublicationStmt { NodeTag type; char *pubname; /* Name of the publication */ List *options; /* List of DefElem nodes */ - List *tables; /* Optional list of tables to add */ + List *pubobjects; /* Optional list of publication objects */ bool for_all_tables; /* Special publication for all tables in db */ } CreatePublicationStmt; @@ -3659,10 +3673,11 @@ typedef struct AlterPublicationStmt /* parameters used for ALTER PUBLICATION ... WITH */ List *options; /* List of DefElem nodes */ - /* parameters used for ALTER PUBLICATION ... ADD/DROP TABLE */ - List *tables; /* List of tables to add/drop */ + /* ALTER PUBLICATION ... ADD/DROP TABLE/ALL TABLES IN SCHEMA parameters */ + List *pubobjects; /* Optional list of publication objects */ bool for_all_tables; /* Special publication for all tables in db */ - DefElemAction tableAction; /* What action to perform with the tables */ + DefElemAction action; /* What action to perform with the + * tables/schemas */ } AlterPublicationStmt; typedef struct CreateSubscriptionStmt diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 423780652f..8a1b97836e 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2045,8 +2045,9 @@ PsqlSettings Publication PublicationActions PublicationInfo +PublicationObjSpec +PublicationObjSpecType PublicationPartOpt -PublicationRelInfo PublicationTable PullFilter PullFilterOps
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index d6fddd6efe..2a2fe03c13 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -141,14 +141,14 @@ pg_relation_is_publishable(PG_FUNCTION_ARGS) * Insert new publication / relation mapping. */ ObjectAddress -publication_add_relation(Oid pubid, PublicationRelInfo *targetrel, +publication_add_relation(Oid pubid, Relation targetrel, bool if_not_exists) { Relation rel; HeapTuple tup; Datum values[Natts_pg_publication_rel]; bool nulls[Natts_pg_publication_rel]; - Oid relid = RelationGetRelid(targetrel->relation); + Oid relid = RelationGetRelid(targetrel); Oid prrelid; Publication *pub = GetPublication(pubid); ObjectAddress myself, @@ -172,10 +172,10 @@ publication_add_relation(Oid pubid, PublicationRelInfo *targetrel, ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("relation \"%s\" is already member of publication \"%s\"", - RelationGetRelationName(targetrel->relation), pub->name))); + RelationGetRelationName(targetrel), pub->name))); } - check_publication_add_relation(targetrel->relation); + check_publication_add_relation(targetrel); /* Form a tuple. */ memset(values, 0, sizeof(values)); @@ -209,7 +209,7 @@ publication_add_relation(Oid pubid, PublicationRelInfo *targetrel, table_close(rel, RowExclusiveLock); /* Invalidate relcache so that publication info is rebuilt. */ - CacheInvalidateRelcache(targetrel->relation); + CacheInvalidateRelcache(targetrel); return myself; } diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index 30929da1f5..4e4e02ba70 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -34,6 +34,7 @@ #include "commands/publicationcmds.h" #include "funcapi.h" #include "miscadmin.h" +#include "nodes/makefuncs.h" #include "utils/acl.h" #include "utils/array.h" #include "utils/builtins.h" @@ -138,6 +139,85 @@ parse_publication_options(ParseState *pstate, } } +/* + * Convert the PublicationObjSpecType list into schema oid list and rangevar + * list. + */ +static void +ObjectsInPublicationToOids(List *pubobjspec_list, ParseState *pstate, + List **rels, List **schemas) +{ + ListCell *cell; + PublicationObjSpec *pubobj; + PublicationObjSpecType prevobjtype = PUBLICATIONOBJ_UNKNOWN; + + if (!pubobjspec_list) + return; + + pubobj = (PublicationObjSpec *) linitial(pubobjspec_list); + if (pubobj->pubobjtype == PUBLICATIONOBJ_UNKNOWN) + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("FOR TABLE/FOR ALL TABLES IN SCHEMA should be specified before the table/schema name(s)"), + parser_errposition(pstate, pubobj->location)); + + foreach(cell, pubobjspec_list) + { + Node *node; + + pubobj = (PublicationObjSpec *) lfirst(cell); + node = (Node *) pubobj->object; + + if (pubobj->pubobjtype == PUBLICATIONOBJ_UNKNOWN) + pubobj->pubobjtype = prevobjtype; + else + prevobjtype = pubobj->pubobjtype; + + if (pubobj->pubobjtype == PUBLICATIONOBJ_TABLE) + { + if (IsA(node, RangeVar)) + *rels = lappend(*rels, (RangeVar *) node); + else if (IsA(node, String)) + { + RangeVar *rel = makeRangeVar(NULL, strVal(node), + pubobj->location); + *rels = lappend(*rels, rel); + } + } + else if (pubobj->pubobjtype == PUBLICATIONOBJ_REL_IN_SCHEMA) + { + Oid schemaid; + char *schemaname; + + if (!IsA(node, String)) + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid schema name at or near"), + parser_errposition(pstate, pubobj->location)); + + schemaname = strVal(node); + if (strcmp(schemaname, "CURRENT_SCHEMA") == 0) + { + List *search_path; + + search_path = fetch_search_path(false); + if (search_path == NIL) /* nothing valid in search_path? */ + ereport(ERROR, + errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("no schema has been selected for CURRENT_SCHEMA")); + + schemaid = linitial_oid(search_path); + list_free(search_path); + } + else + schemaid = get_namespace_oid(schemaname, false); + + /* Filter out duplicates if user specifies "sch1, sch1" */ + *schemas = list_append_unique_oid(*schemas, schemaid); + } + } +} + /* * Create new publication. */ @@ -155,6 +235,8 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) bool publish_via_partition_root_given; bool publish_via_partition_root; AclResult aclresult; + List *relations = NIL; + List *schemaidlist = NIL; /* must have CREATE privilege on database */ aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CREATE); @@ -224,13 +306,15 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) /* Make the changes visible. */ CommandCounterIncrement(); - if (stmt->tables) + ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations, + &schemaidlist); + if (relations != NIL) { List *rels; - Assert(list_length(stmt->tables) > 0); + Assert(list_length(relations) > 0); - rels = OpenTableList(stmt->tables); + rels = OpenTableList(relations); PublicationAddTables(puboid, rels, true, NULL); CloseTableList(rels); } @@ -360,7 +444,7 @@ AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt, */ static void AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel, - HeapTuple tup) + HeapTuple tup, List *tables, List *schemaidlist) { List *rels = NIL; Form_pg_publication pubform = (Form_pg_publication) GETSTRUCT(tup); @@ -374,13 +458,13 @@ AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel, NameStr(pubform->pubname)), errdetail("Tables cannot be added to or dropped from FOR ALL TABLES publications."))); - Assert(list_length(stmt->tables) > 0); + Assert(list_length(tables) > 0); - rels = OpenTableList(stmt->tables); + rels = OpenTableList(tables); - if (stmt->tableAction == DEFELEM_ADD) + if (stmt->action == DEFELEM_ADD) PublicationAddTables(pubid, rels, false, stmt); - else if (stmt->tableAction == DEFELEM_DROP) + else if (stmt->action == DEFELEM_DROP) PublicationDropTables(pubid, rels, false); else /* DEFELEM_SET */ { @@ -398,10 +482,9 @@ AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel, foreach(newlc, rels) { - PublicationRelInfo *newpubrel; + Relation newrel = (Relation) lfirst(newlc); - newpubrel = (PublicationRelInfo *) lfirst(newlc); - if (RelationGetRelid(newpubrel->relation) == oldrelid) + if (RelationGetRelid(newrel) == oldrelid) { found = true; break; @@ -410,16 +493,10 @@ AlterPublicationTables(AlterPublicationStmt *stmt, Relation rel, /* Not yet in the list, open it and add to the list */ if (!found) { - Relation oldrel; - PublicationRelInfo *pubrel; - - /* Wrap relation into PublicationRelInfo */ - oldrel = table_open(oldrelid, ShareUpdateExclusiveLock); + Relation oldrel = table_open(oldrelid, + ShareUpdateExclusiveLock); - pubrel = palloc(sizeof(PublicationRelInfo)); - pubrel->relation = oldrel; - - delrels = lappend(delrels, pubrel); + delrels = lappend(delrels, oldrel); } } @@ -450,6 +527,8 @@ AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt) Relation rel; HeapTuple tup; Form_pg_publication pubform; + List *relations = NIL; + List *schemaidlist = NIL; rel = table_open(PublicationRelationId, RowExclusiveLock); @@ -469,10 +548,16 @@ AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_PUBLICATION, stmt->pubname); + ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations, + &schemaidlist); + if (stmt->options) AlterPublicationOptions(pstate, stmt, rel, tup); else - AlterPublicationTables(stmt, rel, tup); + { + if (relations) + AlterPublicationTables(stmt, rel, tup, relations, schemaidlist); + } /* Cleanup. */ heap_freetuple(tup); @@ -540,7 +625,7 @@ RemovePublicationById(Oid pubid) /* * Open relations specified by a PublicationTable list. - * In the returned list of PublicationRelInfo, tables are locked + * In the returned list of Relation, tables are locked * in ShareUpdateExclusiveLock mode in order to add them to a publication. */ static List * @@ -555,16 +640,15 @@ OpenTableList(List *tables) */ foreach(lc, tables) { - PublicationTable *t = lfirst_node(PublicationTable, lc); - bool recurse = t->relation->inh; + RangeVar *rv = lfirst_node(RangeVar, lc); + bool recurse = rv->inh; Relation rel; Oid myrelid; - PublicationRelInfo *pub_rel; /* Allow query cancel in case this takes a long time */ CHECK_FOR_INTERRUPTS(); - rel = table_openrv(t->relation, ShareUpdateExclusiveLock); + rel = table_openrv(rv, ShareUpdateExclusiveLock); myrelid = RelationGetRelid(rel); /* @@ -580,9 +664,7 @@ OpenTableList(List *tables) continue; } - pub_rel = palloc(sizeof(PublicationRelInfo)); - pub_rel->relation = rel; - rels = lappend(rels, pub_rel); + rels = lappend(rels, rel); relids = lappend_oid(relids, myrelid); /* @@ -615,9 +697,7 @@ OpenTableList(List *tables) /* find_all_inheritors already got lock */ rel = table_open(childrelid, NoLock); - pub_rel = palloc(sizeof(PublicationRelInfo)); - pub_rel->relation = rel; - rels = lappend(rels, pub_rel); + rels = lappend(rels, rel); relids = lappend_oid(relids, childrelid); } } @@ -638,10 +718,9 @@ CloseTableList(List *rels) foreach(lc, rels) { - PublicationRelInfo *pub_rel; + Relation rel = (Relation) lfirst(lc); - pub_rel = (PublicationRelInfo *) lfirst(lc); - table_close(pub_rel->relation, NoLock); + table_close(rel, NoLock); } } @@ -658,8 +737,7 @@ PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, foreach(lc, rels) { - PublicationRelInfo *pub_rel = (PublicationRelInfo *) lfirst(lc); - Relation rel = pub_rel->relation; + Relation rel = (Relation) lfirst(lc); ObjectAddress obj; /* Must be owner of the table or superuser. */ @@ -667,7 +745,7 @@ PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(rel->rd_rel->relkind), RelationGetRelationName(rel)); - obj = publication_add_relation(pubid, pub_rel, if_not_exists); + obj = publication_add_relation(pubid, rel, if_not_exists); if (stmt) { EventTriggerCollectSimpleCommand(obj, InvalidObjectAddress, @@ -691,8 +769,7 @@ PublicationDropTables(Oid pubid, List *rels, bool missing_ok) foreach(lc, rels) { - PublicationRelInfo *pubrel = (PublicationRelInfo *) lfirst(lc); - Relation rel = pubrel->relation; + Relation rel = (Relation) lfirst(lc); Oid relid = RelationGetRelid(rel); prid = GetSysCacheOid2(PUBLICATIONRELMAP, Anum_pg_publication_rel_oid, diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 228387eaee..ade93023b8 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -4817,7 +4817,7 @@ _copyCreatePublicationStmt(const CreatePublicationStmt *from) COPY_STRING_FIELD(pubname); COPY_NODE_FIELD(options); - COPY_NODE_FIELD(tables); + COPY_NODE_FIELD(pubobjects); COPY_SCALAR_FIELD(for_all_tables); return newnode; @@ -4830,9 +4830,9 @@ _copyAlterPublicationStmt(const AlterPublicationStmt *from) COPY_STRING_FIELD(pubname); COPY_NODE_FIELD(options); - COPY_NODE_FIELD(tables); + COPY_NODE_FIELD(pubobjects); COPY_SCALAR_FIELD(for_all_tables); - COPY_SCALAR_FIELD(tableAction); + COPY_SCALAR_FIELD(action); return newnode; } @@ -4958,12 +4958,14 @@ _copyForeignKeyCacheInfo(const ForeignKeyCacheInfo *from) return newnode; } -static PublicationTable * -_copyPublicationTable(const PublicationTable *from) +static PublicationObjSpec * +_copyPublicationObject(const PublicationObjSpec *from) { - PublicationTable *newnode = makeNode(PublicationTable); + PublicationObjSpec *newnode = makeNode(PublicationObjSpec); - COPY_NODE_FIELD(relation); + COPY_SCALAR_FIELD(pubobjtype); + COPY_NODE_FIELD(object); + COPY_LOCATION_FIELD(location); return newnode; } @@ -5887,8 +5889,8 @@ copyObjectImpl(const void *from) case T_PartitionCmd: retval = _copyPartitionCmd(from); break; - case T_PublicationTable: - retval = _copyPublicationTable(from); + case T_PublicationObjSpec: + retval = _copyPublicationObject(from); break; /* diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 800f588b5c..d384af2db7 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -2302,7 +2302,7 @@ _equalCreatePublicationStmt(const CreatePublicationStmt *a, { COMPARE_STRING_FIELD(pubname); COMPARE_NODE_FIELD(options); - COMPARE_NODE_FIELD(tables); + COMPARE_NODE_FIELD(pubobjects); COMPARE_SCALAR_FIELD(for_all_tables); return true; @@ -2314,9 +2314,9 @@ _equalAlterPublicationStmt(const AlterPublicationStmt *a, { COMPARE_STRING_FIELD(pubname); COMPARE_NODE_FIELD(options); - COMPARE_NODE_FIELD(tables); + COMPARE_NODE_FIELD(pubobjects); COMPARE_SCALAR_FIELD(for_all_tables); - COMPARE_SCALAR_FIELD(tableAction); + COMPARE_SCALAR_FIELD(action); return true; } @@ -3134,12 +3134,12 @@ _equalBitString(const BitString *a, const BitString *b) } static bool -_equalPublicationTable(const PublicationTable *a, const PublicationTable *b) +_equalPublicationObject(const PublicationObjSpec *a, const PublicationObjSpec *b) { - COMPARE_NODE_FIELD(relation); + COMPARE_NODE_FIELD(object); return true; -} +} /* * equal @@ -3894,8 +3894,8 @@ equal(const void *a, const void *b) case T_PartitionCmd: retval = _equalPartitionCmd(a, b); break; - case T_PublicationTable: - retval = _equalPublicationTable(a, b); + case T_PublicationObjSpec: + retval = _equalPublicationObject(a, b); break; default: diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e3068a374e..f7d7cab596 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -195,6 +195,9 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, static List *mergeTableFuncParameters(List *func_args, List *columns); static TypeName *TableFuncTypeName(List *columns); static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner); +static RangeVar *makeRangeVarFromQualifiedName(char *name, List *rels, + int location, + core_yyscan_t yyscanner); static void SplitColQualList(List *qualList, List **constraintList, CollateClause **collClause, core_yyscan_t yyscanner); @@ -256,6 +259,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); PartitionSpec *partspec; PartitionBoundSpec *partboundspec; RoleSpec *rolespec; + PublicationObjSpec *publicationobjectspec; struct SelectLimit *selectlimit; SetQuantifier setquantifier; struct GroupClause *groupclause; @@ -425,14 +429,13 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); transform_element_list transform_type_list TriggerTransitions TriggerReferencing vacuum_relation_list opt_vacuum_relation_list - drop_option_list publication_table_list + drop_option_list pub_obj_list %type <node> opt_routine_body %type <groupclause> group_clause %type <list> group_by_list %type <node> group_by_item empty_grouping_set rollup_clause cube_clause %type <node> grouping_sets_clause -%type <node> opt_publication_for_tables publication_for_tables publication_table %type <list> opt_fdw_options fdw_options %type <defelt> fdw_option @@ -517,6 +520,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <node> table_ref %type <jexpr> joined_table %type <range> relation_expr +%type <range> extended_relation_expr %type <range> relation_expr_opt_alias %type <node> tablesample_clause opt_repeatable_clause %type <target> target_el set_target insert_column_item @@ -554,6 +558,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <node> var_value zone_value %type <rolespec> auth_ident RoleSpec opt_granted_by +%type <publicationobjectspec> PublicationObjSpec +%type <publicationobjectspec> pubobj_expr +%type <node> pubobj_name %type <keyword> unreserved_keyword type_func_name_keyword %type <keyword> col_name_keyword reserved_keyword %type <keyword> bare_label_keyword @@ -9591,69 +9598,117 @@ AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec /***************************************************************************** * - * CREATE PUBLICATION name [ FOR TABLE ] [ WITH options ] + * CREATE PUBLICATION name [WITH options] + * + * CREATE PUBLICATION FOR ALL TABLES [WITH options] + * + * CREATE PUBLICATION FOR pub_obj [, pub_obj2] [WITH options] + * + * pub_obj is one of: + * + * TABLE table [, table2] + * ALL TABLES IN SCHEMA schema [, schema2] * *****************************************************************************/ CreatePublicationStmt: - CREATE PUBLICATION name opt_publication_for_tables opt_definition + CREATE PUBLICATION name opt_definition { CreatePublicationStmt *n = makeNode(CreatePublicationStmt); n->pubname = $3; - n->options = $5; - if ($4 != NULL) - { - /* FOR TABLE */ - if (IsA($4, List)) - n->tables = (List *)$4; - /* FOR ALL TABLES */ - else - n->for_all_tables = true; - } + n->options = $4; + $$ = (Node *)n; + } + | CREATE PUBLICATION name FOR ALL TABLES opt_definition + { + CreatePublicationStmt *n = makeNode(CreatePublicationStmt); + n->pubname = $3; + n->options = $7; + n->for_all_tables = true; + $$ = (Node *)n; + } + | CREATE PUBLICATION name FOR pub_obj_list opt_definition + { + CreatePublicationStmt *n = makeNode(CreatePublicationStmt); + n->pubname = $3; + n->options = $6; + n->pubobjects = (List *)$5; $$ = (Node *)n; } ; -opt_publication_for_tables: - publication_for_tables { $$ = $1; } - | /* EMPTY */ { $$ = NULL; } +pubobj_expr: + pubobj_name + { + /* inheritance query, implicitly */ + $$ = makeNode(PublicationObjSpec); + $$->object = $1; + } + | extended_relation_expr + { + $$ = makeNode(PublicationObjSpec); + $$->object = $1; + } + | CURRENT_SCHEMA + { + $$ = makeNode(PublicationObjSpec); + $$->object = makeString("CURRENT_SCHEMA"); + } ; -publication_for_tables: - FOR TABLE publication_table_list +/* This can be either a schema or relation name. */ +pubobj_name: + ColId { - $$ = (Node *) $3; + $$ = (Node *) makeString($1); } - | FOR ALL TABLES + | ColId indirection { - $$ = (Node *) makeInteger(true); + $$ = (Node *) makeRangeVarFromQualifiedName($1, $2, @1, yyscanner); } ; -publication_table_list: - publication_table - { $$ = list_make1($1); } - | publication_table_list ',' publication_table - { $$ = lappend($1, $3); } +/* FOR TABLE and FOR ALL TABLES IN SCHEMA specifications */ +PublicationObjSpec: TABLE pubobj_expr + { + $$ = $2; + $$->pubobjtype = PUBLICATIONOBJ_TABLE; + $$->location = @1; + } + | ALL TABLES IN_P SCHEMA pubobj_expr + { + $$ = $5; + $$->pubobjtype = PUBLICATIONOBJ_REL_IN_SCHEMA; + $$->location = @1; + } + | pubobj_expr + { + $$ = $1; + $$->pubobjtype = PUBLICATIONOBJ_UNKNOWN; + $$->location = @1; + } ; -publication_table: relation_expr - { - PublicationTable *n = makeNode(PublicationTable); - n->relation = $1; - $$ = (Node *) n; - } +pub_obj_list: PublicationObjSpec + { $$ = list_make1($1); } + | pub_obj_list ',' PublicationObjSpec + { $$ = lappend($1, $3); } ; /***************************************************************************** * * ALTER PUBLICATION name SET ( options ) * - * ALTER PUBLICATION name ADD TABLE table [, table2] + * ALTER PUBLICATION name ADD pub_obj [, pub_obj ...] * - * ALTER PUBLICATION name DROP TABLE table [, table2] + * ALTER PUBLICATION name DROP pub_obj [, pub_obj ...] * - * ALTER PUBLICATION name SET TABLE table [, table2] + * ALTER PUBLICATION name SET pub_obj [, pub_obj ...] + * + * pub_obj is one of: + * + * TABLE table_name [, table_name ...] + * ALL TABLES IN SCHEMA schema_name [, schema_name ...] * *****************************************************************************/ @@ -9665,28 +9720,28 @@ AlterPublicationStmt: n->options = $5; $$ = (Node *)n; } - | ALTER PUBLICATION name ADD_P TABLE publication_table_list + | ALTER PUBLICATION name ADD_P pub_obj_list { AlterPublicationStmt *n = makeNode(AlterPublicationStmt); n->pubname = $3; - n->tables = $6; - n->tableAction = DEFELEM_ADD; + n->pubobjects = $5; + n->action = DEFELEM_ADD; $$ = (Node *)n; } - | ALTER PUBLICATION name SET TABLE publication_table_list + | ALTER PUBLICATION name SET pub_obj_list { AlterPublicationStmt *n = makeNode(AlterPublicationStmt); n->pubname = $3; - n->tables = $6; - n->tableAction = DEFELEM_SET; + n->pubobjects = $5; + n->action = DEFELEM_SET; $$ = (Node *)n; } - | ALTER PUBLICATION name DROP TABLE publication_table_list + | ALTER PUBLICATION name DROP pub_obj_list { AlterPublicationStmt *n = makeNode(AlterPublicationStmt); n->pubname = $3; - n->tables = $6; - n->tableAction = DEFELEM_DROP; + n->pubobjects = $5; + n->action = DEFELEM_DROP; $$ = (Node *)n; } ; @@ -12430,7 +12485,14 @@ relation_expr: $$->inh = true; $$->alias = NULL; } - | qualified_name '*' + | extended_relation_expr + { + $$ = $1; + } + ; + +extended_relation_expr: + qualified_name '*' { /* inheritance query, explicitly */ $$ = $1; @@ -12453,7 +12515,6 @@ relation_expr: } ; - relation_expr_list: relation_expr { $$ = list_make1($1); } | relation_expr_list ',' relation_expr { $$ = lappend($1, $3); } @@ -15104,28 +15165,7 @@ qualified_name: } | ColId indirection { - check_qualified_name($2, yyscanner); - $$ = makeRangeVar(NULL, NULL, @1); - switch (list_length($2)) - { - case 1: - $$->catalogname = NULL; - $$->schemaname = $1; - $$->relname = strVal(linitial($2)); - break; - case 2: - $$->catalogname = $1; - $$->schemaname = strVal(linitial($2)); - $$->relname = strVal(lsecond($2)); - break; - default: - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("improper qualified name (too many dotted names): %s", - NameListToString(lcons(makeString($1), $2))), - parser_errposition(@1))); - break; - } + $$ = makeRangeVarFromQualifiedName($1, $2, @1, yyscanner); } ; @@ -17045,6 +17085,41 @@ TableFuncTypeName(List *columns) return result; } +/* + * Convert a relation_name with name and namelist to a RangeVar using + * makeRangeVar. + */ +static RangeVar * +makeRangeVarFromQualifiedName(char *name, List *namelist, int location, + core_yyscan_t yyscanner) +{ + RangeVar *r = makeRangeVar(NULL, NULL, location); + + check_qualified_name(namelist, yyscanner); + switch (list_length(namelist)) + { + case 1: + r->catalogname = NULL; + r->schemaname = name; + r->relname = strVal(linitial(namelist)); + break; + case 2: + r->catalogname = name; + r->schemaname = strVal(linitial(namelist)); + r->relname = strVal(lsecond(namelist)); + break; + default: + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("improper qualified name (too many dotted names): %s", + NameListToString(lcons(makeString(name), namelist))), + parser_errposition(location)); + break; + } + + return r; +} + /* * Convert a list of (dotted) names to a RangeVar (like * makeRangeVarFromNameList, but with position support). The diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h index 561266aa3e..f332bad4d4 100644 --- a/src/include/catalog/pg_publication.h +++ b/src/include/catalog/pg_publication.h @@ -83,11 +83,6 @@ typedef struct Publication PublicationActions pubactions; } Publication; -typedef struct PublicationRelInfo -{ - Relation relation; -} PublicationRelInfo; - extern Publication *GetPublication(Oid pubid); extern Publication *GetPublicationByName(const char *pubname, bool missing_ok); extern List *GetRelationPublications(Oid relid); @@ -113,7 +108,7 @@ extern List *GetAllTablesPublications(void); extern List *GetAllTablesPublicationRelations(bool pubviaroot); extern bool is_publishable_relation(Relation rel); -extern ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *targetrel, +extern ObjectAddress publication_add_relation(Oid pubid, Relation targetrel, bool if_not_exists); extern Oid get_publication_oid(const char *pubname, bool missing_ok); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index b3ee4194d3..40aadb37d9 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -487,7 +487,7 @@ typedef enum NodeTag T_PartitionRangeDatum, T_PartitionCmd, T_VacuumRelation, - T_PublicationTable, + T_PublicationObjSpec, /* * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 45e4f2a16e..6f1239017e 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -353,6 +353,26 @@ typedef struct RoleSpec int location; /* token location, or -1 if unknown */ } RoleSpec; +/* + * Publication object type + */ +typedef enum PublicationObjSpecType +{ + PUBLICATIONOBJ_TABLE, /* Table type */ + PUBLICATIONOBJ_REL_IN_SCHEMA, /* Relations in schema type */ + PUBLICATIONOBJ_UNKNOWN /* Unknown type */ +} PublicationObjSpecType; + +typedef struct PublicationObjSpec +{ + NodeTag type; + PublicationObjSpecType pubobjtype; /* type of this publication object */ + void *object; /* publication object could be: + * RangeVar - table object + * String - tablename or schemaname */ + int location; /* token location, or -1 if unknown */ +} PublicationObjSpec; + /* * FuncCall - a function or aggregate invocation * @@ -3636,18 +3656,12 @@ typedef struct AlterTSConfigurationStmt bool missing_ok; /* for DROP - skip error if missing? */ } AlterTSConfigurationStmt; -typedef struct PublicationTable -{ - NodeTag type; - RangeVar *relation; /* relation to be published */ -} PublicationTable; - typedef struct CreatePublicationStmt { NodeTag type; char *pubname; /* Name of the publication */ List *options; /* List of DefElem nodes */ - List *tables; /* Optional list of tables to add */ + List *pubobjects; /* Optional list of publication objects */ bool for_all_tables; /* Special publication for all tables in db */ } CreatePublicationStmt; @@ -3659,10 +3673,11 @@ typedef struct AlterPublicationStmt /* parameters used for ALTER PUBLICATION ... WITH */ List *options; /* List of DefElem nodes */ - /* parameters used for ALTER PUBLICATION ... ADD/DROP TABLE */ - List *tables; /* List of tables to add/drop */ + /* ALTER PUBLICATION ... ADD/DROP TABLE/ALL TABLES IN SCHEMA parameters */ + List *pubobjects; /* Optional list of publication objects */ bool for_all_tables; /* Special publication for all tables in db */ - DefElemAction tableAction; /* What action to perform with the tables */ + DefElemAction action; /* What action to perform with the + * tables/schemas */ } AlterPublicationStmt; typedef struct CreateSubscriptionStmt diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 423780652f..8a1b97836e 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2045,8 +2045,9 @@ PsqlSettings Publication PublicationActions PublicationInfo +PublicationObjSpec +PublicationObjSpecType PublicationPartOpt -PublicationRelInfo PublicationTable PullFilter PullFilterOps