2017-01-19 18:00:00 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* pg_publication.c
|
|
|
|
* publication C API manipulation
|
|
|
|
*
|
2021-01-02 19:06:25 +01:00
|
|
|
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
2017-01-25 18:32:05 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
2017-01-19 18:00:00 +01:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* pg_publication.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2019-12-27 00:09:00 +01:00
|
|
|
#include "access/genam.h"
|
2017-01-19 18:00:00 +01:00
|
|
|
#include "access/heapam.h"
|
|
|
|
#include "access/htup_details.h"
|
tableam: Add and use scan APIs.
Too allow table accesses to be not directly dependent on heap, several
new abstractions are needed. Specifically:
1) Heap scans need to be generalized into table scans. Do this by
introducing TableScanDesc, which will be the "base class" for
individual AMs. This contains the AM independent fields from
HeapScanDesc.
The previous heap_{beginscan,rescan,endscan} et al. have been
replaced with a table_ version.
There's no direct replacement for heap_getnext(), as that returned
a HeapTuple, which is undesirable for a other AMs. Instead there's
table_scan_getnextslot(). But note that heap_getnext() lives on,
it's still used widely to access catalog tables.
This is achieved by new scan_begin, scan_end, scan_rescan,
scan_getnextslot callbacks.
2) The portion of parallel scans that's shared between backends need
to be able to do so without the user doing per-AM work. To achieve
that new parallelscan_{estimate, initialize, reinitialize}
callbacks are introduced, which operate on a new
ParallelTableScanDesc, which again can be subclassed by AMs.
As it is likely that several AMs are going to be block oriented,
block oriented callbacks that can be shared between such AMs are
provided and used by heap. table_block_parallelscan_{estimate,
intiialize, reinitialize} as callbacks, and
table_block_parallelscan_{nextpage, init} for use in AMs. These
operate on a ParallelBlockTableScanDesc.
3) Index scans need to be able to access tables to return a tuple, and
there needs to be state across individual accesses to the heap to
store state like buffers. That's now handled by introducing a
sort-of-scan IndexFetchTable, which again is intended to be
subclassed by individual AMs (for heap IndexFetchHeap).
The relevant callbacks for an AM are index_fetch_{end, begin,
reset} to create the necessary state, and index_fetch_tuple to
retrieve an indexed tuple. Note that index_fetch_tuple
implementations need to be smarter than just blindly fetching the
tuples for AMs that have optimizations similar to heap's HOT - the
currently alive tuple in the update chain needs to be fetched if
appropriate.
Similar to table_scan_getnextslot(), it's undesirable to continue
to return HeapTuples. Thus index_fetch_heap (might want to rename
that later) now accepts a slot as an argument. Core code doesn't
have a lot of call sites performing index scans without going
through the systable_* API (in contrast to loads of heap_getnext
calls and working directly with HeapTuples).
Index scans now store the result of a search in
IndexScanDesc->xs_heaptid, rather than xs_ctup->t_self. As the
target is not generally a HeapTuple anymore that seems cleaner.
To be able to sensible adapt code to use the above, two further
callbacks have been introduced:
a) slot_callbacks returns a TupleTableSlotOps* suitable for creating
slots capable of holding a tuple of the AMs
type. table_slot_callbacks() and table_slot_create() are based
upon that, but have additional logic to deal with views, foreign
tables, etc.
While this change could have been done separately, nearly all the
call sites that needed to be adapted for the rest of this commit
also would have been needed to be adapted for
table_slot_callbacks(), making separation not worthwhile.
b) tuple_satisfies_snapshot checks whether the tuple in a slot is
currently visible according to a snapshot. That's required as a few
places now don't have a buffer + HeapTuple around, but a
slot (which in heap's case internally has that information).
Additionally a few infrastructure changes were needed:
I) SysScanDesc, as used by systable_{beginscan, getnext} et al. now
internally uses a slot to keep track of tuples. While
systable_getnext() still returns HeapTuples, and will so for the
foreseeable future, the index API (see 1) above) now only deals with
slots.
The remainder, and largest part, of this commit is then adjusting all
scans in postgres to use the new APIs.
Author: Andres Freund, Haribabu Kommi, Alvaro Herrera
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
2019-03-11 20:46:41 +01:00
|
|
|
#include "access/tableam.h"
|
2017-01-19 18:00:00 +01:00
|
|
|
#include "access/xact.h"
|
|
|
|
#include "catalog/catalog.h"
|
|
|
|
#include "catalog/dependency.h"
|
|
|
|
#include "catalog/index.h"
|
|
|
|
#include "catalog/indexing.h"
|
|
|
|
#include "catalog/namespace.h"
|
2020-03-10 08:42:59 +01:00
|
|
|
#include "catalog/partition.h"
|
2017-01-19 18:00:00 +01:00
|
|
|
#include "catalog/objectaccess.h"
|
|
|
|
#include "catalog/objectaddress.h"
|
2020-03-10 08:42:59 +01:00
|
|
|
#include "catalog/pg_inherits.h"
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
#include "catalog/pg_namespace.h"
|
2017-01-19 18:00:00 +01:00
|
|
|
#include "catalog/pg_publication.h"
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
#include "catalog/pg_publication_namespace.h"
|
2017-01-19 18:00:00 +01:00
|
|
|
#include "catalog/pg_publication_rel.h"
|
2019-11-12 04:00:16 +01:00
|
|
|
#include "catalog/pg_type.h"
|
2021-09-22 04:30:54 +02:00
|
|
|
#include "commands/publicationcmds.h"
|
2019-11-12 04:00:16 +01:00
|
|
|
#include "funcapi.h"
|
|
|
|
#include "miscadmin.h"
|
2017-01-19 18:00:00 +01:00
|
|
|
#include "utils/array.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/catcache.h"
|
|
|
|
#include "utils/fmgroids.h"
|
|
|
|
#include "utils/inval.h"
|
|
|
|
#include "utils/lsyscache.h"
|
|
|
|
#include "utils/rel.h"
|
|
|
|
#include "utils/syscache.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if relation can be in given publication and throws appropriate
|
|
|
|
* error if not.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_publication_add_relation(Relation targetrel)
|
|
|
|
{
|
2020-03-10 08:42:59 +01:00
|
|
|
/* Must be a regular or partitioned table */
|
|
|
|
if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
|
|
|
|
RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
|
2017-01-19 18:00:00 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2021-07-21 07:40:05 +02:00
|
|
|
errmsg("cannot add relation \"%s\" to publication",
|
2017-01-19 18:00:00 +01:00
|
|
|
RelationGetRelationName(targetrel)),
|
2021-07-21 07:40:05 +02:00
|
|
|
errdetail_relkind_not_supported(RelationGetForm(targetrel)->relkind)));
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
/* Can't be system table */
|
|
|
|
if (IsCatalogRelation(targetrel))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2021-07-21 07:40:05 +02:00
|
|
|
errmsg("cannot add relation \"%s\" to publication",
|
2017-01-19 18:00:00 +01:00
|
|
|
RelationGetRelationName(targetrel)),
|
2021-07-21 07:40:05 +02:00
|
|
|
errdetail("This operation is not supported for system tables.")));
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
/* UNLOGGED and TEMP relations cannot be part of publication. */
|
2021-11-17 14:40:38 +01:00
|
|
|
if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
|
2017-01-19 18:00:00 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
2021-07-21 07:40:05 +02:00
|
|
|
errmsg("cannot add relation \"%s\" to publication",
|
2017-01-19 18:00:00 +01:00
|
|
|
RelationGetRelationName(targetrel)),
|
2021-11-17 14:40:38 +01:00
|
|
|
errdetail("This operation is not supported for temporary tables.")));
|
|
|
|
else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot add relation \"%s\" to publication",
|
|
|
|
RelationGetRelationName(targetrel)),
|
|
|
|
errdetail("This operation is not supported for unlogged tables.")));
|
2017-01-19 18:00:00 +01:00
|
|
|
}
|
|
|
|
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
/*
|
|
|
|
* Check if schema can be in given publication and throw appropriate error if
|
|
|
|
* not.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_publication_add_schema(Oid schemaid)
|
|
|
|
{
|
|
|
|
/* Can't be system namespace */
|
|
|
|
if (IsCatalogNamespace(schemaid) || IsToastNamespace(schemaid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot add schema \"%s\" to publication",
|
|
|
|
get_namespace_name(schemaid)),
|
|
|
|
errdetail("This operation is not supported for system schemas.")));
|
|
|
|
|
|
|
|
/* Can't be temporary namespace */
|
|
|
|
if (isAnyTempNamespace(schemaid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("cannot add schema \"%s\" to publication",
|
|
|
|
get_namespace_name(schemaid)),
|
|
|
|
errdetail("Temporary schemas cannot be replicated.")));
|
|
|
|
}
|
|
|
|
|
2017-01-19 18:00:00 +01:00
|
|
|
/*
|
|
|
|
* Returns if relation represented by oid and Form_pg_class entry
|
|
|
|
* is publishable.
|
|
|
|
*
|
|
|
|
* Does same checks as the above, but does not need relation to be opened
|
|
|
|
* and also does not throw errors.
|
2017-05-17 02:36:35 +02:00
|
|
|
*
|
2019-05-13 23:05:48 +02:00
|
|
|
* XXX This also excludes all tables with relid < FirstNormalObjectId,
|
2017-05-17 02:36:35 +02:00
|
|
|
* ie all tables created during initdb. This mainly affects the preinstalled
|
2019-05-13 23:05:48 +02:00
|
|
|
* information_schema. IsCatalogRelationOid() only excludes tables with
|
2021-07-15 17:41:47 +02:00
|
|
|
* relid < FirstUnpinnedObjectId, making that test rather redundant,
|
2019-05-13 23:05:48 +02:00
|
|
|
* but really we should get rid of the FirstNormalObjectId test not
|
|
|
|
* IsCatalogRelationOid. We can't do so today because we don't want
|
|
|
|
* information_schema tables to be considered publishable; but this test
|
|
|
|
* is really inadequate for that, since the information_schema could be
|
|
|
|
* dropped and reloaded and then it'll be considered publishable. The best
|
|
|
|
* long-term solution may be to add a "relispublishable" bool to pg_class,
|
|
|
|
* and depend on that instead of OID checks.
|
2017-01-19 18:00:00 +01:00
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
is_publishable_class(Oid relid, Form_pg_class reltuple)
|
|
|
|
{
|
2020-03-10 08:42:59 +01:00
|
|
|
return (reltuple->relkind == RELKIND_RELATION ||
|
|
|
|
reltuple->relkind == RELKIND_PARTITIONED_TABLE) &&
|
Clean up the behavior and API of catalog.c's is-catalog-relation tests.
The right way for IsCatalogRelation/Class to behave is to return true
for OIDs less than FirstBootstrapObjectId (not FirstNormalObjectId),
without any of the ad-hoc fooling around with schema membership.
The previous code was wrong because (1) it claimed that
information_schema tables were not catalog relations but their toast
tables were, which is silly; and (2) if you dropped and recreated
information_schema, which is a supported operation, the behavior
changed. That's even sillier. With this definition, "catalog
relations" are exactly the ones traceable to the postgres.bki data,
which seems like what we want.
With this simplification, we don't actually need access to the pg_class
tuple to identify a catalog relation; we only need its OID. Hence,
replace IsCatalogClass with "IsCatalogRelationOid(oid)". But keep
IsCatalogRelation as a convenience function.
This allows fixing some arguably-wrong semantics in contrib/sepgsql and
ReindexRelationConcurrently, which were using an IsSystemNamespace test
where what they really should be using is IsCatalogRelationOid. The
previous coding failed to protect toast tables of system catalogs, and
also was not on board with the general principle that user-created tables
do not become catalogs just by virtue of being renamed into pg_catalog.
We can also get rid of a messy hack in ReindexMultipleTables.
While we're at it, also rename IsSystemNamespace to IsCatalogNamespace,
because the previous name invited confusion with the more expansive
semantics used by IsSystemRelation/Class.
Also improve the comments in catalog.c.
There are a few remaining places in replication-related code that are
special-casing OIDs below FirstNormalObjectId. I'm inclined to think
those are wrong too, and if there should be any special case it should
just extend to FirstBootstrapObjectId. But first we need to debate
whether a FOR ALL TABLES publication should include information_schema.
Discussion: https://postgr.es/m/21697.1557092753@sss.pgh.pa.us
Discussion: https://postgr.es/m/15150.1557257111@sss.pgh.pa.us
2019-05-09 05:27:29 +02:00
|
|
|
!IsCatalogRelationOid(relid) &&
|
2017-01-19 18:00:00 +01:00
|
|
|
reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
|
|
|
|
relid >= FirstNormalObjectId;
|
|
|
|
}
|
|
|
|
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
/*
|
|
|
|
* Filter out the partitions whose parent tables were also specified in
|
|
|
|
* the publication.
|
|
|
|
*/
|
|
|
|
static List *
|
2021-12-09 04:06:59 +01:00
|
|
|
filter_partitions(List *relids)
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
{
|
|
|
|
List *result = NIL;
|
|
|
|
ListCell *lc;
|
|
|
|
ListCell *lc2;
|
|
|
|
|
|
|
|
foreach(lc, relids)
|
|
|
|
{
|
|
|
|
bool skip = false;
|
|
|
|
List *ancestors = NIL;
|
|
|
|
Oid relid = lfirst_oid(lc);
|
|
|
|
|
|
|
|
if (get_rel_relispartition(relid))
|
|
|
|
ancestors = get_partition_ancestors(relid);
|
|
|
|
|
|
|
|
foreach(lc2, ancestors)
|
|
|
|
{
|
|
|
|
Oid ancestor = lfirst_oid(lc2);
|
|
|
|
|
2021-12-09 04:06:59 +01:00
|
|
|
/* Check if the parent table exists in the published table list. */
|
|
|
|
if (list_member_oid(relids, ancestor))
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
{
|
|
|
|
skip = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!skip)
|
|
|
|
result = lappend_oid(result, relid);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-02-24 04:13:21 +01:00
|
|
|
/*
|
|
|
|
* Another variant of this, taking a Relation.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
is_publishable_relation(Relation rel)
|
|
|
|
{
|
|
|
|
return is_publishable_class(RelationGetRelid(rel), rel->rd_rel);
|
|
|
|
}
|
|
|
|
|
2021-12-08 07:01:16 +01:00
|
|
|
/*
|
|
|
|
* Returns true if any schema is associated with the publication, false if no
|
|
|
|
* schema is associated with the publication.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
is_schema_publication(Oid pubid)
|
|
|
|
{
|
|
|
|
Relation pubschsrel;
|
|
|
|
ScanKeyData scankey;
|
|
|
|
SysScanDesc scan;
|
|
|
|
HeapTuple tup;
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
pubschsrel = table_open(PublicationNamespaceRelationId, AccessShareLock);
|
|
|
|
ScanKeyInit(&scankey,
|
|
|
|
Anum_pg_publication_namespace_pnpubid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(pubid));
|
|
|
|
|
|
|
|
scan = systable_beginscan(pubschsrel,
|
|
|
|
PublicationNamespacePnnspidPnpubidIndexId,
|
|
|
|
true, NULL, 1, &scankey);
|
|
|
|
tup = systable_getnext(scan);
|
|
|
|
result = HeapTupleIsValid(tup);
|
|
|
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
table_close(pubschsrel, AccessShareLock);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2017-06-20 18:25:07 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* SQL-callable variant of the above
|
|
|
|
*
|
|
|
|
* This returns null when the relation does not exist. This is intended to be
|
|
|
|
* used for example in psql to avoid gratuitous errors when there are
|
|
|
|
* concurrent catalog changes.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_relation_is_publishable(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
HeapTuple tuple;
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
|
2019-05-05 19:10:07 +02:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
2017-06-20 18:25:07 +02:00
|
|
|
PG_RETURN_NULL();
|
|
|
|
result = is_publishable_class(relid, (Form_pg_class) GETSTRUCT(tuple));
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
PG_RETURN_BOOL(result);
|
|
|
|
}
|
|
|
|
|
2021-09-22 04:30:54 +02:00
|
|
|
/*
|
|
|
|
* Gets the relations based on the publication partition option for a specified
|
|
|
|
* relation.
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
GetPubPartitionOptionRelations(List *result, PublicationPartOpt pub_partopt,
|
|
|
|
Oid relid)
|
|
|
|
{
|
|
|
|
if (get_rel_relkind(relid) == RELKIND_PARTITIONED_TABLE &&
|
|
|
|
pub_partopt != PUBLICATION_PART_ROOT)
|
|
|
|
{
|
|
|
|
List *all_parts = find_all_inheritors(relid, NoLock,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (pub_partopt == PUBLICATION_PART_ALL)
|
|
|
|
result = list_concat(result, all_parts);
|
|
|
|
else if (pub_partopt == PUBLICATION_PART_LEAF)
|
|
|
|
{
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
foreach(lc, all_parts)
|
|
|
|
{
|
|
|
|
Oid partOid = lfirst_oid(lc);
|
|
|
|
|
|
|
|
if (get_rel_relkind(partOid) != RELKIND_PARTITIONED_TABLE)
|
|
|
|
result = lappend_oid(result, partOid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Assert(false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = lappend_oid(result, relid);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2017-06-20 18:25:07 +02:00
|
|
|
|
2017-01-19 18:00:00 +01:00
|
|
|
/*
|
|
|
|
* Insert new publication / relation mapping.
|
|
|
|
*/
|
|
|
|
ObjectAddress
|
2021-09-06 19:24:50 +02:00
|
|
|
publication_add_relation(Oid pubid, PublicationRelInfo *targetrel,
|
2017-01-19 18:00:00 +01:00
|
|
|
bool if_not_exists)
|
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
HeapTuple tup;
|
|
|
|
Datum values[Natts_pg_publication_rel];
|
|
|
|
bool nulls[Natts_pg_publication_rel];
|
2021-09-06 19:24:50 +02:00
|
|
|
Oid relid = RelationGetRelid(targetrel->relation);
|
2017-01-19 18:00:00 +01:00
|
|
|
Oid prrelid;
|
|
|
|
Publication *pub = GetPublication(pubid);
|
|
|
|
ObjectAddress myself,
|
|
|
|
referenced;
|
2021-09-22 04:30:54 +02:00
|
|
|
List *relids = NIL;
|
2017-01-19 18:00:00 +01:00
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
rel = table_open(PublicationRelRelationId, RowExclusiveLock);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for duplicates. Note that this does not really prevent
|
|
|
|
* duplicates, it's here just to provide nicer error message in common
|
|
|
|
* case. The real protection is the unique key on the catalog.
|
|
|
|
*/
|
|
|
|
if (SearchSysCacheExists2(PUBLICATIONRELMAP, ObjectIdGetDatum(relid),
|
|
|
|
ObjectIdGetDatum(pubid)))
|
|
|
|
{
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(rel, RowExclusiveLock);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
if (if_not_exists)
|
|
|
|
return InvalidObjectAddress;
|
|
|
|
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("relation \"%s\" is already member of publication \"%s\"",
|
2021-09-06 19:24:50 +02:00
|
|
|
RelationGetRelationName(targetrel->relation), pub->name)));
|
2017-01-19 18:00:00 +01:00
|
|
|
}
|
|
|
|
|
2021-09-06 19:24:50 +02:00
|
|
|
check_publication_add_relation(targetrel->relation);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
/* Form a tuple. */
|
|
|
|
memset(values, 0, sizeof(values));
|
|
|
|
memset(nulls, false, sizeof(nulls));
|
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
prrelid = GetNewOidWithIndex(rel, PublicationRelObjectIndexId,
|
|
|
|
Anum_pg_publication_rel_oid);
|
|
|
|
values[Anum_pg_publication_rel_oid - 1] = ObjectIdGetDatum(prrelid);
|
2017-01-19 18:00:00 +01:00
|
|
|
values[Anum_pg_publication_rel_prpubid - 1] =
|
|
|
|
ObjectIdGetDatum(pubid);
|
|
|
|
values[Anum_pg_publication_rel_prrelid - 1] =
|
|
|
|
ObjectIdGetDatum(relid);
|
|
|
|
|
|
|
|
tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
|
|
|
|
|
|
|
|
/* Insert tuple into catalog. */
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
CatalogTupleInsert(rel, tup);
|
2017-01-19 18:00:00 +01:00
|
|
|
heap_freetuple(tup);
|
|
|
|
|
|
|
|
ObjectAddressSet(myself, PublicationRelRelationId, prrelid);
|
|
|
|
|
|
|
|
/* Add dependency on the publication */
|
|
|
|
ObjectAddressSet(referenced, PublicationRelationId, pubid);
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
|
|
|
|
|
|
|
|
/* Add dependency on the relation */
|
|
|
|
ObjectAddressSet(referenced, RelationRelationId, relid);
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
|
|
|
|
|
|
|
|
/* Close the table. */
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(rel, RowExclusiveLock);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
2021-09-22 04:30:54 +02:00
|
|
|
/*
|
|
|
|
* Invalidate relcache so that publication info is rebuilt.
|
|
|
|
*
|
|
|
|
* For the partitioned tables, we must invalidate all partitions contained
|
|
|
|
* in the respective partition hierarchies, not just the one explicitly
|
|
|
|
* mentioned in the publication. This is required because we implicitly
|
|
|
|
* publish the child tables when the parent table is published.
|
|
|
|
*/
|
|
|
|
relids = GetPubPartitionOptionRelations(relids, PUBLICATION_PART_ALL,
|
|
|
|
relid);
|
|
|
|
|
|
|
|
InvalidatePublicationRels(relids);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
return myself;
|
|
|
|
}
|
|
|
|
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
/*
|
|
|
|
* Insert new publication / schema mapping.
|
|
|
|
*/
|
|
|
|
ObjectAddress
|
|
|
|
publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)
|
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
HeapTuple tup;
|
|
|
|
Datum values[Natts_pg_publication_namespace];
|
|
|
|
bool nulls[Natts_pg_publication_namespace];
|
|
|
|
Oid psschid;
|
|
|
|
Publication *pub = GetPublication(pubid);
|
|
|
|
List *schemaRels = NIL;
|
|
|
|
ObjectAddress myself,
|
|
|
|
referenced;
|
|
|
|
|
|
|
|
rel = table_open(PublicationNamespaceRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for duplicates. Note that this does not really prevent
|
|
|
|
* duplicates, it's here just to provide nicer error message in common
|
|
|
|
* case. The real protection is the unique key on the catalog.
|
|
|
|
*/
|
|
|
|
if (SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP,
|
|
|
|
ObjectIdGetDatum(schemaid),
|
|
|
|
ObjectIdGetDatum(pubid)))
|
|
|
|
{
|
|
|
|
table_close(rel, RowExclusiveLock);
|
|
|
|
|
|
|
|
if (if_not_exists)
|
|
|
|
return InvalidObjectAddress;
|
|
|
|
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("schema \"%s\" is already member of publication \"%s\"",
|
|
|
|
get_namespace_name(schemaid), pub->name)));
|
|
|
|
}
|
|
|
|
|
|
|
|
check_publication_add_schema(schemaid);
|
|
|
|
|
|
|
|
/* Form a tuple */
|
|
|
|
memset(values, 0, sizeof(values));
|
|
|
|
memset(nulls, false, sizeof(nulls));
|
|
|
|
|
|
|
|
psschid = GetNewOidWithIndex(rel, PublicationNamespaceObjectIndexId,
|
|
|
|
Anum_pg_publication_namespace_oid);
|
|
|
|
values[Anum_pg_publication_namespace_oid - 1] = ObjectIdGetDatum(psschid);
|
|
|
|
values[Anum_pg_publication_namespace_pnpubid - 1] =
|
|
|
|
ObjectIdGetDatum(pubid);
|
|
|
|
values[Anum_pg_publication_namespace_pnnspid - 1] =
|
|
|
|
ObjectIdGetDatum(schemaid);
|
|
|
|
|
|
|
|
tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
|
|
|
|
|
|
|
|
/* Insert tuple into catalog */
|
|
|
|
CatalogTupleInsert(rel, tup);
|
|
|
|
heap_freetuple(tup);
|
|
|
|
|
|
|
|
ObjectAddressSet(myself, PublicationNamespaceRelationId, psschid);
|
|
|
|
|
|
|
|
/* Add dependency on the publication */
|
|
|
|
ObjectAddressSet(referenced, PublicationRelationId, pubid);
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
|
|
|
|
|
|
|
|
/* Add dependency on the schema */
|
|
|
|
ObjectAddressSet(referenced, NamespaceRelationId, schemaid);
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
|
|
|
|
|
|
|
|
/* Close the table */
|
|
|
|
table_close(rel, RowExclusiveLock);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Invalidate relcache so that publication info is rebuilt. See
|
|
|
|
* publication_add_relation for why we need to consider all the
|
|
|
|
* partitions.
|
|
|
|
*/
|
|
|
|
schemaRels = GetSchemaPublicationRelations(schemaid,
|
|
|
|
PUBLICATION_PART_ALL);
|
|
|
|
InvalidatePublicationRels(schemaRels);
|
|
|
|
|
|
|
|
return myself;
|
|
|
|
}
|
|
|
|
|
2020-04-08 09:59:27 +02:00
|
|
|
/* Gets list of publication oids for a relation */
|
2017-01-19 18:00:00 +01:00
|
|
|
List *
|
|
|
|
GetRelationPublications(Oid relid)
|
|
|
|
{
|
|
|
|
List *result = NIL;
|
|
|
|
CatCList *pubrellist;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Find all publications associated with the relation. */
|
|
|
|
pubrellist = SearchSysCacheList1(PUBLICATIONRELMAP,
|
|
|
|
ObjectIdGetDatum(relid));
|
|
|
|
for (i = 0; i < pubrellist->n_members; i++)
|
|
|
|
{
|
|
|
|
HeapTuple tup = &pubrellist->members[i]->tuple;
|
|
|
|
Oid pubid = ((Form_pg_publication_rel) GETSTRUCT(tup))->prpubid;
|
|
|
|
|
|
|
|
result = lappend_oid(result, pubid);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseSysCacheList(pubrellist);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Gets list of relation oids for a publication.
|
|
|
|
*
|
2021-09-22 04:30:54 +02:00
|
|
|
* This should only be used FOR TABLE publications, the FOR ALL TABLES
|
2017-01-19 18:00:00 +01:00
|
|
|
* should use GetAllTablesPublicationRelations().
|
|
|
|
*/
|
|
|
|
List *
|
2020-03-10 08:42:59 +01:00
|
|
|
GetPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
|
2017-01-19 18:00:00 +01:00
|
|
|
{
|
|
|
|
List *result;
|
|
|
|
Relation pubrelsrel;
|
|
|
|
ScanKeyData scankey;
|
|
|
|
SysScanDesc scan;
|
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
/* Find all publications associated with the relation. */
|
2019-01-21 19:32:19 +01:00
|
|
|
pubrelsrel = table_open(PublicationRelRelationId, AccessShareLock);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
ScanKeyInit(&scankey,
|
|
|
|
Anum_pg_publication_rel_prpubid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(pubid));
|
|
|
|
|
2017-03-23 13:36:36 +01:00
|
|
|
scan = systable_beginscan(pubrelsrel, PublicationRelPrrelidPrpubidIndexId,
|
|
|
|
true, NULL, 1, &scankey);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
result = NIL;
|
|
|
|
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
|
|
|
{
|
|
|
|
Form_pg_publication_rel pubrel;
|
|
|
|
|
|
|
|
pubrel = (Form_pg_publication_rel) GETSTRUCT(tup);
|
2021-09-22 04:30:54 +02:00
|
|
|
result = GetPubPartitionOptionRelations(result, pub_partopt,
|
|
|
|
pubrel->prrelid);
|
2017-01-19 18:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
systable_endscan(scan);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(pubrelsrel, AccessShareLock);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
2021-12-08 06:45:25 +01:00
|
|
|
/* Now sort and de-duplicate the result list */
|
|
|
|
list_sort(result, list_oid_cmp);
|
|
|
|
list_deduplicate_oid(result);
|
|
|
|
|
2017-01-19 18:00:00 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Gets list of publication oids for publications marked as FOR ALL TABLES.
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
GetAllTablesPublications(void)
|
|
|
|
{
|
|
|
|
List *result;
|
|
|
|
Relation rel;
|
|
|
|
ScanKeyData scankey;
|
|
|
|
SysScanDesc scan;
|
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
/* Find all publications that are marked as for all tables. */
|
2019-01-21 19:32:19 +01:00
|
|
|
rel = table_open(PublicationRelationId, AccessShareLock);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
ScanKeyInit(&scankey,
|
|
|
|
Anum_pg_publication_puballtables,
|
|
|
|
BTEqualStrategyNumber, F_BOOLEQ,
|
|
|
|
BoolGetDatum(true));
|
|
|
|
|
|
|
|
scan = systable_beginscan(rel, InvalidOid, false,
|
|
|
|
NULL, 1, &scankey);
|
|
|
|
|
|
|
|
result = NIL;
|
|
|
|
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
{
|
|
|
|
Oid oid = ((Form_pg_publication) GETSTRUCT(tup))->oid;
|
|
|
|
|
|
|
|
result = lappend_oid(result, oid);
|
|
|
|
}
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
systable_endscan(scan);
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(rel, AccessShareLock);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Gets list of all relation published by FOR ALL TABLES publication(s).
|
2020-04-08 09:59:27 +02:00
|
|
|
*
|
|
|
|
* If the publication publishes partition changes via their respective root
|
|
|
|
* partitioned tables, we must exclude partitions in favor of including the
|
|
|
|
* root partitioned tables.
|
2017-01-19 18:00:00 +01:00
|
|
|
*/
|
|
|
|
List *
|
2020-04-08 09:59:27 +02:00
|
|
|
GetAllTablesPublicationRelations(bool pubviaroot)
|
2017-01-19 18:00:00 +01:00
|
|
|
{
|
|
|
|
Relation classRel;
|
|
|
|
ScanKeyData key[1];
|
tableam: Add and use scan APIs.
Too allow table accesses to be not directly dependent on heap, several
new abstractions are needed. Specifically:
1) Heap scans need to be generalized into table scans. Do this by
introducing TableScanDesc, which will be the "base class" for
individual AMs. This contains the AM independent fields from
HeapScanDesc.
The previous heap_{beginscan,rescan,endscan} et al. have been
replaced with a table_ version.
There's no direct replacement for heap_getnext(), as that returned
a HeapTuple, which is undesirable for a other AMs. Instead there's
table_scan_getnextslot(). But note that heap_getnext() lives on,
it's still used widely to access catalog tables.
This is achieved by new scan_begin, scan_end, scan_rescan,
scan_getnextslot callbacks.
2) The portion of parallel scans that's shared between backends need
to be able to do so without the user doing per-AM work. To achieve
that new parallelscan_{estimate, initialize, reinitialize}
callbacks are introduced, which operate on a new
ParallelTableScanDesc, which again can be subclassed by AMs.
As it is likely that several AMs are going to be block oriented,
block oriented callbacks that can be shared between such AMs are
provided and used by heap. table_block_parallelscan_{estimate,
intiialize, reinitialize} as callbacks, and
table_block_parallelscan_{nextpage, init} for use in AMs. These
operate on a ParallelBlockTableScanDesc.
3) Index scans need to be able to access tables to return a tuple, and
there needs to be state across individual accesses to the heap to
store state like buffers. That's now handled by introducing a
sort-of-scan IndexFetchTable, which again is intended to be
subclassed by individual AMs (for heap IndexFetchHeap).
The relevant callbacks for an AM are index_fetch_{end, begin,
reset} to create the necessary state, and index_fetch_tuple to
retrieve an indexed tuple. Note that index_fetch_tuple
implementations need to be smarter than just blindly fetching the
tuples for AMs that have optimizations similar to heap's HOT - the
currently alive tuple in the update chain needs to be fetched if
appropriate.
Similar to table_scan_getnextslot(), it's undesirable to continue
to return HeapTuples. Thus index_fetch_heap (might want to rename
that later) now accepts a slot as an argument. Core code doesn't
have a lot of call sites performing index scans without going
through the systable_* API (in contrast to loads of heap_getnext
calls and working directly with HeapTuples).
Index scans now store the result of a search in
IndexScanDesc->xs_heaptid, rather than xs_ctup->t_self. As the
target is not generally a HeapTuple anymore that seems cleaner.
To be able to sensible adapt code to use the above, two further
callbacks have been introduced:
a) slot_callbacks returns a TupleTableSlotOps* suitable for creating
slots capable of holding a tuple of the AMs
type. table_slot_callbacks() and table_slot_create() are based
upon that, but have additional logic to deal with views, foreign
tables, etc.
While this change could have been done separately, nearly all the
call sites that needed to be adapted for the rest of this commit
also would have been needed to be adapted for
table_slot_callbacks(), making separation not worthwhile.
b) tuple_satisfies_snapshot checks whether the tuple in a slot is
currently visible according to a snapshot. That's required as a few
places now don't have a buffer + HeapTuple around, but a
slot (which in heap's case internally has that information).
Additionally a few infrastructure changes were needed:
I) SysScanDesc, as used by systable_{beginscan, getnext} et al. now
internally uses a slot to keep track of tuples. While
systable_getnext() still returns HeapTuples, and will so for the
foreseeable future, the index API (see 1) above) now only deals with
slots.
The remainder, and largest part, of this commit is then adjusting all
scans in postgres to use the new APIs.
Author: Andres Freund, Haribabu Kommi, Alvaro Herrera
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
2019-03-11 20:46:41 +01:00
|
|
|
TableScanDesc scan;
|
2017-01-19 18:00:00 +01:00
|
|
|
HeapTuple tuple;
|
|
|
|
List *result = NIL;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
classRel = table_open(RelationRelationId, AccessShareLock);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
Anum_pg_class_relkind,
|
|
|
|
BTEqualStrategyNumber, F_CHAREQ,
|
|
|
|
CharGetDatum(RELKIND_RELATION));
|
|
|
|
|
tableam: Add and use scan APIs.
Too allow table accesses to be not directly dependent on heap, several
new abstractions are needed. Specifically:
1) Heap scans need to be generalized into table scans. Do this by
introducing TableScanDesc, which will be the "base class" for
individual AMs. This contains the AM independent fields from
HeapScanDesc.
The previous heap_{beginscan,rescan,endscan} et al. have been
replaced with a table_ version.
There's no direct replacement for heap_getnext(), as that returned
a HeapTuple, which is undesirable for a other AMs. Instead there's
table_scan_getnextslot(). But note that heap_getnext() lives on,
it's still used widely to access catalog tables.
This is achieved by new scan_begin, scan_end, scan_rescan,
scan_getnextslot callbacks.
2) The portion of parallel scans that's shared between backends need
to be able to do so without the user doing per-AM work. To achieve
that new parallelscan_{estimate, initialize, reinitialize}
callbacks are introduced, which operate on a new
ParallelTableScanDesc, which again can be subclassed by AMs.
As it is likely that several AMs are going to be block oriented,
block oriented callbacks that can be shared between such AMs are
provided and used by heap. table_block_parallelscan_{estimate,
intiialize, reinitialize} as callbacks, and
table_block_parallelscan_{nextpage, init} for use in AMs. These
operate on a ParallelBlockTableScanDesc.
3) Index scans need to be able to access tables to return a tuple, and
there needs to be state across individual accesses to the heap to
store state like buffers. That's now handled by introducing a
sort-of-scan IndexFetchTable, which again is intended to be
subclassed by individual AMs (for heap IndexFetchHeap).
The relevant callbacks for an AM are index_fetch_{end, begin,
reset} to create the necessary state, and index_fetch_tuple to
retrieve an indexed tuple. Note that index_fetch_tuple
implementations need to be smarter than just blindly fetching the
tuples for AMs that have optimizations similar to heap's HOT - the
currently alive tuple in the update chain needs to be fetched if
appropriate.
Similar to table_scan_getnextslot(), it's undesirable to continue
to return HeapTuples. Thus index_fetch_heap (might want to rename
that later) now accepts a slot as an argument. Core code doesn't
have a lot of call sites performing index scans without going
through the systable_* API (in contrast to loads of heap_getnext
calls and working directly with HeapTuples).
Index scans now store the result of a search in
IndexScanDesc->xs_heaptid, rather than xs_ctup->t_self. As the
target is not generally a HeapTuple anymore that seems cleaner.
To be able to sensible adapt code to use the above, two further
callbacks have been introduced:
a) slot_callbacks returns a TupleTableSlotOps* suitable for creating
slots capable of holding a tuple of the AMs
type. table_slot_callbacks() and table_slot_create() are based
upon that, but have additional logic to deal with views, foreign
tables, etc.
While this change could have been done separately, nearly all the
call sites that needed to be adapted for the rest of this commit
also would have been needed to be adapted for
table_slot_callbacks(), making separation not worthwhile.
b) tuple_satisfies_snapshot checks whether the tuple in a slot is
currently visible according to a snapshot. That's required as a few
places now don't have a buffer + HeapTuple around, but a
slot (which in heap's case internally has that information).
Additionally a few infrastructure changes were needed:
I) SysScanDesc, as used by systable_{beginscan, getnext} et al. now
internally uses a slot to keep track of tuples. While
systable_getnext() still returns HeapTuples, and will so for the
foreseeable future, the index API (see 1) above) now only deals with
slots.
The remainder, and largest part, of this commit is then adjusting all
scans in postgres to use the new APIs.
Author: Andres Freund, Haribabu Kommi, Alvaro Herrera
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
2019-03-11 20:46:41 +01:00
|
|
|
scan = table_beginscan_catalog(classRel, 1, key);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
|
|
{
|
|
|
|
Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
Oid relid = relForm->oid;
|
2017-01-19 18:00:00 +01:00
|
|
|
|
2020-04-08 09:59:27 +02:00
|
|
|
if (is_publishable_class(relid, relForm) &&
|
|
|
|
!(relForm->relispartition && pubviaroot))
|
2017-01-19 18:00:00 +01:00
|
|
|
result = lappend_oid(result, relid);
|
|
|
|
}
|
|
|
|
|
tableam: Add and use scan APIs.
Too allow table accesses to be not directly dependent on heap, several
new abstractions are needed. Specifically:
1) Heap scans need to be generalized into table scans. Do this by
introducing TableScanDesc, which will be the "base class" for
individual AMs. This contains the AM independent fields from
HeapScanDesc.
The previous heap_{beginscan,rescan,endscan} et al. have been
replaced with a table_ version.
There's no direct replacement for heap_getnext(), as that returned
a HeapTuple, which is undesirable for a other AMs. Instead there's
table_scan_getnextslot(). But note that heap_getnext() lives on,
it's still used widely to access catalog tables.
This is achieved by new scan_begin, scan_end, scan_rescan,
scan_getnextslot callbacks.
2) The portion of parallel scans that's shared between backends need
to be able to do so without the user doing per-AM work. To achieve
that new parallelscan_{estimate, initialize, reinitialize}
callbacks are introduced, which operate on a new
ParallelTableScanDesc, which again can be subclassed by AMs.
As it is likely that several AMs are going to be block oriented,
block oriented callbacks that can be shared between such AMs are
provided and used by heap. table_block_parallelscan_{estimate,
intiialize, reinitialize} as callbacks, and
table_block_parallelscan_{nextpage, init} for use in AMs. These
operate on a ParallelBlockTableScanDesc.
3) Index scans need to be able to access tables to return a tuple, and
there needs to be state across individual accesses to the heap to
store state like buffers. That's now handled by introducing a
sort-of-scan IndexFetchTable, which again is intended to be
subclassed by individual AMs (for heap IndexFetchHeap).
The relevant callbacks for an AM are index_fetch_{end, begin,
reset} to create the necessary state, and index_fetch_tuple to
retrieve an indexed tuple. Note that index_fetch_tuple
implementations need to be smarter than just blindly fetching the
tuples for AMs that have optimizations similar to heap's HOT - the
currently alive tuple in the update chain needs to be fetched if
appropriate.
Similar to table_scan_getnextslot(), it's undesirable to continue
to return HeapTuples. Thus index_fetch_heap (might want to rename
that later) now accepts a slot as an argument. Core code doesn't
have a lot of call sites performing index scans without going
through the systable_* API (in contrast to loads of heap_getnext
calls and working directly with HeapTuples).
Index scans now store the result of a search in
IndexScanDesc->xs_heaptid, rather than xs_ctup->t_self. As the
target is not generally a HeapTuple anymore that seems cleaner.
To be able to sensible adapt code to use the above, two further
callbacks have been introduced:
a) slot_callbacks returns a TupleTableSlotOps* suitable for creating
slots capable of holding a tuple of the AMs
type. table_slot_callbacks() and table_slot_create() are based
upon that, but have additional logic to deal with views, foreign
tables, etc.
While this change could have been done separately, nearly all the
call sites that needed to be adapted for the rest of this commit
also would have been needed to be adapted for
table_slot_callbacks(), making separation not worthwhile.
b) tuple_satisfies_snapshot checks whether the tuple in a slot is
currently visible according to a snapshot. That's required as a few
places now don't have a buffer + HeapTuple around, but a
slot (which in heap's case internally has that information).
Additionally a few infrastructure changes were needed:
I) SysScanDesc, as used by systable_{beginscan, getnext} et al. now
internally uses a slot to keep track of tuples. While
systable_getnext() still returns HeapTuples, and will so for the
foreseeable future, the index API (see 1) above) now only deals with
slots.
The remainder, and largest part, of this commit is then adjusting all
scans in postgres to use the new APIs.
Author: Andres Freund, Haribabu Kommi, Alvaro Herrera
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
2019-03-11 20:46:41 +01:00
|
|
|
table_endscan(scan);
|
2020-04-08 09:59:27 +02:00
|
|
|
|
|
|
|
if (pubviaroot)
|
|
|
|
{
|
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
Anum_pg_class_relkind,
|
|
|
|
BTEqualStrategyNumber, F_CHAREQ,
|
|
|
|
CharGetDatum(RELKIND_PARTITIONED_TABLE));
|
|
|
|
|
|
|
|
scan = table_beginscan_catalog(classRel, 1, key);
|
|
|
|
|
|
|
|
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
|
|
{
|
|
|
|
Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
|
|
Oid relid = relForm->oid;
|
|
|
|
|
|
|
|
if (is_publishable_class(relid, relForm) &&
|
|
|
|
!relForm->relispartition)
|
|
|
|
result = lappend_oid(result, relid);
|
|
|
|
}
|
|
|
|
|
|
|
|
table_endscan(scan);
|
|
|
|
}
|
2017-01-19 18:00:00 +01:00
|
|
|
|
2020-04-11 09:44:14 +02:00
|
|
|
table_close(classRel, AccessShareLock);
|
2017-01-19 18:00:00 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
/*
|
|
|
|
* Gets the list of schema oids for a publication.
|
|
|
|
*
|
|
|
|
* This should only be used FOR ALL TABLES IN SCHEMA publications.
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
GetPublicationSchemas(Oid pubid)
|
|
|
|
{
|
|
|
|
List *result = NIL;
|
|
|
|
Relation pubschsrel;
|
|
|
|
ScanKeyData scankey;
|
|
|
|
SysScanDesc scan;
|
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
/* Find all schemas associated with the publication */
|
|
|
|
pubschsrel = table_open(PublicationNamespaceRelationId, AccessShareLock);
|
|
|
|
|
|
|
|
ScanKeyInit(&scankey,
|
|
|
|
Anum_pg_publication_namespace_pnpubid,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(pubid));
|
|
|
|
|
|
|
|
scan = systable_beginscan(pubschsrel,
|
|
|
|
PublicationNamespacePnnspidPnpubidIndexId,
|
|
|
|
true, NULL, 1, &scankey);
|
|
|
|
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
|
|
|
{
|
|
|
|
Form_pg_publication_namespace pubsch;
|
|
|
|
|
|
|
|
pubsch = (Form_pg_publication_namespace) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
result = lappend_oid(result, pubsch->pnnspid);
|
|
|
|
}
|
|
|
|
|
|
|
|
systable_endscan(scan);
|
|
|
|
table_close(pubschsrel, AccessShareLock);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Gets the list of publication oids associated with a specified schema.
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
GetSchemaPublications(Oid schemaid)
|
|
|
|
{
|
|
|
|
List *result = NIL;
|
|
|
|
CatCList *pubschlist;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Find all publications associated with the schema */
|
|
|
|
pubschlist = SearchSysCacheList1(PUBLICATIONNAMESPACEMAP,
|
|
|
|
ObjectIdGetDatum(schemaid));
|
|
|
|
for (i = 0; i < pubschlist->n_members; i++)
|
|
|
|
{
|
|
|
|
HeapTuple tup = &pubschlist->members[i]->tuple;
|
|
|
|
Oid pubid = ((Form_pg_publication_namespace) GETSTRUCT(tup))->pnpubid;
|
|
|
|
|
|
|
|
result = lappend_oid(result, pubid);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseSysCacheList(pubschlist);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the list of publishable relation oids for a specified schema.
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
GetSchemaPublicationRelations(Oid schemaid, PublicationPartOpt pub_partopt)
|
|
|
|
{
|
|
|
|
Relation classRel;
|
|
|
|
ScanKeyData key[1];
|
|
|
|
TableScanDesc scan;
|
|
|
|
HeapTuple tuple;
|
|
|
|
List *result = NIL;
|
|
|
|
|
|
|
|
Assert(OidIsValid(schemaid));
|
|
|
|
|
|
|
|
classRel = table_open(RelationRelationId, AccessShareLock);
|
|
|
|
|
|
|
|
ScanKeyInit(&key[0],
|
|
|
|
Anum_pg_class_relnamespace,
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
schemaid);
|
|
|
|
|
|
|
|
/* get all the relations present in the specified schema */
|
|
|
|
scan = table_beginscan_catalog(classRel, 1, key);
|
|
|
|
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
|
|
|
{
|
|
|
|
Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
|
|
|
|
Oid relid = relForm->oid;
|
|
|
|
char relkind;
|
|
|
|
|
|
|
|
if (!is_publishable_class(relid, relForm))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
relkind = get_rel_relkind(relid);
|
|
|
|
if (relkind == RELKIND_RELATION)
|
|
|
|
result = lappend_oid(result, relid);
|
|
|
|
else if (relkind == RELKIND_PARTITIONED_TABLE)
|
|
|
|
{
|
|
|
|
List *partitionrels = NIL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It is quite possible that some of the partitions are in a
|
|
|
|
* different schema than the parent table, so we need to get such
|
|
|
|
* partitions separately.
|
|
|
|
*/
|
|
|
|
partitionrels = GetPubPartitionOptionRelations(partitionrels,
|
|
|
|
pub_partopt,
|
|
|
|
relForm->oid);
|
|
|
|
result = list_concat_unique_oid(result, partitionrels);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
table_endscan(scan);
|
|
|
|
table_close(classRel, AccessShareLock);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Gets the list of all relations published by FOR ALL TABLES IN SCHEMA
|
|
|
|
* publication.
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
GetAllSchemaPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
|
|
|
|
{
|
|
|
|
List *result = NIL;
|
|
|
|
List *pubschemalist = GetPublicationSchemas(pubid);
|
|
|
|
ListCell *cell;
|
|
|
|
|
|
|
|
foreach(cell, pubschemalist)
|
|
|
|
{
|
|
|
|
Oid schemaid = lfirst_oid(cell);
|
|
|
|
List *schemaRels = NIL;
|
|
|
|
|
|
|
|
schemaRels = GetSchemaPublicationRelations(schemaid, pub_partopt);
|
|
|
|
result = list_concat(result, schemaRels);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-01-19 18:00:00 +01:00
|
|
|
/*
|
|
|
|
* Get publication using oid
|
|
|
|
*
|
2017-04-26 18:04:44 +02:00
|
|
|
* The Publication struct and its data are palloc'ed here.
|
2017-01-19 18:00:00 +01:00
|
|
|
*/
|
|
|
|
Publication *
|
|
|
|
GetPublication(Oid pubid)
|
|
|
|
{
|
|
|
|
HeapTuple tup;
|
|
|
|
Publication *pub;
|
|
|
|
Form_pg_publication pubform;
|
|
|
|
|
|
|
|
tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
|
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
elog(ERROR, "cache lookup failed for publication %u", pubid);
|
|
|
|
|
|
|
|
pubform = (Form_pg_publication) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
pub = (Publication *) palloc(sizeof(Publication));
|
|
|
|
pub->oid = pubid;
|
|
|
|
pub->name = pstrdup(NameStr(pubform->pubname));
|
|
|
|
pub->alltables = pubform->puballtables;
|
|
|
|
pub->pubactions.pubinsert = pubform->pubinsert;
|
|
|
|
pub->pubactions.pubupdate = pubform->pubupdate;
|
|
|
|
pub->pubactions.pubdelete = pubform->pubdelete;
|
2018-04-07 17:24:53 +02:00
|
|
|
pub->pubactions.pubtruncate = pubform->pubtruncate;
|
2020-04-08 09:59:27 +02:00
|
|
|
pub->pubviaroot = pubform->pubviaroot;
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
|
|
|
return pub;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get Publication using name.
|
|
|
|
*/
|
|
|
|
Publication *
|
|
|
|
GetPublicationByName(const char *pubname, bool missing_ok)
|
|
|
|
{
|
|
|
|
Oid oid;
|
|
|
|
|
2019-12-23 16:47:36 +01:00
|
|
|
oid = get_publication_oid(pubname, missing_ok);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
2019-12-23 16:47:36 +01:00
|
|
|
return OidIsValid(oid) ? GetPublication(oid) : NULL;
|
2017-01-19 18:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_publication_oid - given a publication name, look up the OID
|
|
|
|
*
|
|
|
|
* If missing_ok is false, throw an error if name not found. If true, just
|
|
|
|
* return InvalidOid.
|
|
|
|
*/
|
|
|
|
Oid
|
|
|
|
get_publication_oid(const char *pubname, bool missing_ok)
|
|
|
|
{
|
|
|
|
Oid oid;
|
|
|
|
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
|
|
|
oid = GetSysCacheOid1(PUBLICATIONNAME, Anum_pg_publication_oid,
|
|
|
|
CStringGetDatum(pubname));
|
2017-01-19 18:00:00 +01:00
|
|
|
if (!OidIsValid(oid) && !missing_ok)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("publication \"%s\" does not exist", pubname)));
|
|
|
|
return oid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_publication_name - given a publication Oid, look up the name
|
2018-09-18 05:00:18 +02:00
|
|
|
*
|
|
|
|
* If missing_ok is false, throw an error if name not found. If true, just
|
|
|
|
* return NULL.
|
2017-01-19 18:00:00 +01:00
|
|
|
*/
|
|
|
|
char *
|
2018-09-18 05:00:18 +02:00
|
|
|
get_publication_name(Oid pubid, bool missing_ok)
|
2017-01-19 18:00:00 +01:00
|
|
|
{
|
|
|
|
HeapTuple tup;
|
|
|
|
char *pubname;
|
|
|
|
Form_pg_publication pubform;
|
|
|
|
|
|
|
|
tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
|
|
|
|
|
|
|
|
if (!HeapTupleIsValid(tup))
|
2018-09-18 05:00:18 +02:00
|
|
|
{
|
|
|
|
if (!missing_ok)
|
|
|
|
elog(ERROR, "cache lookup failed for publication %u", pubid);
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
pubform = (Form_pg_publication) GETSTRUCT(tup);
|
|
|
|
pubname = pstrdup(NameStr(pubform->pubname));
|
|
|
|
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
|
|
|
return pubname;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns Oids of tables in a publication.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_get_publication_tables(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
FuncCallContext *funcctx;
|
|
|
|
char *pubname = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
|
|
|
Publication *publication;
|
|
|
|
List *tables;
|
|
|
|
|
|
|
|
/* stuff done only on the first call of the function */
|
|
|
|
if (SRF_IS_FIRSTCALL())
|
|
|
|
{
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
/* create a function context for cross-call persistence */
|
|
|
|
funcctx = SRF_FIRSTCALL_INIT();
|
|
|
|
|
|
|
|
/* switch to memory context appropriate for multiple function calls */
|
|
|
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
|
|
|
|
|
|
|
publication = GetPublicationByName(pubname, false);
|
2020-03-10 08:42:59 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Publications support partitioned tables, although all changes are
|
|
|
|
* replicated using leaf partition identity and schema, so we only
|
|
|
|
* need those.
|
|
|
|
*/
|
2017-01-19 18:00:00 +01:00
|
|
|
if (publication->alltables)
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
{
|
2020-04-08 09:59:27 +02:00
|
|
|
tables = GetAllTablesPublicationRelations(publication->pubviaroot);
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
}
|
2017-01-19 18:00:00 +01:00
|
|
|
else
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
{
|
|
|
|
List *relids,
|
|
|
|
*schemarelids;
|
|
|
|
|
|
|
|
relids = GetPublicationRelations(publication->oid,
|
2020-04-08 09:59:27 +02:00
|
|
|
publication->pubviaroot ?
|
|
|
|
PUBLICATION_PART_ROOT :
|
2020-03-10 08:42:59 +01:00
|
|
|
PUBLICATION_PART_LEAF);
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
schemarelids = GetAllSchemaPublicationRelations(publication->oid,
|
|
|
|
publication->pubviaroot ?
|
|
|
|
PUBLICATION_PART_ROOT :
|
|
|
|
PUBLICATION_PART_LEAF);
|
|
|
|
tables = list_concat_unique_oid(relids, schemarelids);
|
2021-12-09 04:06:59 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the publication publishes partition changes via their
|
|
|
|
* respective root partitioned tables, we must exclude partitions
|
|
|
|
* in favor of including the root partitioned tables. Otherwise,
|
|
|
|
* the function could return both the child and parent tables
|
|
|
|
* which could cause data of the child table to be
|
|
|
|
* double-published on the subscriber side.
|
|
|
|
*/
|
|
|
|
if (publication->pubviaroot)
|
|
|
|
tables = filter_partitions(tables);
|
Allow publishing the tables of schema.
A new option "FOR ALL TABLES IN SCHEMA" in Create/Alter Publication allows
one or more schemas to be specified, whose tables are selected by the
publisher for sending the data to the subscriber.
The new syntax allows specifying both the tables and schemas. For example:
CREATE PUBLICATION pub1 FOR TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
OR
ALTER PUBLICATION pub1 ADD TABLE t1,t2,t3, ALL TABLES IN SCHEMA s1,s2;
A new system table "pg_publication_namespace" has been added, to maintain
the schemas that the user wants to publish through the publication.
Modified the output plugin (pgoutput) to publish the changes if the
relation is part of schema publication.
Updates pg_dump to identify and dump schema publications. Updates the \d
family of commands to display schema publications and \dRp+ variant will
now display associated schemas if any.
Author: Vignesh C, Hou Zhijie, Amit Kapila
Syntax-Suggested-by: Tom Lane, Alvaro Herrera
Reviewed-by: Greg Nancarrow, Masahiko Sawada, Hou Zhijie, Amit Kapila, Haiying Tang, Ajin Cherian, Rahila Syed, Bharath Rupireddy, Mark Dilger
Tested-by: Haiying Tang
Discussion: https://www.postgresql.org/message-id/CALDaNm0OANxuJ6RXqwZsM1MSY4s19nuH3734j4a72etDwvBETQ@mail.gmail.com
2021-10-27 04:14:52 +02:00
|
|
|
}
|
|
|
|
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
funcctx->user_fctx = (void *) tables;
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stuff done on every call of the function */
|
|
|
|
funcctx = SRF_PERCALL_SETUP();
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
tables = (List *) funcctx->user_fctx;
|
2017-01-19 18:00:00 +01:00
|
|
|
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
if (funcctx->call_cntr < list_length(tables))
|
2017-01-19 18:00:00 +01:00
|
|
|
{
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
Oid relid = list_nth_oid(tables, funcctx->call_cntr);
|
2017-01-19 18:00:00 +01:00
|
|
|
|
|
|
|
SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(relid));
|
|
|
|
}
|
|
|
|
|
|
|
|
SRF_RETURN_DONE(funcctx);
|
|
|
|
}
|