From ed61637425713363ff147a1ef389c5583c0a872a Mon Sep 17 00:00:00 2001 From: Hari Babu Date: Wed, 18 Apr 2018 19:46:42 +1000 Subject: [PATCH 15/16] External relation infrastructure Extensions can create an external relation in pg_class and use it for their internal functionality and these tables cannot be queried directly from SQL commands. These tables are not visible from psql \d commands and also these are not dumped by the pg_dump. we may need to enhance pg_dump to handle these external relations for pg_upgrade. --- contrib/pageinspect/rawpage.c | 6 ++++++ contrib/pgstattuple/pgstattuple.c | 3 +++ src/backend/access/common/reloptions.c | 1 + src/backend/catalog/heap.c | 3 ++- src/backend/catalog/namespace.c | 6 ++++++ src/backend/catalog/objectaddress.c | 7 +++++++ src/backend/executor/execMain.c | 6 ++++++ src/backend/parser/parse_relation.c | 6 ++++++ src/backend/utils/adt/dbsize.c | 2 ++ src/backend/utils/cache/relcache.c | 7 +++++-- src/include/catalog/pg_class.h | 1 + 11 files changed, 45 insertions(+), 3 deletions(-) diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c index d7bf782ccd..af211ad1fd 100644 --- a/contrib/pageinspect/rawpage.c +++ b/contrib/pageinspect/rawpage.c @@ -133,6 +133,12 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno) (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot get raw page from partitioned index \"%s\"", RelationGetRelationName(rel)))); + if (rel->rd_rel->relkind == RELKIND_EXTERNAL) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot get raw page from external table \"%s\"", + RelationGetRelationName(rel)))); + /* * Reject attempts to read non-local temporary relations; we would be diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index bd022e031a..f61316a4ed 100644 --- a/contrib/pgstattuple/pgstattuple.c +++ b/contrib/pgstattuple/pgstattuple.c @@ -299,6 +299,9 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo) case RELKIND_PARTITIONED_INDEX: err = "partitioned index"; break; + case RELKIND_EXTERNAL: + err = "external table"; + break; default: err = "unknown"; break; diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index e0c9c3431c..fc5eea0ebc 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -1014,6 +1014,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, options = index_reloptions(amoptions, datum, false); break; case RELKIND_FOREIGN_TABLE: + case RELKIND_EXTERNAL: options = NULL; break; default: diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index a984c4a98a..8c7a06f3b5 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -1396,7 +1396,8 @@ heap_create_init_fork(Relation rel) { Assert(rel->rd_rel->relkind == RELKIND_RELATION || rel->rd_rel->relkind == RELKIND_MATVIEW || - rel->rd_rel->relkind == RELKIND_TOASTVALUE); + rel->rd_rel->relkind == RELKIND_TOASTVALUE || + rel->rd_rel->relkind == RELKIND_EXTERNAL); RelationOpenSmgr(rel); smgrcreate(rel->rd_smgr, INIT_FORKNUM, false); log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM); diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 0f67a122ed..0c46372a87 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -710,6 +710,12 @@ RelationIsVisible(Oid relid) elog(ERROR, "cache lookup failed for relation %u", relid); relform = (Form_pg_class) GETSTRUCT(reltup); + if (relform->relkind == RELKIND_EXTERNAL) + { + ReleaseSysCache(reltup); + return false; + } + recomputeNamespacePath(); /* diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index ad682673e6..db8c66ff2f 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -3654,6 +3654,10 @@ getRelationDescription(StringInfo buffer, Oid relid) appendStringInfo(buffer, _("foreign table %s"), relname); break; + case RELKIND_EXTERNAL: + appendStringInfo(buffer, _("external table %s"), + relname); + break; default: /* shouldn't get here */ appendStringInfo(buffer, _("relation %s"), @@ -4122,6 +4126,9 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId) case RELKIND_FOREIGN_TABLE: appendStringInfoString(buffer, "foreign table"); break; + case RELKIND_EXTERNAL: + appendStringInfoString(buffer, "external table"); + break; default: /* shouldn't get here */ appendStringInfoString(buffer, "relation"); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 745a9fa491..9aec828f71 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1222,6 +1222,12 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation) break; } break; + case RELKIND_EXTERNAL: + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot change external table \"%s\"", + RelationGetRelationName(resultRel)))); + break; default: ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index bf5df26009..f11388f492 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -1218,6 +1218,12 @@ addRangeTableEntry(ParseState *pstate, rte->relid = RelationGetRelid(rel); rte->relkind = rel->rd_rel->relkind; + if (rte->relkind == RELKIND_EXTERNAL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Cannot execute SQL queries on external tables"), + parser_errposition(pstate, exprLocation((Node *)relation)))); + /* * Build the list of effective column names using user-supplied aliases * and/or actual column names. diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index 07e5e78caa..a5e9a71976 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -881,6 +881,7 @@ pg_relation_filenode(PG_FUNCTION_ARGS) case RELKIND_INDEX: case RELKIND_SEQUENCE: case RELKIND_TOASTVALUE: + case RELKIND_EXTERNAL: /* okay, these have storage */ if (relform->relfilenode) result = relform->relfilenode; @@ -958,6 +959,7 @@ pg_relation_filepath(PG_FUNCTION_ARGS) case RELKIND_INDEX: case RELKIND_SEQUENCE: case RELKIND_TOASTVALUE: + case RELKIND_EXTERNAL: /* okay, these have storage */ /* This logic should match RelationInitPhysicalAddr */ diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 75475060f9..4565e659f8 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -1217,6 +1217,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) case RELKIND_MATVIEW: case RELKIND_PARTITIONED_TABLE: case RELKIND_FOREIGN_TABLE: /* hari FIXME :To support COPY on foreign tables */ + case RELKIND_EXTERNAL: RelationInitTableAccessMethod(relation); break; default: @@ -3373,7 +3374,8 @@ RelationBuildLocalRelation(const char *relname, relkind == RELKIND_VIEW || /* Not exactly the storage, but underlying * tuple access, it is required */ relkind == RELKIND_PARTITIONED_TABLE || - relkind == RELKIND_TOASTVALUE) + relkind == RELKIND_TOASTVALUE || + relkind == RELKIND_EXTERNAL) RelationInitTableAccessMethod(rel); /* @@ -3902,7 +3904,8 @@ RelationCacheInitializePhase3(void) relation->rd_rel->relkind == RELKIND_MATVIEW || relation->rd_rel->relkind == RELKIND_VIEW || relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE || - relation->rd_rel->relkind == RELKIND_TOASTVALUE)) + relation->rd_rel->relkind == RELKIND_TOASTVALUE || + relation->rd_rel->relkind == RELKIND_EXTERNAL)) { RelationInitTableAccessMethod(relation); Assert(relation->rd_tableamroutine != NULL); diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index dc6c415c58..4a98562ec4 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -104,6 +104,7 @@ typedef FormData_pg_class *Form_pg_class; #define RELKIND_FOREIGN_TABLE 'f' /* foreign table */ #define RELKIND_PARTITIONED_TABLE 'p' /* partitioned table */ #define RELKIND_PARTITIONED_INDEX 'I' /* partitioned index */ +#define RELKIND_EXTERNAL 'E' /* External table */ #define RELPERSISTENCE_PERMANENT 'p' /* regular table */ #define RELPERSISTENCE_UNLOGGED 'u' /* unlogged permanent table */ -- 2.16.1.windows.4