v41-0002-Client-side-changes-to-support-FOR-ALL-TABLES-IN.patch
application/octet-stream
Filename: v41-0002-Client-side-changes-to-support-FOR-ALL-TABLES-IN.patch
Type: application/octet-stream
Part: 3
Patch
Format: format-patch
Series: patch v41-0002
Subject: Client side changes to support "FOR ALL TABLES IN SCHEMA" publication.
| File | + | − |
|---|---|---|
| src/bin/pg_dump/common.c | 4 | 1 |
| src/bin/pg_dump/pg_backup_archiver.c | 2 | 1 |
| src/bin/pg_dump/pg_dump.c | 138 | 6 |
| src/bin/pg_dump/pg_dump.h | 14 | 0 |
| src/bin/pg_dump/pg_dump_sort.c | 7 | 0 |
| src/bin/psql/describe.c | 159 | 39 |
| src/bin/psql/tab-complete.c | 27 | 7 |
| src/tools/pgindent/typedefs.list | 1 | 0 |
From 5470d932e083e6c6bc14c954e75d84b64340964e Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sun, 12 Sep 2021 20:32:28 +0530
Subject: [PATCH v40 2/5] Client side changes to support "FOR ALL TABLES IN
SCHEMA" publication.
Client side changes to support "FOR ALL TABLES IN SCHEMA" publication.
Author: Vignesh C
Reviewed-by: Amit Kapila, Hou Zhijie, Greg Nancarrow
Tested-by: Tang Haiying
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ%40mail.gmail.com
---
src/bin/pg_dump/common.c | 5 +-
src/bin/pg_dump/pg_backup_archiver.c | 3 +-
src/bin/pg_dump/pg_dump.c | 144 ++++++++++++++++++-
src/bin/pg_dump/pg_dump.h | 14 ++
src/bin/pg_dump/pg_dump_sort.c | 7 +
src/bin/psql/describe.c | 198 +++++++++++++++++++++------
src/bin/psql/tab-complete.c | 34 ++++-
src/tools/pgindent/typedefs.list | 1 +
8 files changed, 352 insertions(+), 54 deletions(-)
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 1f24e79665..8691efe04b 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -254,9 +254,12 @@ getSchemaData(Archive *fout, int *numTablesPtr)
pubinfoindex = buildIndexArray(pubinfo, numPublications,
sizeof(PublicationInfo));
- pg_log_info("reading publication membership");
+ pg_log_info("reading publication membership of tables");
getPublicationTables(fout, tblinfo, numTables);
+ pg_log_info("reading publication membership of schemas");
+ getPublicationNamespaces(fout, nspinfo, numNamespaces);
+
pg_log_info("reading subscriptions");
getSubscriptions(fout);
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index ee06dc6822..6d690ee49c 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -2788,7 +2788,8 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH)
*/
if (ropt->no_publications &&
(strcmp(te->desc, "PUBLICATION") == 0 ||
- strcmp(te->desc, "PUBLICATION TABLE") == 0))
+ strcmp(te->desc, "PUBLICATION TABLE") == 0 ||
+ strcmp(te->desc, "PUBLICATION TABLES IN SCHEMA") == 0))
return 0;
/* If it's a security label, maybe ignore it */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index a485fb2d07..945cbcbd79 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1875,14 +1875,15 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
}
/*
- * selectDumpablePublicationTable: policy-setting subroutine
- * Mark a publication table as to be dumped or not
+ * selectDumpablePublicationObject: policy-setting subroutine
+ * Mark a publication object as to be dumped or not
*
- * Publication tables have schemas, but those are ignored in decision making,
- * because publications are only dumped when we are dumping everything.
+ * A publication can have schemas and tables which have schemas, but those are
+ * ignored in decision making, because publications are only dumped when we are
+ * dumping everything.
*/
static void
-selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
+selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
{
if (checkExtensionMembership(dobj, fout))
return; /* extension membership overrides all else */
@@ -4126,6 +4127,94 @@ dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
free(qpubname);
}
+/*
+ * getPublicationNamespaces
+ * get information about publication membership for dumpable schemas.
+ */
+void
+getPublicationNamespaces(Archive *fout, NamespaceInfo nspinfo[],
+ int numSchemas)
+{
+ PQExpBuffer query;
+ PGresult *res;
+ PublicationSchemaInfo *pubsinfo;
+ DumpOptions *dopt = fout->dopt;
+ int i_tableoid;
+ int i_oid;
+ int i_pnpubid;
+ int i_pnnspid;
+ int i,
+ j,
+ ntups;
+
+ if (dopt->no_publications || fout->remoteVersion < 150000)
+ return;
+
+ query = createPQExpBuffer();
+
+ /* Collect all publication membership info. */
+ appendPQExpBufferStr(query,
+ "SELECT tableoid, oid, pnpubid, pnnspid "
+ "FROM pg_catalog.pg_publication_namespace");
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_pnpubid = PQfnumber(res, "pnpubid");
+ i_pnnspid = PQfnumber(res, "pnnspid");
+
+ /* this allocation may be more than we need */
+ pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
+ j = 0;
+
+ for (i = 0; i < ntups; i++)
+ {
+ Oid pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
+ Oid pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
+ PublicationInfo *pubinfo;
+ NamespaceInfo *nspinfo;
+
+ /*
+ * Ignore any entries for which we aren't interested in either the
+ * publication or the rel.
+ */
+ pubinfo = findPublicationByOid(pnpubid);
+ if (pubinfo == NULL)
+ continue;
+ nspinfo = findNamespaceByOid(pnnspid);
+ if (nspinfo == NULL)
+ continue;
+
+ /*
+ * We always dump publication namespaces unless the corresponding
+ * namespace is excluded from the dump.
+ */
+ if (nspinfo->dobj.dump == DUMP_COMPONENT_NONE)
+ continue;
+
+ /* OK, make a DumpableObject for this relationship */
+ pubsinfo[j].dobj.objType = DO_PUBLICATION_REL_IN_SCHEMA;
+ pubsinfo[j].dobj.catId.tableoid =
+ atooid(PQgetvalue(res, i, i_tableoid));
+ pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&pubsinfo[j].dobj);
+ pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
+ pubsinfo[j].dobj.name = nspinfo->dobj.name;
+ pubsinfo[j].publication = pubinfo;
+ pubsinfo[j].pubschema = nspinfo;
+
+ /* Decide whether we want to dump it */
+ selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
+
+ j++;
+ }
+
+ PQclear(res);
+ destroyPQExpBuffer(query);
+}
+
/*
* getPublicationTables
* get information about publication membership for dumpable tables.
@@ -4204,7 +4293,7 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
pubrinfo[j].pubtable = tbinfo;
/* Decide whether we want to dump it */
- selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
+ selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
j++;
}
@@ -4213,6 +4302,44 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
destroyPQExpBuffer(query);
}
+/*
+ * dumpPublicationNamespace
+ * dump the definition of the given publication schema mapping.
+ */
+static void
+dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
+{
+ NamespaceInfo *schemainfo = pubsinfo->pubschema;
+ PublicationInfo *pubinfo = pubsinfo->publication;
+ PQExpBuffer query;
+ char *tag;
+
+ if (!(pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
+ return;
+
+ tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
+
+ query = createPQExpBuffer();
+
+ appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
+ appendPQExpBuffer(query, "ADD ALL TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
+
+ /*
+ * There is no point in creating drop query as the drop is done by schema
+ * drop.
+ */
+ ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
+ ARCHIVE_OPTS(.tag = tag,
+ .namespace = schemainfo->dobj.name,
+ .owner = pubinfo->rolname,
+ .description = "PUBLICATION TABLES IN SCHEMA",
+ .section = SECTION_POST_DATA,
+ .createStmt = query->data));
+
+ free(tag);
+ destroyPQExpBuffer(query);
+}
+
/*
* dumpPublicationTable
* dump the definition of the given publication table mapping
@@ -10485,6 +10612,10 @@ dumpDumpableObject(Archive *fout, const DumpableObject *dobj)
case DO_PUBLICATION_REL:
dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
break;
+ case DO_PUBLICATION_REL_IN_SCHEMA:
+ dumpPublicationNamespace(fout,
+ (const PublicationSchemaInfo *) dobj);
+ break;
case DO_SUBSCRIPTION:
dumpSubscription(fout, (const SubscriptionInfo *) dobj);
break;
@@ -18717,6 +18848,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
case DO_POLICY:
case DO_PUBLICATION:
case DO_PUBLICATION_REL:
+ case DO_PUBLICATION_REL_IN_SCHEMA:
case DO_SUBSCRIPTION:
/* Post-data objects: must come after the post-data boundary */
addObjectDependency(dobj, postDataBound->dumpId);
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 29af845ece..45b8e85b84 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -81,6 +81,7 @@ typedef enum
DO_POLICY,
DO_PUBLICATION,
DO_PUBLICATION_REL,
+ DO_PUBLICATION_REL_IN_SCHEMA,
DO_SUBSCRIPTION
} DumpableObjectType;
@@ -631,6 +632,17 @@ typedef struct _PublicationRelInfo
TableInfo *pubtable;
} PublicationRelInfo;
+/*
+ * The PublicationSchemaInfo struct is used to represent publication schema
+ * mapping.
+ */
+typedef struct _PublicationSchemaInfo
+{
+ DumpableObject dobj;
+ PublicationInfo *publication;
+ NamespaceInfo *pubschema;
+} PublicationSchemaInfo;
+
/*
* The SubscriptionInfo struct is used to represent subscription.
*/
@@ -737,6 +749,8 @@ extern PublicationInfo *getPublications(Archive *fout,
int *numPublications);
extern void getPublicationTables(Archive *fout, TableInfo tblinfo[],
int numTables);
+extern void getPublicationNamespaces(Archive *fout, NamespaceInfo nspinfo[],
+ int numSchemas);
extern void getSubscriptions(Archive *fout);
#endif /* PG_DUMP_H */
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 46461fb6a1..9901d9e0ba 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -82,6 +82,7 @@ enum dbObjectTypePriorities
PRIO_POLICY,
PRIO_PUBLICATION,
PRIO_PUBLICATION_REL,
+ PRIO_PUBLICATION_REL_IN_SCHEMA,
PRIO_SUBSCRIPTION,
PRIO_DEFAULT_ACL, /* done in ACL pass */
PRIO_EVENT_TRIGGER, /* must be next to last! */
@@ -135,6 +136,7 @@ static const int dbObjectTypePriority[] =
PRIO_POLICY, /* DO_POLICY */
PRIO_PUBLICATION, /* DO_PUBLICATION */
PRIO_PUBLICATION_REL, /* DO_PUBLICATION_REL */
+ PRIO_PUBLICATION_REL_IN_SCHEMA, /* DO_PUBLICATION_REL_IN_SCHEMA */
PRIO_SUBSCRIPTION /* DO_SUBSCRIPTION */
};
@@ -1477,6 +1479,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
"PUBLICATION TABLE (ID %d OID %u)",
obj->dumpId, obj->catId.oid);
return;
+ case DO_PUBLICATION_REL_IN_SCHEMA:
+ snprintf(buf, bufsize,
+ "PUBLICATION TABLES IN SCHEMA (ID %d OID %u)",
+ obj->dumpId, obj->catId.oid);
+ return;
case DO_SUBSCRIPTION:
snprintf(buf, bufsize,
"SUBSCRIPTION (ID %d OID %u)",
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index a33d77c0ef..c93478070d 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3147,17 +3147,40 @@ describeOneTableDetails(const char *schemaname,
/* print any publications */
if (pset.sversion >= 100000)
{
- printfPQExpBuffer(&buf,
- "SELECT pubname\n"
- "FROM pg_catalog.pg_publication p\n"
- "JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
- "WHERE pr.prrelid = '%s'\n"
- "UNION ALL\n"
- "SELECT pubname\n"
- "FROM pg_catalog.pg_publication p\n"
- "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
- "ORDER BY 1;",
- oid, oid);
+ if (pset.sversion >= 150000)
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT pubname\n"
+ "FROM pg_catalog.pg_publication p\n"
+ " JOIN pg_catalog.pg_publication_namespace pn ON p.oid = pn.pnpubid\n"
+ " JOIN pg_catalog.pg_class pc ON pc.relnamespace = pn.pnnspid\n"
+ "WHERE pc.oid ='%s' and pg_catalog.pg_relation_is_publishable('%s')\n"
+ "UNION\n"
+ "SELECT pubname\n"
+ "FROM pg_catalog.pg_publication p\n"
+ " JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
+ "WHERE pr.prrelid = '%s'\n"
+ "UNION\n"
+ "SELECT pubname\n"
+ "FROM pg_catalog.pg_publication p\n"
+ "WHERE puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
+ "ORDER BY 1;",
+ oid, oid, oid, oid);
+ }
+ else
+ {
+ printfPQExpBuffer(&buf,
+ "SELECT pubname\n"
+ "FROM pg_catalog.pg_publication p\n"
+ "JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
+ "WHERE pr.prrelid = '%s'\n"
+ "UNION ALL\n"
+ "SELECT pubname\n"
+ "FROM pg_catalog.pg_publication p\n"
+ "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
+ "ORDER BY 1;",
+ oid, oid);
+ }
result = PSQLexec(buf.data);
if (!result)
@@ -5021,6 +5044,8 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
PQExpBufferData buf;
PGresult *res;
printQueryOpt myopt = pset.popt;
+ int pub_schema_tuples = 0;
+ char **footers = NULL;
initPQExpBuffer(&buf);
printfPQExpBuffer(&buf,
@@ -5053,17 +5078,80 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
appendPQExpBufferStr(&buf, "ORDER BY 1;");
res = PSQLexec(buf.data);
- termPQExpBuffer(&buf);
if (!res)
+ {
+ termPQExpBuffer(&buf);
return false;
+ }
myopt.nullPrint = NULL;
myopt.title = _("List of schemas");
myopt.translate_header = true;
+ if (pattern && pset.sversion >= 150000)
+ {
+ PGresult *result;
+ int i;
+
+ printfPQExpBuffer(&buf,
+ "SELECT pubname \n"
+ "FROM pg_catalog.pg_publication p\n"
+ " JOIN pg_catalog.pg_publication_namespace pn ON p.oid = pn.pnpubid\n"
+ " JOIN pg_catalog.pg_namespace n ON n.oid = pn.pnnspid \n"
+ "WHERE n.nspname = '%s'\n"
+ "ORDER BY 1",
+ pattern);
+ result = PSQLexec(buf.data);
+ if (!result)
+ {
+ termPQExpBuffer(&buf);
+ return false;
+ }
+ else
+ pub_schema_tuples = PQntuples(result);
+
+ if (pub_schema_tuples > 0)
+ {
+ /*
+ * Allocate memory for footers. Size of footers will be 1 (for
+ * storing "Publications:" string) + publication schema mapping
+ * count + 1 (for storing NULL).
+ */
+ footers = (char **) palloc((1 + pub_schema_tuples + 1) * sizeof(char *));
+ footers[0] = pstrdup(_("Publications:"));
+
+ /* Might be an empty set - that's ok */
+ for (i = 0; i < pub_schema_tuples; i++)
+ {
+ printfPQExpBuffer(&buf, " \"%s\"",
+ PQgetvalue(result, i, 0));
+
+ footers[i + 1] = pstrdup(buf.data);
+ }
+
+ footers[i + 1] = NULL;
+ myopt.footers = footers;
+ }
+
+ PQclear(result);
+ }
+
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ termPQExpBuffer(&buf);
PQclear(res);
+
+ /* Free the memory allocated for the footer */
+ if (footers)
+ {
+ char **footer = NULL;
+
+ for (footer = footers; *footer; footer++)
+ pfree(*footer);
+
+ pfree(footers);
+ }
+
return true;
}
@@ -6210,6 +6298,41 @@ listPublications(const char *pattern)
return true;
}
+/*
+ * Add footer to publication description.
+ */
+static bool
+addFooterToPublicationDesc(PQExpBuffer buf, char *footermsg,
+ bool singlecol, printTableContent *cont)
+{
+ PGresult *res;
+ int count = 0;
+ int i = 0;
+
+ res = PSQLexec(buf->data);
+ if (!res)
+ return false;
+ else
+ count = PQntuples(res);
+
+ if (count > 0)
+ printTableAddFooter(cont, _(footermsg));
+
+ for (i = 0; i < count; i++)
+ {
+ if (!singlecol)
+ printfPQExpBuffer(buf, " \"%s.%s\"", PQgetvalue(res, i, 0),
+ PQgetvalue(res, i, 1));
+ else
+ printfPQExpBuffer(buf, " \"%s\"", PQgetvalue(res, i, 0));
+
+ printTableAddFooter(cont, buf->data);
+ }
+
+ PQclear(res);
+ return true;
+}
+
/*
* \dRp+
* Describes publications including the contents.
@@ -6225,6 +6348,9 @@ describePublications(const char *pattern)
bool has_pubtruncate;
bool has_pubviaroot;
+ PQExpBufferData title;
+ printTableContent cont;
+
if (pset.sversion < 100000)
{
char sverbuf[32];
@@ -6287,15 +6413,10 @@ describePublications(const char *pattern)
const char align = 'l';
int ncols = 5;
int nrows = 1;
- int tables = 0;
- PGresult *tabres;
char *pubid = PQgetvalue(res, i, 0);
char *pubname = PQgetvalue(res, i, 1);
bool puballtables = strcmp(PQgetvalue(res, i, 3), "t") == 0;
- int j;
- PQExpBufferData title;
printTableOpt myopt = pset.popt.topt;
- printTableContent cont;
if (has_pubtruncate)
ncols++;
@@ -6328,6 +6449,7 @@ describePublications(const char *pattern)
if (!puballtables)
{
+ /* Get the tables for the specified publication */
printfPQExpBuffer(&buf,
"SELECT n.nspname, c.relname\n"
"FROM pg_catalog.pg_class c,\n"
@@ -6337,31 +6459,22 @@ describePublications(const char *pattern)
" AND c.oid = pr.prrelid\n"
" AND pr.prpubid = '%s'\n"
"ORDER BY 1,2", pubid);
+ if (!addFooterToPublicationDesc(&buf, "Tables:", false, &cont))
+ goto error_return;
- tabres = PSQLexec(buf.data);
- if (!tabres)
- {
- printTableCleanup(&cont);
- PQclear(res);
- termPQExpBuffer(&buf);
- termPQExpBuffer(&title);
- return false;
- }
- else
- tables = PQntuples(tabres);
-
- if (tables > 0)
- printTableAddFooter(&cont, _("Tables:"));
-
- for (j = 0; j < tables; j++)
+ if (pset.sversion >= 150000)
{
- printfPQExpBuffer(&buf, " \"%s.%s\"",
- PQgetvalue(tabres, j, 0),
- PQgetvalue(tabres, j, 1));
-
- printTableAddFooter(&cont, buf.data);
+ /* Get the schemas for the specified publication */
+ printfPQExpBuffer(&buf,
+ "SELECT n.nspname\n"
+ "FROM pg_catalog.pg_namespace n\n"
+ " JOIN pg_catalog.pg_publication_namespace pn ON n.oid = pn.pnnspid\n"
+ "WHERE pn.pnpubid = '%s'\n"
+ "ORDER BY 1", pubid);
+ if (!addFooterToPublicationDesc(&buf, "Tables from schemas:",
+ true, &cont))
+ goto error_return;
}
- PQclear(tabres);
}
printTable(&cont, pset.queryFout, false, pset.logfile);
@@ -6374,6 +6487,13 @@ describePublications(const char *pattern)
PQclear(res);
return true;
+
+error_return:
+ printTableCleanup(&cont);
+ PQclear(res);
+ termPQExpBuffer(&buf);
+ termPQExpBuffer(&title);
+ return false;
}
/*
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index ecae9df8ed..2a0f234622 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1644,10 +1644,19 @@ psql_completion(const char *text, int start, int end)
/* ALTER PUBLICATION <name> */
else if (Matches("ALTER", "PUBLICATION", MatchAny))
- COMPLETE_WITH("ADD TABLE", "DROP TABLE", "OWNER TO", "RENAME TO", "SET");
+ COMPLETE_WITH("ADD", "DROP", "OWNER TO", "RENAME TO", "SET");
+ /* ALTER PUBLICATION <name> ADD */
+ else if (Matches("ALTER", "PUBLICATION", MatchAny, "ADD"))
+ COMPLETE_WITH("ALL TABLES IN SCHEMA", "TABLE");
+ /* ALTER PUBLICATION <name> DROP */
+ else if (Matches("ALTER", "PUBLICATION", MatchAny, "DROP"))
+ COMPLETE_WITH("ALL TABLES IN SCHEMA", "TABLE");
/* ALTER PUBLICATION <name> SET */
else if (Matches("ALTER", "PUBLICATION", MatchAny, "SET"))
- COMPLETE_WITH("(", "TABLE");
+ COMPLETE_WITH("(", "ALL TABLES IN SCHEMA", "TABLE");
+ else if (Matches("ALTER", "PUBLICATION", MatchAny, "ADD|DROP|SET", "ALL", "TABLES", "IN", "SCHEMA"))
+ COMPLETE_WITH_QUERY(Query_for_list_of_schemas
+ " UNION SELECT 'CURRENT_SCHEMA'");
/* ALTER PUBLICATION <name> SET ( */
else if (HeadMatches("ALTER", "PUBLICATION", MatchAny) && TailMatches("SET", "("))
COMPLETE_WITH("publish", "publish_via_partition_root");
@@ -2688,17 +2697,28 @@ psql_completion(const char *text, int start, int end)
/* CREATE PUBLICATION */
else if (Matches("CREATE", "PUBLICATION", MatchAny))
- COMPLETE_WITH("FOR TABLE", "FOR ALL TABLES", "WITH (");
+ COMPLETE_WITH("FOR TABLE", "FOR ALL TABLES", "FOR ALL TABLES IN SCHEMA", "WITH (");
else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR"))
- COMPLETE_WITH("TABLE", "ALL TABLES");
+ COMPLETE_WITH("TABLE", "ALL TABLES", "ALL TABLES IN SCHEMA");
else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL"))
- COMPLETE_WITH("TABLES");
- else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "TABLES")
- || Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "TABLE", MatchAny))
+ COMPLETE_WITH("TABLES", "TABLES IN SCHEMA");
+ else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "TABLES"))
+ COMPLETE_WITH("IN SCHEMA", "WITH (");
+ else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "TABLE", MatchAny))
COMPLETE_WITH("WITH (");
/* Complete "CREATE PUBLICATION <name> FOR TABLE" with "<table>, ..." */
else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "TABLE"))
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+
+ /*
+ * Complete "CREATE PUBLICATION <name> FOR ALL TABLES IN SCHEMA <schema>,
+ * ..."
+ */
+ else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "TABLES", "IN", "SCHEMA"))
+ COMPLETE_WITH_QUERY(Query_for_list_of_schemas
+ " UNION SELECT 'CURRENT_SCHEMA' ");
+ else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "ALL", "TABLES", "IN", "SCHEMA", MatchAny) && (!ends_with(prev_wd, ',')))
+ COMPLETE_WITH("WITH (");
/* Complete "CREATE PUBLICATION <name> [...] WITH" */
else if (HeadMatches("CREATE", "PUBLICATION") && TailMatches("WITH", "("))
COMPLETE_WITH("publish", "publish_via_partition_root");
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 746566c01a..cd3736b7a3 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2052,6 +2052,7 @@ PublicationObjSpec
PublicationObjSpecType
PublicationPartOpt
PublicationRelInfo
+PublicationSchemaInfo
PullFilter
PullFilterOps
PushFilter
--
2.30.2