Fix internal schema publish.

This commit is contained in:
TotaJ
2022-03-28 10:20:46 +08:00
parent 472a7d66ff
commit 45b0f39326
3 changed files with 105 additions and 17 deletions

View File

@ -43,6 +43,40 @@
#include "utils/rel.h"
#include "utils/syscache.h"
/* check if namespace is internal schema, internal schema doesn't need publish */
static inline bool IsInternalSchema(Oid relnamespace)
{
Assert(CSTORE_NAMESPACE < PG_PKG_SERVICE_NAMESPACE);
Assert(PG_PKG_SERVICE_NAMESPACE < PG_DBEPERF_NAMESPACE);
Assert(PG_DBEPERF_NAMESPACE < PG_SNAPSHOT_NAMESPACE);
Assert(PG_SNAPSHOT_NAMESPACE < PG_BLOCKCHAIN_NAMESPACE);
Assert(PG_BLOCKCHAIN_NAMESPACE < PG_DB4AI_NAMESPACE);
Assert(PG_DB4AI_NAMESPACE < PG_PLDEBUG_NAMESPACE);
#ifndef ENABLE_MULTIPLE_NODES
Assert(PG_PLDEBUG_NAMESPACE < DBE_PLDEVELOPER_NAMESPACE);
Assert(DBE_PLDEVELOPER_NAMESPACE < PG_SQLADVISOR_NAMESPACE);
#else
Assert(PG_PLDEBUG_NAMESPACE < PG_SQLADVISOR_NAMESPACE);
#endif
/* please make sure the list is ordered */
static Oid internalSchemaList[] = {
CSTORE_NAMESPACE,
PG_PKG_SERVICE_NAMESPACE,
PG_DBEPERF_NAMESPACE,
PG_SNAPSHOT_NAMESPACE,
PG_BLOCKCHAIN_NAMESPACE,
PG_DB4AI_NAMESPACE,
PG_PLDEBUG_NAMESPACE,
#ifndef ENABLE_MULTIPLE_NODES
DBE_PLDEVELOPER_NAMESPACE,
#endif
PG_SQLADVISOR_NAMESPACE
};
static size_t count = lengthof(internalSchemaList);
return bsearch(&relnamespace, &internalSchemaList, count, sizeof(Oid), oid_cmp) != NULL;
}
/*
* Check if relation can be in given publication and throws appropriate
* error if not.
@ -66,6 +100,19 @@ static void check_publication_add_relation(Relation targetrel)
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("table \"%s\" cannot be replicated", RelationGetRelationName(targetrel)),
errdetail("Temporary and unlogged relations cannot be replicated.")));
if (IsInternalSchema(targetrel->rd_rel->relnamespace)) {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("\"%s\" is in internal schema", RelationGetRelationName(targetrel)),
errdetail("\"%s\" is a internal schema, table in this schema cannot be replicated.",
get_namespace_name(RelationGetNamespace(targetrel)))));
}
if (!RelationIsRowFormat(targetrel)) {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("\"%s\" is not a row table", RelationGetRelationName(targetrel)),
errdetail("Only row tables can be added to publications.")));
}
}
/*
@ -102,30 +149,43 @@ static Publication *GetPublication(Oid pubid)
* 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
* Does same checks as check_publication_add_relation, but does not need relation to be opened
* and also does not throw errors.
*/
static bool is_publishable_class(Oid relid, Form_pg_class reltuple)
static bool is_publishable_class(Oid relid, HeapTuple tuple, Relation rel)
{
/* internal namespace, doesn't need to publish */
if (reltuple->relnamespace == CSTORE_NAMESPACE || reltuple->relnamespace == PG_PKG_SERVICE_NAMESPACE ||
#ifndef ENABLE_MULTIPLE_NODES
reltuple->relnamespace == DBE_PLDEVELOPER_NAMESPACE ||
#endif
reltuple->relnamespace == PG_SNAPSHOT_NAMESPACE || reltuple->relnamespace == PG_SQLADVISOR_NAMESPACE ||
reltuple->relnamespace == PG_BLOCKCHAIN_NAMESPACE || reltuple->relnamespace == PG_DB4AI_NAMESPACE ||
reltuple->relnamespace == PG_PLDEBUG_NAMESPACE) {
return false;
Form_pg_class reltuple = NULL;
if (rel != NULL) {
reltuple = rel->rd_rel;
} else if (tuple != NULL) {
reltuple = (Form_pg_class)GETSTRUCT(tuple);
} else {
/* should not happen */
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("null input of pg_class heap tuple or relation, oid: %u", relid)));
}
return reltuple->relkind == RELKIND_RELATION && !IsCatalogClass(relid, reltuple) &&
reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
if (IsInternalSchema(reltuple->relnamespace) || reltuple->relkind != RELKIND_RELATION ||
IsCatalogClass(relid, reltuple) || reltuple->relpersistence != RELPERSISTENCE_PERMANENT ||
/*
* Also exclude any tables created as part of initdb. This mainly
* affects the preinstalled information_schema.
* Note that IsCatalogClass() only checks for these inside pg_catalog
* and toast schemas.
*/
relid >= FirstNormalObjectId;
relid < FirstNormalObjectId) {
return false;
}
/* check whether is row table */
bool isRowTable = true;
if (rel != NULL) {
isRowTable = RelationIsRowFormat(rel);
} else {
/* already checkd tuple before */
isRowTable = CheckRelOrientationByPgClassTuple(tuple, GetDefaultPgClassDesc(), ORIENTATION_ROW);
}
return isRowTable;
}
/*
@ -314,9 +374,9 @@ static List *GetAllTablesPublicationRelations(void)
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) {
Oid relid = HeapTupleGetOid(tuple);
Form_pg_class relForm = (Form_pg_class)GETSTRUCT(tuple);
if (is_publishable_class(relid, relForm))
if (is_publishable_class(relid, tuple, NULL)) {
result = lappend_oid(result, relid);
}
}
heap_endscan(scan);
@ -432,5 +492,5 @@ Datum pg_get_publication_tables(PG_FUNCTION_ARGS)
*/
bool is_publishable_relation(Relation rel)
{
return is_publishable_class(RelationGetRelid(rel), rel->rd_rel);
return is_publishable_class(RelationGetRelid(rel), NULL, rel);
}

View File

@ -16,10 +16,15 @@ SET SESSION AUTHORIZATION 'regress_publication_user' PASSWORD 'Abcdef@123';
CREATE TABLE testpub_tbl1 (id int primary key, data text);
CREATE TABLE testpub_tbl2 (id int primary key, data text);
CREATE TABLE testpub_tbl3 (id int primary key, data text);
CREATE TABLE testpub_tbl_col(id int) WITH (orientation=column);
--- create publication
CREATE PUBLICATION testpub_default;
------ for all tables
CREATE PUBLICATION testpub_foralltables FOR ALL TABLES;
------ after create all table publication, do IUD to non-pk column table, should ok
INSERT INTO testpub_tbl_col values(1);
UPDATE testpub_tbl_col set id = 66 where id = 1;
DELETE FROM testpub_tbl_col;
CREATE TABLE testpub_tbl4 (id int primary key, data text);
select pubname, tablename from pg_publication_tables where pubname='testpub_foralltables' AND tablename like 'testpub_%' order by tablename;
------ for only table testpub_tbl1
@ -52,6 +57,11 @@ ALTER PUBLICATION testpub_default SET TABLE testpub_tbl2;
select pubname, tablename from pg_publication_tables where pubname='testpub_default';
------ drop table
ALTER PUBLICATION testpub_multitbls DROP TABLE ONLY testpub_tbl2;
------ fail - add column table
ALTER PUBLICATION testpub_multitbls ADD TABLE testpub_tbl_col;
------ fail - add internal schema table
ALTER PUBLICATION testpub_multitbls ADD TABLE db4ai.snapshot;
ALTER PUBLICATION testpub_multitbls ADD TABLE dbe_pldeveloper.gs_source;
select pubname, tablename from pg_publication_tables where pubname='testpub_multitbls';
------ SET (parameter xxx)
ALTER PUBLICATION testpub_default SET (publish='insert, delete');
@ -77,6 +87,7 @@ DROP PUBLICATION IF EXISTS testpub_nonexists;
DROP TABLE testpub_tbl2;
DROP TABLE testpub_tbl3;
DROP TABLE testpub_tbl4;
DROP TABLE testpub_tbl_col;
DROP VIEW testpub_view;
DROP PUBLICATION IF EXISTS testpub_default;
DROP PUBLICATION IF EXISTS testpub_only_tbl1;

View File

@ -47,10 +47,15 @@ CREATE TABLE testpub_tbl2 (id int primary key, data text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "testpub_tbl2_pkey" for table "testpub_tbl2"
CREATE TABLE testpub_tbl3 (id int primary key, data text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "testpub_tbl3_pkey" for table "testpub_tbl3"
CREATE TABLE testpub_tbl_col(id int) WITH (orientation=column);
--- create publication
CREATE PUBLICATION testpub_default;
------ for all tables
CREATE PUBLICATION testpub_foralltables FOR ALL TABLES;
------ after create all table publication, do IUD to non-pk column table, should ok
INSERT INTO testpub_tbl_col values(1);
UPDATE testpub_tbl_col set id = 66 where id = 1;
DELETE FROM testpub_tbl_col;
CREATE TABLE testpub_tbl4 (id int primary key, data text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "testpub_tbl4_pkey" for table "testpub_tbl4"
select pubname, tablename from pg_publication_tables where pubname='testpub_foralltables' AND tablename like 'testpub_%' order by tablename;
@ -122,6 +127,17 @@ select pubname, tablename from pg_publication_tables where pubname='testpub_defa
------ drop table
ALTER PUBLICATION testpub_multitbls DROP TABLE ONLY testpub_tbl2;
------ fail - add column table
ALTER PUBLICATION testpub_multitbls ADD TABLE testpub_tbl_col;
ERROR: "testpub_tbl_col" is not a row table
DETAIL: Only row tables can be added to publications.
------ fail - add internal schema table
ALTER PUBLICATION testpub_multitbls ADD TABLE db4ai.snapshot;
ERROR: "snapshot" is in internal schema
DETAIL: "db4ai" is a internal schema, table in this schema cannot be replicated.
ALTER PUBLICATION testpub_multitbls ADD TABLE dbe_pldeveloper.gs_source;
ERROR: "gs_source" is in internal schema
DETAIL: "dbe_pldeveloper" is a internal schema, table in this schema cannot be replicated.
select pubname, tablename from pg_publication_tables where pubname='testpub_multitbls';
pubname | tablename
-------------------+--------------
@ -172,6 +188,7 @@ NOTICE: publication "testpub_nonexists" does not exist, skipping, skipping
DROP TABLE testpub_tbl2;
DROP TABLE testpub_tbl3;
DROP TABLE testpub_tbl4;
DROP TABLE testpub_tbl_col;
DROP VIEW testpub_view;
DROP PUBLICATION IF EXISTS testpub_default;
DROP PUBLICATION IF EXISTS testpub_only_tbl1;