diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/foreigncmds.c | 209 | ||||
-rw-r--r-- | src/backend/foreign/foreign.c | 1 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 5 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 5 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 46 | ||||
-rw-r--r-- | src/backend/utils/adt/pseudotypes.c | 27 |
6 files changed, 235 insertions, 58 deletions
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index a2b5358e16f..acd40c1f4e9 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -165,7 +165,7 @@ transformGenericOptions(Oid catalogId, result = optionListToArray(resultOptions); - if (fdwvalidator) + if (OidIsValid(fdwvalidator) && DatumGetPointer(result) != NULL) OidFunctionCall2(fdwvalidator, result, ObjectIdGetDatum(catalogId)); return result; @@ -246,8 +246,9 @@ AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId) newOwnerId); } - heap_close(rel, NoLock); heap_freetuple(tup); + + heap_close(rel, RowExclusiveLock); } @@ -308,25 +309,98 @@ AlterForeignServerOwner(const char *name, Oid newOwnerId) newOwnerId); } - heap_close(rel, NoLock); heap_freetuple(tup); + + heap_close(rel, RowExclusiveLock); } /* + * Convert a handler function name passed from the parser to an Oid. + */ +static Oid +lookup_fdw_handler_func(DefElem *handler) +{ + Oid handlerOid; + + if (handler == NULL || handler->arg == NULL) + return InvalidOid; + + /* handlers have no arguments */ + handlerOid = LookupFuncName((List *) handler->arg, 0, NULL, false); + + /* check that handler has correct return type */ + if (get_func_rettype(handlerOid) != FDW_HANDLEROID) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("function %s must return type \"fdw_handler\"", + NameListToString((List *) handler->arg)))); + + return handlerOid; +} + +/* * Convert a validator function name passed from the parser to an Oid. */ static Oid -lookup_fdw_validator_func(List *validator) +lookup_fdw_validator_func(DefElem *validator) { Oid funcargtypes[2]; + if (validator == NULL || validator->arg == NULL) + return InvalidOid; + + /* validators take text[], oid */ funcargtypes[0] = TEXTARRAYOID; funcargtypes[1] = OIDOID; - return LookupFuncName(validator, 2, funcargtypes, false); - /* return value is ignored, so we don't check the type */ + + return LookupFuncName((List *) validator->arg, 2, funcargtypes, false); + /* validator's return value is ignored, so we don't check the type */ } +/* + * Process function options of CREATE/ALTER FDW + */ +static void +parse_func_options(List *func_options, + bool *handler_given, Oid *fdwhandler, + bool *validator_given, Oid *fdwvalidator) +{ + ListCell *cell; + + *handler_given = false; + *validator_given = false; + /* return InvalidOid if not given */ + *fdwhandler = InvalidOid; + *fdwvalidator = InvalidOid; + + foreach(cell, func_options) + { + DefElem *def = (DefElem *) lfirst(cell); + + if (strcmp(def->defname, "handler") == 0) + { + if (*handler_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + *handler_given = true; + *fdwhandler = lookup_fdw_handler_func(def); + } + else if (strcmp(def->defname, "validator") == 0) + { + if (*validator_given) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + *validator_given = true; + *fdwvalidator = lookup_fdw_validator_func(def); + } + else + elog(ERROR, "option \"%s\" not recognized", + def->defname); + } +} /* * Create a foreign-data wrapper @@ -339,6 +413,9 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) bool nulls[Natts_pg_foreign_data_wrapper]; HeapTuple tuple; Oid fdwId; + bool handler_given; + bool validator_given; + Oid fdwhandler; Oid fdwvalidator; Datum fdwoptions; Oid ownerId; @@ -377,12 +454,13 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname)); values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId); - if (stmt->validator) - fdwvalidator = lookup_fdw_validator_func(stmt->validator); - else - fdwvalidator = InvalidOid; + /* Lookup handler and validator functions, if given */ + parse_func_options(stmt->func_options, + &handler_given, &fdwhandler, + &validator_given, &fdwvalidator); - values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = fdwvalidator; + values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler); + values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator); nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true; @@ -408,7 +486,15 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) myself.objectId = fdwId; myself.objectSubId = 0; - if (fdwvalidator) + if (OidIsValid(fdwhandler)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = fdwhandler; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(fdwvalidator)) { referenced.classId = ProcedureRelationId; referenced.objectId = fdwvalidator; @@ -425,7 +511,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) InvokeObjectAccessHook(OAT_POST_CREATE, ForeignDataWrapperRelationId, fdwId, 0); - heap_close(rel, NoLock); + heap_close(rel, RowExclusiveLock); } @@ -437,12 +523,16 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) { Relation rel; HeapTuple tp; + Form_pg_foreign_data_wrapper fdwForm; Datum repl_val[Natts_pg_foreign_data_wrapper]; bool repl_null[Natts_pg_foreign_data_wrapper]; bool repl_repl[Natts_pg_foreign_data_wrapper]; Oid fdwId; bool isnull; Datum datum; + bool handler_given; + bool validator_given; + Oid fdwhandler; Oid fdwvalidator; /* Must be super user */ @@ -461,15 +551,32 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname))); + fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp); fdwId = HeapTupleGetOid(tp); memset(repl_val, 0, sizeof(repl_val)); memset(repl_null, false, sizeof(repl_null)); memset(repl_repl, false, sizeof(repl_repl)); - if (stmt->change_validator) + parse_func_options(stmt->func_options, + &handler_given, &fdwhandler, + &validator_given, &fdwvalidator); + + if (handler_given) + { + repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler); + repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true; + + /* + * It could be that the behavior of accessing foreign table changes + * with the new handler. Warn about this. + */ + ereport(WARNING, + (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables"))); + } + + if (validator_given) { - fdwvalidator = stmt->validator ? lookup_fdw_validator_func(stmt->validator) : InvalidOid; repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator); repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true; @@ -477,26 +584,21 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) * It could be that the options for the FDW, SERVER and USER MAPPING * are no longer valid with the new validator. Warn about this. */ - if (stmt->validator) + if (OidIsValid(fdwvalidator)) ereport(WARNING, - (errmsg("changing the foreign-data wrapper validator can cause " - "the options for dependent objects to become invalid"))); + (errmsg("changing the foreign-data wrapper validator can cause " + "the options for dependent objects to become invalid"))); } else { /* * Validator is not changed, but we need it for validating options. */ - datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, - tp, - Anum_pg_foreign_data_wrapper_fdwvalidator, - &isnull); - Assert(!isnull); - fdwvalidator = DatumGetObjectId(datum); + fdwvalidator = fdwForm->fdwvalidator; } /* - * Options specified, validate and update. + * If options specified, validate and update. */ if (stmt->options) { @@ -532,8 +634,46 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt) simple_heap_update(rel, &tp->t_self, tp); CatalogUpdateIndexes(rel, tp); - heap_close(rel, RowExclusiveLock); heap_freetuple(tp); + + /* Update function dependencies if we changed them */ + if (handler_given || validator_given) + { + ObjectAddress myself; + ObjectAddress referenced; + + /* + * Flush all existing dependency records of this FDW on functions; + * we assume there can be none other than the ones we are fixing. + */ + deleteDependencyRecordsForClass(ForeignDataWrapperRelationId, + fdwId, + ProcedureRelationId, + DEPENDENCY_NORMAL); + + /* And build new ones. */ + myself.classId = ForeignDataWrapperRelationId; + myself.objectId = fdwId; + myself.objectSubId = 0; + + if (OidIsValid(fdwhandler)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = fdwhandler; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + + if (OidIsValid(fdwvalidator)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = fdwvalidator; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + } + + heap_close(rel, RowExclusiveLock); } @@ -712,7 +852,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt) /* Post creation hook for new foreign server */ InvokeObjectAccessHook(OAT_POST_CREATE, ForeignServerRelationId, srvId, 0); - heap_close(rel, NoLock); + heap_close(rel, RowExclusiveLock); } @@ -804,8 +944,9 @@ AlterForeignServer(AlterForeignServerStmt *stmt) simple_heap_update(rel, &tp->t_self, tp); CatalogUpdateIndexes(rel, tp); - heap_close(rel, RowExclusiveLock); heap_freetuple(tp); + + heap_close(rel, RowExclusiveLock); } @@ -991,7 +1132,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt) /* Post creation hook for new user mapping */ InvokeObjectAccessHook(OAT_POST_CREATE, UserMappingRelationId, umId, 0); - heap_close(rel, NoLock); + heap_close(rel, RowExclusiveLock); } @@ -1076,8 +1217,9 @@ AlterUserMapping(AlterUserMappingStmt *stmt) simple_heap_update(rel, &tp->t_self, tp); CatalogUpdateIndexes(rel, tp); - heap_close(rel, RowExclusiveLock); heap_freetuple(tp); + + heap_close(rel, RowExclusiveLock); } @@ -1184,7 +1326,6 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) Datum values[Natts_pg_foreign_table]; bool nulls[Natts_pg_foreign_table]; HeapTuple tuple; - Oid ftId; AclResult aclresult; ObjectAddress myself; ObjectAddress referenced; @@ -1237,9 +1378,7 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) tuple = heap_form_tuple(ftrel->rd_att, values, nulls); - /* pg_foreign_table don't have OID */ - ftId = simple_heap_insert(ftrel, tuple); - + simple_heap_insert(ftrel, tuple); CatalogUpdateIndexes(ftrel, tuple); heap_freetuple(tuple); @@ -1254,5 +1393,5 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); - heap_close(ftrel, NoLock); + heap_close(ftrel, RowExclusiveLock); } diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index 9a0f847f93c..6e391025ffa 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -58,6 +58,7 @@ GetForeignDataWrapper(Oid fdwid) fdw->fdwid = fdwid; fdw->owner = fdwform->fdwowner; fdw->fdwname = pstrdup(NameStr(fdwform->fdwname)); + fdw->fdwhandler = fdwform->fdwhandler; fdw->fdwvalidator = fdwform->fdwvalidator; /* Extract the options */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 57d58020810..9a8a97c4bec 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3282,7 +3282,7 @@ _copyCreateFdwStmt(CreateFdwStmt *from) CreateFdwStmt *newnode = makeNode(CreateFdwStmt); COPY_STRING_FIELD(fdwname); - COPY_NODE_FIELD(validator); + COPY_NODE_FIELD(func_options); COPY_NODE_FIELD(options); return newnode; @@ -3294,8 +3294,7 @@ _copyAlterFdwStmt(AlterFdwStmt *from) AlterFdwStmt *newnode = makeNode(AlterFdwStmt); COPY_STRING_FIELD(fdwname); - COPY_NODE_FIELD(validator); - COPY_SCALAR_FIELD(change_validator); + COPY_NODE_FIELD(func_options); COPY_NODE_FIELD(options); return newnode; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index f57cf99ba2c..dd332f19f00 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1679,7 +1679,7 @@ static bool _equalCreateFdwStmt(CreateFdwStmt *a, CreateFdwStmt *b) { COMPARE_STRING_FIELD(fdwname); - COMPARE_NODE_FIELD(validator); + COMPARE_NODE_FIELD(func_options); COMPARE_NODE_FIELD(options); return true; @@ -1689,8 +1689,7 @@ static bool _equalAlterFdwStmt(AlterFdwStmt *a, AlterFdwStmt *b) { COMPARE_STRING_FIELD(fdwname); - COMPARE_NODE_FIELD(validator); - COMPARE_SCALAR_FIELD(change_validator); + COMPARE_NODE_FIELD(func_options); COMPARE_NODE_FIELD(options); return true; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 077a10532eb..c6811a11bd1 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -309,6 +309,9 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_ create_generic_options alter_generic_options relation_expr_list dostmt_opt_list +%type <list> opt_fdw_options fdw_options +%type <defelt> fdw_option + %type <range> OptTempTableName %type <into> into_clause create_as_target @@ -3505,20 +3508,37 @@ AlterExtensionContentsStmt: /***************************************************************************** * * QUERY: - * CREATE FOREIGN DATA WRAPPER name [ VALIDATOR name ] + * CREATE FOREIGN DATA WRAPPER name options * *****************************************************************************/ -CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_validator create_generic_options +CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_fdw_options create_generic_options { CreateFdwStmt *n = makeNode(CreateFdwStmt); n->fdwname = $5; - n->validator = $6; + n->func_options = $6; n->options = $7; $$ = (Node *) n; } ; +fdw_option: + HANDLER handler_name { $$ = makeDefElem("handler", (Node *)$2); } + | NO HANDLER { $$ = makeDefElem("handler", NULL); } + | VALIDATOR handler_name { $$ = makeDefElem("validator", (Node *)$2); } + | NO VALIDATOR { $$ = makeDefElem("validator", NULL); } + ; + +fdw_options: + fdw_option { $$ = list_make1($1); } + | fdw_options fdw_option { $$ = lappend($1, $2); } + ; + +opt_fdw_options: + fdw_options { $$ = $1; } + | /*EMPTY*/ { $$ = NIL; } + ; + /***************************************************************************** * * QUERY : @@ -3547,32 +3567,24 @@ DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior /***************************************************************************** * * QUERY : - * ALTER FOREIGN DATA WRAPPER name + * ALTER FOREIGN DATA WRAPPER name options * ****************************************************************************/ -AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name validator_clause alter_generic_options +AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name opt_fdw_options alter_generic_options { AlterFdwStmt *n = makeNode(AlterFdwStmt); n->fdwname = $5; - n->validator = $6; - n->change_validator = true; + n->func_options = $6; n->options = $7; $$ = (Node *) n; } - | ALTER FOREIGN DATA_P WRAPPER name validator_clause + | ALTER FOREIGN DATA_P WRAPPER name fdw_options { AlterFdwStmt *n = makeNode(AlterFdwStmt); n->fdwname = $5; - n->validator = $6; - n->change_validator = true; - $$ = (Node *) n; - } - | ALTER FOREIGN DATA_P WRAPPER name alter_generic_options - { - AlterFdwStmt *n = makeNode(AlterFdwStmt); - n->fdwname = $5; - n->options = $6; + n->func_options = $6; + n->options = NIL; $$ = (Node *) n; } ; diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index 2be0696f609..d9329f83428 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -268,6 +268,33 @@ language_handler_out(PG_FUNCTION_ARGS) /* + * fdw_handler_in - input routine for pseudo-type FDW_HANDLER. + */ +Datum +fdw_handler_in(PG_FUNCTION_ARGS) +{ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot accept a value of type fdw_handler"))); + + PG_RETURN_VOID(); /* keep compiler quiet */ +} + +/* + * fdw_handler_out - output routine for pseudo-type FDW_HANDLER. + */ +Datum +fdw_handler_out(PG_FUNCTION_ARGS) +{ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot display a value of type fdw_handler"))); + + PG_RETURN_VOID(); /* keep compiler quiet */ +} + + +/* * internal_in - input routine for pseudo-type INTERNAL. */ Datum |