Fix internal schema publish.
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Reference in New Issue
Block a user