From b32355c36314ffc801b458b2d672f0d84f230fa5 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Fri, 31 Aug 2018 16:54:53 +0900 Subject: [PATCH 1/2] PoC: Support ROUTINE MAPPING. --- src/backend/catalog/Makefile | 2 +- src/backend/catalog/dependency.c | 9 ++ src/backend/catalog/objectaddress.c | 45 +++++++ src/backend/commands/alter.c | 1 + src/backend/commands/event_trigger.c | 2 + src/backend/commands/foreigncmds.c | 216 +++++++++++++++++++++++++++++++ src/backend/commands/tablecmds.c | 1 + src/backend/foreign/foreign.c | 61 +++++++++ src/backend/parser/gram.y | 115 +++++++++++++++- src/backend/tcop/utility.c | 32 +++++ src/backend/utils/cache/lsyscache.c | 3 +- src/backend/utils/cache/syscache.c | 34 +++++ src/include/catalog/dependency.h | 1 + src/include/catalog/indexing.h | 7 + src/include/catalog/pg_routine_mapping.h | 45 +++++++ src/include/commands/defrem.h | 4 + src/include/foreign/foreign.h | 10 ++ src/include/nodes/nodes.h | 3 + src/include/nodes/parsenodes.h | 29 +++++ src/include/parser/kwlist.h | 2 +- src/include/utils/syscache.h | 3 + 21 files changed, 616 insertions(+), 9 deletions(-) create mode 100644 src/include/catalog/pg_routine_mapping.h diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 0865240..0ba23e5 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -42,7 +42,7 @@ CATALOG_HEADERS := \ pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ pg_ts_parser.h pg_ts_template.h pg_extension.h \ pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ - pg_foreign_table.h pg_policy.h pg_replication_origin.h \ + pg_routine_mapping.h pg_foreign_table.h pg_policy.h pg_replication_origin.h \ pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \ pg_collation.h pg_partitioned_table.h pg_range.h pg_transform.h \ pg_sequence.h pg_publication.h pg_publication_rel.h pg_subscription.h \ diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 4f1d365..046c839 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -48,6 +48,7 @@ #include "catalog/pg_publication.h" #include "catalog/pg_publication_rel.h" #include "catalog/pg_rewrite.h" +#include "catalog/pg_routine_mapping.h" #include "catalog/pg_statistic_ext.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" @@ -163,6 +164,7 @@ static const Oid object_classes[] = { ForeignDataWrapperRelationId, /* OCLASS_FDW */ ForeignServerRelationId, /* OCLASS_FOREIGN_SERVER */ UserMappingRelationId, /* OCLASS_USER_MAPPING */ + RoutineMappingRelationId, /* OCLASS_ROUTINE_MAPPING */ DefaultAclRelationId, /* OCLASS_DEFACL */ ExtensionRelationId, /* OCLASS_EXTENSION */ EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */ @@ -1252,6 +1254,10 @@ doDeletion(const ObjectAddress *object, int flags) RemoveUserMappingById(object->objectId); break; + case OCLASS_ROUTINE_MAPPING: + RemoveRoutineMappingById(object->objectId); + break; + case OCLASS_DEFACL: RemoveDefaultACLById(object->objectId); break; @@ -2514,6 +2520,9 @@ getObjectClass(const ObjectAddress *object) case UserMappingRelationId: return OCLASS_USER_MAPPING; + case RoutineMappingRelationId: + return OCLASS_ROUTINE_MAPPING; + case DefaultAclRelationId: return OCLASS_DEFACL; diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 7db942d..2a40731 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -47,6 +47,7 @@ #include "catalog/pg_publication.h" #include "catalog/pg_publication_rel.h" #include "catalog/pg_rewrite.h" +#include "catalog/pg_routine_mapping.h" #include "catalog/pg_statistic_ext.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" @@ -3339,6 +3340,25 @@ getObjectDescription(const ObjectAddress *object) break; } + case OCLASS_ROUTINE_MAPPING: + { + HeapTuple tup; + Oid funcid; + Form_pg_routine_mapping rmform; + + tup = SearchSysCache1(ROUTINEMAPPINGOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for routine mapping %u", + object->objectId); + rmform = (Form_pg_routine_mapping) GETSTRUCT(tup); + funcid = rmform->rmproc; + + ReleaseSysCache(tup); + appendStringInfoString(&buffer, NameStr(rmform->rmname)); + break; + } + case OCLASS_DEFACL: { Relation defaclrel; @@ -4038,6 +4058,10 @@ getObjectTypeDescription(const ObjectAddress *object) appendStringInfoString(&buffer, "user mapping"); break; + case OCLASS_ROUTINE_MAPPING: + appendStringInfoString(&buffer, "routine mapping"); + break; + case OCLASS_DEFACL: appendStringInfoString(&buffer, "default acl"); break; @@ -4897,6 +4921,27 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case OCLASS_ROUTINE_MAPPING: + { + HeapTuple tup; + Form_pg_routine_mapping rmform; + + tup = SearchSysCache1(ROUTINEMAPPINGOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for routine mapping %u", + object->objectId); + rmform = (Form_pg_routine_mapping) GETSTRUCT(tup); + + ReleaseSysCache(tup); + + if (objname) + *objname = list_make1(pstrdup(NameStr(rmform->rmname))); + + appendStringInfoString(&buffer, NameStr(rmform->rmname)); + break; + } + case OCLASS_DEFACL: { Relation defaclrel; diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index eff325c..5352470 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -623,6 +623,7 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, case OCLASS_FDW: case OCLASS_FOREIGN_SERVER: case OCLASS_USER_MAPPING: + case OCLASS_ROUTINE_MAPPING: case OCLASS_DEFACL: case OCLASS_EXTENSION: case OCLASS_EVENT_TRIGGER: diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index eecc85d..dd174cd 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -110,6 +110,7 @@ static event_trigger_support_data event_trigger_support[] = { {"PUBLICATION", true}, {"ROLE", false}, {"ROUTINE", true}, + {"ROUTINE MAPPING", true}, {"RULE", true}, {"SCHEMA", true}, {"SEQUENCE", true}, @@ -1202,6 +1203,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass) case OCLASS_FDW: case OCLASS_FOREIGN_SERVER: case OCLASS_USER_MAPPING: + case OCLASS_ROUTINE_MAPPING: case OCLASS_DEFACL: case OCLASS_EXTENSION: case OCLASS_POLICY: diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index e5dd995..e84f011 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -26,6 +26,7 @@ #include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "catalog/pg_user_mapping.h" +#include "catalog/pg_routine_mapping.h" #include "commands/defrem.h" #include "foreign/fdwapi.h" #include "foreign/foreign.h" @@ -1662,3 +1663,218 @@ import_error_callback(void *arg) errcontext("importing foreign table \"%s\"", callback_arg->tablename); } + +/* + * Create rouitne mapping + */ +ObjectAddress +CreateRoutineMapping(CreateRoutineMappingStmt *stmt) +{ + Relation rel; + Datum options; + Datum values[Natts_pg_routine_mapping]; + bool nulls[Natts_pg_routine_mapping]; + Oid rmId; + Oid funcId; + NameData procname; + HeapTuple tuple; + ObjectAddress myself; + ObjectAddress referenced; + ForeignServer *srv; + ForeignDataWrapper *fdw; + + rel = heap_open(RoutineMappingRelationId, RowExclusiveLock); + + funcId = LookupFuncWithArgs(stmt->objtype, stmt->func, false); + + /* @@@: acl check */ + + if (GetRoutineMappingByName(stmt->name, true) != NULL) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("routine mapping \"%s\" already exists", + stmt->name))); + + srv = GetForeignServerByName(stmt->servername, false); + rmId = GetSysCacheOid2(ROUTINEMAPPINGPROCSERVER, + ObjectIdGetDatum(funcId), + ObjectIdGetDatum(srv->serverid)); + + if (OidIsValid(rmId)) + { + if (stmt->if_not_exists) + { + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("rouitne mapping for \"%s\" already exists for server %s, skipping", + NameListToString(stmt->func->objname), stmt->servername))); + return InvalidObjectAddress; + } + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("routine mapping for \"%s\" already exists for server %s", + NameListToString(stmt->func->objname), stmt->servername))); + } + + fdw = GetForeignDataWrapper(srv->fdwid); + + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(values)); + + namestrcpy(&procname, stmt->name); + values[Anum_pg_routine_mapping_rmname - 1] = NameGetDatum(&procname); + values[Anum_pg_routine_mapping_rmproc - 1] = ObjectIdGetDatum(funcId); + values[Anum_pg_routine_mapping_rmserver - 1] = ObjectIdGetDatum(srv->serverid); + + options = transformGenericOptions(RoutineMappingRelationId, + PointerGetDatum(NULL), + stmt->options, + fdw->fdwvalidator); + + if (PointerIsValid(DatumGetPointer(options))) + values[Anum_pg_routine_mapping_rmoptions - 1] = options; + else + nulls[Anum_pg_routine_mapping_rmoptions - 1] = true; + + tuple = heap_form_tuple(rel->rd_att, values, nulls); + + rmId = CatalogTupleInsert(rel, tuple); + + /* Add dependency on the server and proc */ + myself.classId = RoutineMappingRelationId; + myself.objectId = rmId; + myself.objectSubId = 0; + + referenced.classId = ForeignServerRelationId; + referenced.objectId = srv->serverid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* Post creation hook for new user mapping */ + InvokeObjectPostCreateHook(RoutineMappingRelationId, rmId, 0); + + heap_close(rel, RowExclusiveLock); + + return myself; +} + +Oid +RemoveRoutineMapping(DropRoutineMappingStmt *stmt) +{ + RoutineMapping *rm; + ObjectAddress object; + Oid rmId; + + rm = GetRoutineMappingByName(stmt->name, true); + + if (!rm) + { + if (!stmt->missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("routine mapping \"%s\" does not exist", + stmt->name))); + + ereport(NOTICE, + (errcode(ERRCODE_UNDEFINED_OBJECT), + (errmsg("routine mapping \"%s\" done not exist, skipping", + stmt->name)))); + return InvalidOid; + } + + rmId = rm->rmid; + + object.classId = RoutineMappingRelationId; + object.objectId = rm->rmid; + object.objectSubId = 0; + + performDeletion(&object, DROP_CASCADE, 0); + + return rmId; +} + +void +RemoveRoutineMappingById(Oid rmId) +{ + HeapTuple tp; + Relation rel; + + rel = heap_open(RoutineMappingRelationId, RowExclusiveLock); + + tp = SearchSysCache1(ROUTINEMAPPINGOID, ObjectIdGetDatum(rmId)); + + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for routine mapping %u", rmId); + + CatalogTupleDelete(rel, &tp->t_self); + + ReleaseSysCache(tp); + + heap_close(rel, RowExclusiveLock); +} + +ObjectAddress +AlterRoutineMapping(AlterRoutineMappingStmt *stmt) +{ + RoutineMapping *rm; + Relation rel; + Datum values[Natts_pg_routine_mapping]; + bool nulls[Natts_pg_routine_mapping]; + bool repl[Natts_pg_user_mapping]; + HeapTuple tp; + ObjectAddress address; + + rel = heap_open(RoutineMappingRelationId, RowExclusiveLock); + + rm = GetRoutineMappingByName(stmt->name, false); + + tp = SearchSysCacheCopy1(ROUTINEMAPPINGOID, ObjectIdGetDatum(rm->rmid)); + + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + memset(repl, false, sizeof(repl)); + + if (stmt->options) + { + ForeignServer *server; + ForeignDataWrapper *fdw; + Datum datum; + bool isnull; + + server = GetForeignServer(rm->serverid); + fdw = GetForeignDataWrapper(server->fdwid); + + datum = SysCacheGetAttr(ROUTINEMAPPINGPROCSERVER, + tp, + Anum_pg_routine_mapping_rmoptions, + &isnull); + + if (isnull) + datum = PointerGetDatum(NULL); + + datum = transformGenericOptions(RoutineMappingRelationId, + datum, + stmt->options, + fdw->fdwvalidator); + if (PointerIsValid(DatumGetPointer(datum))) + values[Anum_pg_routine_mapping_rmoptions - 1] = datum; + else + nulls[Anum_pg_routine_mapping_rmoptions - 1] = true; + + repl[Anum_pg_routine_mapping_rmoptions - 1] = true; + } + + tp = heap_modify_tuple(tp, RelationGetDescr(rel), + values, nulls, repl); + + CatalogTupleUpdate(rel, &tp->t_self, tp); + + ObjectAddressSet(address, RoutineMappingRelationId, rm->rmid); + + heap_freetuple(tp); + + heap_close(rel, RowExclusiveLock); + + return address; +} diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f46af41..687d67d 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -9648,6 +9648,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, case OCLASS_FDW: case OCLASS_FOREIGN_SERVER: case OCLASS_USER_MAPPING: + case OCLASS_ROUTINE_MAPPING: case OCLASS_DEFACL: case OCLASS_EXTENSION: case OCLASS_EVENT_TRIGGER: diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index eac78a5..0a435af 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -17,6 +17,7 @@ #include "catalog/pg_foreign_data_wrapper.h" #include "catalog/pg_foreign_server.h" #include "catalog/pg_foreign_table.h" +#include "catalog/pg_routine_mapping.h" #include "catalog/pg_user_mapping.h" #include "foreign/fdwapi.h" #include "foreign/foreign.h" @@ -465,6 +466,66 @@ IsImportableForeignTable(const char *tablename, return false; /* shouldn't get here */ } +/* + * GetRoutineMapping - look up the routine mapping. + */ +RoutineMapping * +GetRoutineMapping(Oid rmid) +{ + Form_pg_routine_mapping rmform; + RoutineMapping *rm; + HeapTuple tp; + Datum datum; + bool isnull; + + tp = SearchSysCache1(ROUTINEMAPPINGOID, ObjectIdGetDatum(rmid)); + + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for routine mapping"); + + rmform = (Form_pg_routine_mapping) GETSTRUCT(tp); + + rm = (RoutineMapping *) palloc(sizeof(RoutineMapping)); + rm->rmid = rmid; + rm->rmname = pstrdup(NameStr(rmform->rmname)); + rm->procid = rmform->rmproc; + rm->serverid = rmform->rmserver; + + datum = SysCacheGetAttr(ROUTINEMAPPINGPROCSERVER, + tp, + Anum_pg_routine_mapping_rmoptions, + &isnull); + + if (isnull) + rm->options = NIL; + else + rm->options = untransformRelOptions(datum); + + ReleaseSysCache(tp); + + return rm; +} + +/* + * GetRoutineMappingByName - look up the routine map by name. + */ +RoutineMapping * +GetRoutineMappingByName(const char *rmname, bool missing_ok) +{ + Oid rmid; + + rmid = GetSysCacheOid1(ROUTINEMAPPINGNAME, CStringGetDatum(rmname)); + + if (!OidIsValid(rmid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("routine mapping \"%s\" does not exist", rmname))); + + if (!OidIsValid(rmid)) + return NULL; + + return GetRoutineMapping(rmid); +} /* * deflist_to_tuplestore - Helper function to convert DefElem list to diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 4bd2223..0275a63 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -250,7 +250,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt AlterOperatorStmt AlterSeqStmt AlterSystemStmt AlterTableStmt AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt - AlterCompositeTypeStmt AlterUserMappingStmt + AlterCompositeTypeStmt AlterUserMappingStmt AlterRoutineMappingStmt AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt AlterDefaultPrivilegesStmt DefACLAction AnalyzeStmt CallStmt ClosePortalStmt ClusterStmt CommentStmt @@ -260,10 +260,11 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); CreateSchemaStmt CreateSeqStmt CreateStmt CreateStatsStmt CreateTableSpaceStmt CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt CreateAssertStmt CreateTransformStmt CreateTrigStmt CreateEventTrigStmt - CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatePolicyStmt - CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt + CreateUserStmt CreateUserMappingStmt CreateRoutineMappingStmt CreateRoleStmt + CreatePolicyStmt CreatedbStmt + DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt - DropAssertStmt DropCastStmt DropRoleStmt + DropAssertStmt DropCastStmt DropRoleStmt DropRoutineMappingStmt DropdbStmt DropTableSpaceStmt DropTransformStmt DropUserMappingStmt ExplainStmt FetchStmt @@ -846,6 +847,7 @@ stmt : | AlterPublicationStmt | AlterRoleSetStmt | AlterRoleStmt + | AlterRoutineMappingStmt | AlterSubscriptionStmt | AlterTSConfigurationStmt | AlterTSDictionaryStmt @@ -886,6 +888,7 @@ stmt : | CreateTransformStmt | CreateTrigStmt | CreateEventTrigStmt + | CreateRoutineMappingStmt | CreateRoleStmt | CreateUserStmt | CreateUserMappingStmt @@ -907,6 +910,7 @@ stmt : | DropTableSpaceStmt | DropTransformStmt | DropRoleStmt + | DropRoutineMappingStmt | DropUserMappingStmt | DropdbStmt | ExecuteStmt @@ -5224,6 +5228,107 @@ AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generi /***************************************************************************** * + * QUERY: + * CREATE ROUTINE MAPPING [IF NOT EXISTS] name + * FOR [FUNCTION|PROCEDUER] + * SERVER name [OPTIONS] + * + *****************************************************************************/ + +CreateRoutineMappingStmt: CREATE ROUTINE MAPPING name + FOR FUNCTION function_with_argtypes + SERVER name create_generic_options + { + CreateRoutineMappingStmt *n = makeNode(CreateRoutineMappingStmt); + n->name = $4; + n->objtype = OBJECT_FUNCTION; + n->func = $7; + n->servername = $9; + n->options = $10; + n->if_not_exists = false; + $$ = (Node *) n; + } + | CREATE ROUTINE MAPPING IF_P NOT EXISTS name + FOR FUNCTION function_with_argtypes + SERVER name create_generic_options + { + CreateRoutineMappingStmt *n = makeNode(CreateRoutineMappingStmt); + n->name = $7; + n->objtype = OBJECT_FUNCTION; + n->func = $10; + n->servername = $12; + n->options = $13; + n->if_not_exists = true; + $$ = (Node *) n; + } + | CREATE ROUTINE MAPPING name + FOR PROCEDURE function_with_argtypes + SERVER name create_generic_options + { + CreateRoutineMappingStmt *n = makeNode(CreateRoutineMappingStmt); + n->name = $4; + n->objtype = OBJECT_PROCEDURE; + n->func = $7; + n->servername = $9; + n->options = $10; + n->if_not_exists = false; + $$ = (Node *) n; + } + | CREATE ROUTINE MAPPING IF_P NOT EXISTS name + FOR PROCEDURE function_with_argtypes + SERVER name create_generic_options + { + CreateRoutineMappingStmt *n = makeNode(CreateRoutineMappingStmt); + n->name = $7; + n->objtype = OBJECT_PROCEDURE; + n->func = $10; + n->servername = $12; + n->options = $13; + n->if_not_exists = true; + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * + * QUERY: + * ALTER ROUTINE MAPPING name OPTION + + *****************************************************************************/ +AlterRoutineMappingStmt: ALTER ROUTINE MAPPING name alter_generic_options + { + AlterRoutineMappingStmt *n = makeNode(AlterRoutineMappingStmt); + n->name = $4; + n->options = $5; + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * + * QUERY: + * DROP ROUTINE MAPPING name + + *****************************************************************************/ + +DropRoutineMappingStmt: DROP ROUTINE MAPPING name + { + DropRoutineMappingStmt *n = makeNode(DropRoutineMappingStmt); + n->name = $4; + n->missing_ok = false; + $$ = (Node *) n; + } + | DROP ROUTINE MAPPING IF_P EXISTS name + { + DropRoutineMappingStmt *n = makeNode(DropRoutineMappingStmt); + n->name = $6; + n->missing_ok = true; + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * * QUERIES: * CREATE POLICY name ON table * [AS { PERMISSIVE | RESTRICTIVE } ] @@ -15140,7 +15245,6 @@ unreserved_keyword: | LOCK_P | LOCKED | LOGGED - | MAPPING | MATCH | MATERIALIZED | MAXVALUE @@ -15451,6 +15555,7 @@ reserved_keyword: | LIMIT | LOCALTIME | LOCALTIMESTAMP + | MAPPING | NOT | NULL_P | OFFSET diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index b5804f6..68a8a51 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -211,6 +211,9 @@ check_xact_readonly(Node *parsetree) case T_CreateUserMappingStmt: case T_AlterUserMappingStmt: case T_DropUserMappingStmt: + case T_CreateRoutineMappingStmt: + case T_AlterRoutineMappingStmt: + case T_DropRoutineMappingStmt: case T_AlterTableSpaceOptionsStmt: case T_CreateForeignTableStmt: case T_ImportForeignSchemaStmt: @@ -1421,6 +1424,20 @@ ProcessUtilitySlow(ParseState *pstate, commandCollected = true; break; + case T_CreateRoutineMappingStmt: + address = CreateRoutineMapping((CreateRoutineMappingStmt *) parsetree); + break; + + case T_AlterRoutineMappingStmt: + address = AlterRoutineMapping((AlterRoutineMappingStmt *) parsetree); + break; + + case T_DropRoutineMappingStmt: + RemoveRoutineMapping((DropRoutineMappingStmt *) parsetree); + /* no commands stashed for DROP */ + commandCollected = true; + break; + case T_CompositeTypeStmt: /* CREATE TYPE (composite) */ { CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree; @@ -2250,6 +2267,18 @@ CreateCommandTag(Node *parsetree) tag = "IMPORT FOREIGN SCHEMA"; break; + case T_CreateRoutineMappingStmt: + tag = "CREATE ROUTINE MAPPING"; + break; + + case T_AlterRoutineMappingStmt: + tag = "ALTER ROUTINE MAPPING"; + break; + + case T_DropRoutineMappingStmt: + tag = "DROP ROUTINE MAPPING"; + break; + case T_DropStmt: switch (((DropStmt *) parsetree)->removeType) { @@ -3006,6 +3035,9 @@ GetCommandLogLevel(Node *parsetree) case T_CreateUserMappingStmt: case T_AlterUserMappingStmt: case T_DropUserMappingStmt: + case T_CreateRoutineMappingStmt: + case T_AlterRoutineMappingStmt: + case T_DropRoutineMappingStmt: case T_ImportForeignSchemaStmt: lev = LOGSTMT_DDL; break; diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index bba595a..a585101 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -2838,8 +2838,7 @@ type_is_collatable(Oid typid) * Currently this is only consulted for individual tables, not for inheritance * trees, so we don't need an "inh" parameter. * - * Calling a hook at this point looks somewhat strange, but is required - * because the optimizer calls this function without any other way for + * Calling a hook at this point looks somewhat strange, but is required * because the optimizer calls this function without any other way for * plug-ins to control the result. */ int32 diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 2b38178..355cffc 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -59,6 +59,7 @@ #include "catalog/pg_shdepend.h" #include "catalog/pg_shdescription.h" #include "catalog/pg_shseclabel.h" +#include "catalog/pg_routine_mapping.h" #include "catalog/pg_replication_origin.h" #include "catalog/pg_statistic.h" #include "catalog/pg_statistic_ext.h" @@ -705,6 +706,39 @@ static const struct cachedesc cacheinfo[] = { }, 16 }, + {RoutineMappingRelationId, /* ROUTINEMAPPINGOID */ + RoutineMappingOidIndexId, + 1, + { + ObjectIdAttributeNumber, + 0, + 0, + 0 + }, + 2 + }, + {RoutineMappingRelationId, /* ROUTINEMAPPINGPROCSERVER */ + RoutineMappingProcServerIndexId, + 2, + { + Anum_pg_routine_mapping_rmproc, + Anum_pg_routine_mapping_rmserver, + 0, + 0 + }, + 2 + }, + {RoutineMappingRelationId, /* ROUTINEMAPINGNAME */ + RoutineMappingNameIndexId, + 1, + { + Anum_pg_routine_mapping_rmname, + 0, + 0, + 0 + }, + 2 + }, {RewriteRelationId, /* RULERELNAME */ RewriteRelRulenameIndexId, 2, diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 46c271a..f027521 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -173,6 +173,7 @@ typedef enum ObjectClass OCLASS_FDW, /* pg_foreign_data_wrapper */ OCLASS_FOREIGN_SERVER, /* pg_foreign_server */ OCLASS_USER_MAPPING, /* pg_user_mapping */ + OCLASS_ROUTINE_MAPPING, /* pg_routine_mapping */ OCLASS_DEFACL, /* pg_default_acl */ OCLASS_EXTENSION, /* pg_extension */ OCLASS_EVENT_TRIGGER, /* pg_event_trigger */ diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 2491582..539e410 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -299,6 +299,13 @@ DECLARE_UNIQUE_INDEX(pg_user_mapping_oid_index, 174, on pg_user_mapping using bt DECLARE_UNIQUE_INDEX(pg_user_mapping_user_server_index, 175, on pg_user_mapping using btree(umuser oid_ops, umserver oid_ops)); #define UserMappingUserServerIndexId 175 +DECLARE_UNIQUE_INDEX(pg_routine_mapping_oid_index, 6021, on pg_routine_mapping using btree(oid oid_ops)); +#define RoutineMappingOidIndexId 6021 +DECLARE_UNIQUE_INDEX(pg_routine_mapping_proc_server_index, 6022, on pg_routine_mapping using btree(rmproc oid_ops, rmserver oid_ops)); +#define RoutineMappingProcServerIndexId 6022 +DECLARE_UNIQUE_INDEX(pg_routine_mapping_name_index, 6023, on pg_routine_mapping using btree(rmname name_ops)); +#define RoutineMappingNameIndexId 6023 + DECLARE_UNIQUE_INDEX(pg_foreign_table_relid_index, 3119, on pg_foreign_table using btree(ftrelid oid_ops)); #define ForeignTableRelidIndexId 3119 diff --git a/src/include/catalog/pg_routine_mapping.h b/src/include/catalog/pg_routine_mapping.h new file mode 100644 index 0000000..cf3e7cb --- /dev/null +++ b/src/include/catalog/pg_routine_mapping.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * pg_routine_mapping.h + * definition of the "routine mapping" system catalog (pg_routine_mapping) + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_routine_mapping.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_ROUTINE_MAPPING_H +#define PG_ROUTINE_MAPPING_H + +#include "catalog/genbki.h" +#include "catalog/pg_routine_mapping_d.h" + +/* ---------------- + * pg_routine_mapping definition. cpp turns this into + * typedef struct FormData_pg_routine_mapping + * ---------------- + */ +CATALOG(pg_routine_mapping,6020,RoutineMappingRelationId) +{ + NameData rmname; + Oid rmproc; + Oid rmserver; +#ifdef CATALOG_VARLEN + text rmoptions[1]; +#endif +} FormData_pg_routine_mapping; + +/* ---------------- + * Form_pg_routine_mapping corresponds to a pointer to a tuple with + * the format of pg_routine_mapping relation. + * ---------------- + */ +typedef FormData_pg_routine_mapping *Form_pg_routine_mapping; + +#endif /* PG_ROUTINE_MAPPING_H */ diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 6b83723..3df9d49 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -150,6 +150,10 @@ extern Datum transformGenericOptions(Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator); +extern ObjectAddress CreateRoutineMapping(CreateRoutineMappingStmt *stmt); +extern ObjectAddress AlterRoutineMapping(AlterRoutineMappingStmt *stmt); +extern Oid RemoveRoutineMapping(DropRoutineMappingStmt *stmt); +extern void RemoveRoutineMappingById(Oid rmId); /* commands/amcmds.c */ extern ObjectAddress CreateAccessMethod(CreateAmStmt *stmt); diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h index 3ca12e6..05393dd 100644 --- a/src/include/foreign/foreign.h +++ b/src/include/foreign/foreign.h @@ -68,6 +68,14 @@ typedef struct ForeignTable List *options; /* ftoptions as DefElem list */ } ForeignTable; +typedef struct RoutineMapping +{ + Oid rmid; /* Oid of routine mapping */ + char *rmname; + Oid procid; /* local function oid */ + Oid serverid; /* server oid */ + List *options; /* rmoptions as DefElem list */ +} RoutineMapping; extern ForeignServer *GetForeignServer(Oid serverid); extern ForeignServer *GetForeignServerByName(const char *name, bool missing_ok); @@ -76,6 +84,8 @@ extern ForeignDataWrapper *GetForeignDataWrapper(Oid fdwid); extern ForeignDataWrapper *GetForeignDataWrapperByName(const char *name, bool missing_ok); extern ForeignTable *GetForeignTable(Oid relid); +extern RoutineMapping *GetRoutineMapping(Oid rmid); +extern RoutineMapping *GetRoutineMappingByName(const char *rmname, bool missing_ok); extern List *GetForeignColumnOptions(Oid relid, AttrNumber attnum); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 697d3d7..70aff71 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -419,6 +419,9 @@ typedef enum NodeTag T_CreateStatsStmt, T_AlterCollationStmt, T_CallStmt, + T_CreateRoutineMappingStmt, + T_AlterRoutineMappingStmt, + T_DropRoutineMappingStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 07ab1a3..98f761f 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2316,6 +2316,35 @@ typedef struct ImportForeignSchemaStmt List *options; /* list of options to pass to FDW */ } ImportForeignSchemaStmt; +/* ---------------------- + * Create/Drop ROUTINE MAPPING Statements + * ---------------------- + */ +typedef struct CreateRoutineMappingStmt +{ + NodeTag type; + char *name; /* routine mapping name */ + ObjectType objtype; + ObjectWithArgs *func; /* name and args of function */ + char *servername; /* server name */ + List *options; /* generic option to server */ + bool if_not_exists; +} CreateRoutineMappingStmt; + +typedef struct AlterRoutineMappingStmt +{ + NodeTag type; + char *name; + List *options; +} AlterRoutineMappingStmt; + +typedef struct DropRoutineMappingStmt +{ + NodeTag type; + char *name; + bool missing_ok; +} DropRoutineMappingStmt; + /*---------------------- * Create POLICY Statement *---------------------- diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 23db401..52752d7 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -243,7 +243,7 @@ PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD) PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD) PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD) PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD) -PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD) +PG_KEYWORD("mapping", MAPPING, RESERVED_KEYWORD) PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD) PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD) PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD) diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 4f33358..96282ea 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -84,6 +84,9 @@ enum SysCacheIdentifier RELOID, REPLORIGIDENT, REPLORIGNAME, + ROUTINEMAPPINGOID, + ROUTINEMAPPINGPROCSERVER, + ROUTINEMAPPINGNAME, RULERELNAME, SEQRELID, STATEXTNAMENSP, -- 2.10.5