diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/commands/event_trigger.c | 3 | ||||
-rw-r--r-- | src/backend/commands/foreigncmds.c | 144 | ||||
-rw-r--r-- | src/backend/foreign/foreign.c | 41 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 18 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 16 | ||||
-rw-r--r-- | src/backend/nodes/outfuncs.c | 16 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 64 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 10 | ||||
-rw-r--r-- | src/bin/psql/tab-complete.c | 12 | ||||
-rw-r--r-- | src/include/commands/defrem.h | 1 | ||||
-rw-r--r-- | src/include/foreign/fdwapi.h | 8 | ||||
-rw-r--r-- | src/include/nodes/nodes.h | 1 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 25 | ||||
-rw-r--r-- | src/include/parser/kwlist.h | 1 | ||||
-rw-r--r-- | src/test/regress/expected/foreign_data.out | 10 | ||||
-rw-r--r-- | src/test/regress/sql/foreign_data.sql | 7 |
16 files changed, 369 insertions, 8 deletions
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 110fe004a46..754264eb3ee 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -250,7 +250,8 @@ check_ddl_tag(const char *tag) pg_strcasecmp(tag, "REFRESH MATERIALIZED VIEW") == 0 || pg_strcasecmp(tag, "ALTER DEFAULT PRIVILEGES") == 0 || pg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0 || - pg_strcasecmp(tag, "DROP OWNED") == 0) + pg_strcasecmp(tag, "DROP OWNED") == 0 || + pg_strcasecmp(tag, "IMPORT FOREIGN SCHEMA") == 0) return EVENT_TRIGGER_COMMAND_TAG_OK; /* diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index 8ab9c439db2..ab4ed6c78ec 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -15,8 +15,8 @@ #include "access/heapam.h" #include "access/htup_details.h" -#include "access/xact.h" #include "access/reloptions.h" +#include "access/xact.h" #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/objectaccess.h" @@ -27,9 +27,11 @@ #include "catalog/pg_type.h" #include "catalog/pg_user_mapping.h" #include "commands/defrem.h" +#include "foreign/fdwapi.h" #include "foreign/foreign.h" #include "miscadmin.h" #include "parser/parse_func.h" +#include "tcop/utility.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" @@ -37,6 +39,16 @@ #include "utils/syscache.h" +typedef struct +{ + char *tablename; + char *cmd; +} import_error_callback_arg; + +/* Internal functions */ +static void import_error_callback(void *arg); + + /* * Convert a DefElem list to the text array format that is used in * pg_foreign_data_wrapper, pg_foreign_server, pg_user_mapping, and @@ -1427,3 +1439,133 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) heap_close(ftrel, RowExclusiveLock); } + +/* + * Import a foreign schema + */ +void +ImportForeignSchema(ImportForeignSchemaStmt *stmt) +{ + ForeignServer *server; + ForeignDataWrapper *fdw; + FdwRoutine *fdw_routine; + AclResult aclresult; + List *cmd_list; + ListCell *lc; + + /* Check that the foreign server exists and that we have USAGE on it */ + server = GetForeignServerByName(stmt->server_name, false); + aclresult = pg_foreign_server_aclcheck(server->serverid, GetUserId(), ACL_USAGE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, server->servername); + + /* Check that the schema exists and we have CREATE permissions on it */ + (void) LookupCreationNamespace(stmt->local_schema); + + /* Get the FDW and check it supports IMPORT */ + fdw = GetForeignDataWrapper(server->fdwid); + if (!OidIsValid(fdw->fdwhandler)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("foreign-data wrapper \"%s\" has no handler", + fdw->fdwname))); + fdw_routine = GetFdwRoutine(fdw->fdwhandler); + if (fdw_routine->ImportForeignSchema == NULL) + ereport(ERROR, + (errcode(ERRCODE_FDW_NO_SCHEMAS), + errmsg("foreign-data wrapper \"%s\" does not support IMPORT FOREIGN SCHEMA", + fdw->fdwname))); + + /* Call FDW to get a list of commands */ + cmd_list = fdw_routine->ImportForeignSchema(stmt, server->serverid); + + /* Parse and execute each command */ + foreach(lc, cmd_list) + { + char *cmd = (char *) lfirst(lc); + import_error_callback_arg callback_arg; + ErrorContextCallback sqlerrcontext; + List *raw_parsetree_list; + ListCell *lc2; + + /* + * Setup error traceback support for ereport(). This is so that any + * error in the generated SQL will be displayed nicely. + */ + callback_arg.tablename = NULL; /* not known yet */ + callback_arg.cmd = cmd; + sqlerrcontext.callback = import_error_callback; + sqlerrcontext.arg = (void *) &callback_arg; + sqlerrcontext.previous = error_context_stack; + error_context_stack = &sqlerrcontext; + + /* + * Parse the SQL string into a list of raw parse trees. + */ + raw_parsetree_list = pg_parse_query(cmd); + + /* + * Process each parse tree (we allow the FDW to put more than one + * command per string, though this isn't really advised). + */ + foreach(lc2, raw_parsetree_list) + { + CreateForeignTableStmt *cstmt = lfirst(lc2); + + /* + * Because we only allow CreateForeignTableStmt, we can skip parse + * analysis, rewrite, and planning steps here. + */ + if (!IsA(cstmt, CreateForeignTableStmt)) + elog(ERROR, + "foreign-data wrapper \"%s\" returned incorrect statement type %d", + fdw->fdwname, (int) nodeTag(cstmt)); + + /* Ignore commands for tables excluded by filter options */ + if (!IsImportableForeignTable(cstmt->base.relation->relname, stmt)) + continue; + + /* Enable reporting of current table's name on error */ + callback_arg.tablename = cstmt->base.relation->relname; + + /* Ensure creation schema is the one given in IMPORT statement */ + cstmt->base.relation->schemaname = pstrdup(stmt->local_schema); + + /* Execute statement */ + ProcessUtility((Node *) cstmt, + cmd, + PROCESS_UTILITY_SUBCOMMAND, NULL, + None_Receiver, NULL); + + /* Be sure to advance the command counter between subcommands */ + CommandCounterIncrement(); + + callback_arg.tablename = NULL; + } + + error_context_stack = sqlerrcontext.previous; + } +} + +/* + * error context callback to let us supply the failing SQL statement's text + */ +static void +import_error_callback(void *arg) +{ + import_error_callback_arg *callback_arg = (import_error_callback_arg *) arg; + int syntaxerrposition; + + /* If it's a syntax error, convert to internal syntax error report */ + syntaxerrposition = geterrposition(); + if (syntaxerrposition > 0) + { + errposition(0); + internalerrposition(syntaxerrposition); + internalerrquery(callback_arg->cmd); + } + + if (callback_arg->tablename) + errcontext("importing foreign table \"%s\"", + callback_arg->tablename); +} diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index 6d548b7d08b..4f5f6ae362b 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -400,6 +400,47 @@ GetFdwRoutineForRelation(Relation relation, bool makecopy) /* + * IsImportableForeignTable - filter table names for IMPORT FOREIGN SCHEMA + * + * Returns TRUE if given table name should be imported according to the + * statement's import filter options. + */ +bool +IsImportableForeignTable(const char *tablename, + ImportForeignSchemaStmt *stmt) +{ + ListCell *lc; + + switch (stmt->list_type) + { + case FDW_IMPORT_SCHEMA_ALL: + return true; + + case FDW_IMPORT_SCHEMA_LIMIT_TO: + foreach(lc, stmt->table_list) + { + RangeVar *rv = (RangeVar *) lfirst(lc); + + if (strcmp(tablename, rv->relname) == 0) + return true; + } + return false; + + case FDW_IMPORT_SCHEMA_EXCEPT: + foreach(lc, stmt->table_list) + { + RangeVar *rv = (RangeVar *) lfirst(lc); + + if (strcmp(tablename, rv->relname) == 0) + return false; + } + return true; + } + return false; /* shouldn't get here */ +} + + +/* * deflist_to_tuplestore - Helper function to convert DefElem list to * tuplestore usable in SRF. */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 8d3d5a7c734..30885789304 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3567,6 +3567,21 @@ _copyCreateForeignTableStmt(const CreateForeignTableStmt *from) return newnode; } +static ImportForeignSchemaStmt * +_copyImportForeignSchemaStmt(const ImportForeignSchemaStmt *from) +{ + ImportForeignSchemaStmt *newnode = makeNode(ImportForeignSchemaStmt); + + COPY_STRING_FIELD(server_name); + COPY_STRING_FIELD(remote_schema); + COPY_STRING_FIELD(local_schema); + COPY_SCALAR_FIELD(list_type); + COPY_NODE_FIELD(table_list); + COPY_NODE_FIELD(options); + + return newnode; +} + static CreateTrigStmt * _copyCreateTrigStmt(const CreateTrigStmt *from) { @@ -4477,6 +4492,9 @@ copyObject(const void *from) case T_CreateForeignTableStmt: retval = _copyCreateForeignTableStmt(from); break; + case T_ImportForeignSchemaStmt: + retval = _copyImportForeignSchemaStmt(from); + break; case T_CreateTrigStmt: retval = _copyCreateTrigStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index e7b49f680cf..1b07db69d73 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1769,6 +1769,19 @@ _equalCreateForeignTableStmt(const CreateForeignTableStmt *a, const CreateForeig } static bool +_equalImportForeignSchemaStmt(const ImportForeignSchemaStmt *a, const ImportForeignSchemaStmt *b) +{ + COMPARE_STRING_FIELD(server_name); + COMPARE_STRING_FIELD(remote_schema); + COMPARE_STRING_FIELD(local_schema); + COMPARE_SCALAR_FIELD(list_type); + COMPARE_NODE_FIELD(table_list); + COMPARE_NODE_FIELD(options); + + return true; +} + +static bool _equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b) { COMPARE_STRING_FIELD(trigname); @@ -2943,6 +2956,9 @@ equal(const void *a, const void *b) case T_CreateForeignTableStmt: retval = _equalCreateForeignTableStmt(a, b); break; + case T_ImportForeignSchemaStmt: + retval = _equalImportForeignSchemaStmt(a, b); + break; case T_CreateTrigStmt: retval = _equalCreateTrigStmt(a, b); break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index c182212e62f..9573a9bb0e6 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -2012,6 +2012,19 @@ _outCreateForeignTableStmt(StringInfo str, const CreateForeignTableStmt *node) } static void +_outImportForeignSchemaStmt(StringInfo str, const ImportForeignSchemaStmt *node) +{ + WRITE_NODE_TYPE("IMPORTFOREIGNSCHEMASTMT"); + + WRITE_STRING_FIELD(server_name); + WRITE_STRING_FIELD(remote_schema); + WRITE_STRING_FIELD(local_schema); + WRITE_ENUM_FIELD(list_type, ImportForeignSchemaType); + WRITE_NODE_FIELD(table_list); + WRITE_NODE_FIELD(options); +} + +static void _outIndexStmt(StringInfo str, const IndexStmt *node) { WRITE_NODE_TYPE("INDEXSTMT"); @@ -3119,6 +3132,9 @@ _outNode(StringInfo str, const void *obj) case T_CreateForeignTableStmt: _outCreateForeignTableStmt(str, obj); break; + case T_ImportForeignSchemaStmt: + _outImportForeignSchemaStmt(str, obj); + break; case T_IndexStmt: _outIndexStmt(str, obj); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index ba7d091dc79..a113809ca63 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -111,6 +111,13 @@ typedef struct PrivTarget List *objs; } PrivTarget; +/* Private struct for the result of import_qualification production */ +typedef struct ImportQual +{ + ImportForeignSchemaType type; + List *table_names; +} ImportQual; + /* ConstraintAttributeSpec yields an integer bitmask of these flags: */ #define CAS_NOT_DEFERRABLE 0x01 #define CAS_DEFERRABLE 0x02 @@ -212,6 +219,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); ResTarget *target; struct PrivTarget *privtarget; AccessPriv *accesspriv; + struct ImportQual *importqual; InsertStmt *istmt; VariableSetStmt *vsetstmt; } @@ -238,8 +246,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt DropForeignServerStmt DropUserMappingStmt ExplainStmt FetchStmt - GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt - LockStmt NotifyStmt ExplainableStmt PreparableStmt + GrantStmt GrantRoleStmt ImportForeignSchemaStmt IndexStmt InsertStmt + ListenStmt LoadStmt LockStmt NotifyStmt ExplainableStmt PreparableStmt CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt RuleActionStmt RuleActionStmtOrEmpty RuleStmt @@ -322,6 +330,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <ival> defacl_privilege_target %type <defelt> DefACLOption %type <list> DefACLOptionList +%type <ival> import_qualification_type +%type <importqual> import_qualification %type <list> stmtblock stmtmulti OptTableElementList TableElementList OptInherit definition @@ -556,7 +566,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); HANDLER HAVING HEADER_P HOLD HOUR_P - IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P + IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IMPORT_P IN_P INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION @@ -802,6 +812,7 @@ stmt : | FetchStmt | GrantStmt | GrantRoleStmt + | ImportForeignSchemaStmt | IndexStmt | InsertStmt | ListenStmt @@ -4275,6 +4286,52 @@ AlterForeignTableStmt: /***************************************************************************** * * QUERY: + * IMPORT FOREIGN SCHEMA remote_schema + * [ { LIMIT TO | EXCEPT } ( table_list ) ] + * FROM SERVER server_name INTO local_schema [ OPTIONS (...) ] + * + ****************************************************************************/ + +ImportForeignSchemaStmt: + IMPORT_P FOREIGN SCHEMA name import_qualification + FROM SERVER name INTO name create_generic_options + { + ImportForeignSchemaStmt *n = makeNode(ImportForeignSchemaStmt); + n->server_name = $8; + n->remote_schema = $4; + n->local_schema = $10; + n->list_type = $5->type; + n->table_list = $5->table_names; + n->options = $11; + $$ = (Node *) n; + } + ; + +import_qualification_type: + LIMIT TO { $$ = FDW_IMPORT_SCHEMA_LIMIT_TO; } + | EXCEPT { $$ = FDW_IMPORT_SCHEMA_EXCEPT; } + ; + +import_qualification: + import_qualification_type '(' relation_expr_list ')' + { + ImportQual *n = (ImportQual *) palloc(sizeof(ImportQual)); + n->type = $1; + n->table_names = $3; + $$ = n; + } + | /*EMPTY*/ + { + ImportQual *n = (ImportQual *) palloc(sizeof(ImportQual)); + n->type = FDW_IMPORT_SCHEMA_ALL; + n->table_names = NIL; + $$ = n; + } + ; + +/***************************************************************************** + * + * QUERY: * CREATE USER MAPPING FOR auth_ident SERVER name [OPTIONS] * *****************************************************************************/ @@ -12909,6 +12966,7 @@ unreserved_keyword: | IMMEDIATE | IMMUTABLE | IMPLICIT_P + | IMPORT_P | INCLUDING | INCREMENT | INDEX diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 3423898c112..07e0b987212 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -202,6 +202,7 @@ check_xact_readonly(Node *parsetree) case T_AlterTableSpaceOptionsStmt: case T_AlterTableSpaceMoveStmt: case T_CreateForeignTableStmt: + case T_ImportForeignSchemaStmt: case T_SecLabelStmt: PreventCommandIfReadOnly(CreateCommandTag(parsetree)); break; @@ -1196,6 +1197,10 @@ ProcessUtilitySlow(Node *parsetree, RemoveUserMapping((DropUserMappingStmt *) parsetree); break; + case T_ImportForeignSchemaStmt: + ImportForeignSchema((ImportForeignSchemaStmt *) parsetree); + break; + case T_CompositeTypeStmt: /* CREATE TYPE (composite) */ { CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree; @@ -1853,6 +1858,10 @@ CreateCommandTag(Node *parsetree) tag = "CREATE FOREIGN TABLE"; break; + case T_ImportForeignSchemaStmt: + tag = "IMPORT FOREIGN SCHEMA"; + break; + case T_DropStmt: switch (((DropStmt *) parsetree)->removeType) { @@ -2518,6 +2527,7 @@ GetCommandLogLevel(Node *parsetree) case T_CreateUserMappingStmt: case T_AlterUserMappingStmt: case T_DropUserMappingStmt: + case T_ImportForeignSchemaStmt: lev = LOGSTMT_DDL; break; diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index bab03572352..6c2d431842c 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -876,8 +876,9 @@ psql_completion(const char *text, int start, int end) static const char *const sql_commands[] = { "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", - "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH", - "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE", + "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", + "FETCH", "GRANT", "IMPORT", "INSERT", "LISTEN", "LOAD", "LOCK", + "MOVE", "NOTIFY", "PREPARE", "REASSIGN", "REFRESH", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK", "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START", "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH", @@ -2947,6 +2948,13 @@ psql_completion(const char *text, int start, int end) pg_strcasecmp(prev_wd, "GROUP") == 0) COMPLETE_WITH_CONST("BY"); +/* IMPORT FOREIGN SCHEMA */ + else if (pg_strcasecmp(prev_wd, "IMPORT") == 0) + COMPLETE_WITH_CONST("FOREIGN SCHEMA"); + else if (pg_strcasecmp(prev2_wd, "IMPORT") == 0 && + pg_strcasecmp(prev_wd, "FOREIGN") == 0) + COMPLETE_WITH_CONST("SCHEMA"); + /* INSERT */ /* Complete INSERT with "INTO" */ else if (pg_strcasecmp(prev_wd, "INSERT") == 0) diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 5ec9374aad0..0ebdbc1c186 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -124,6 +124,7 @@ extern Oid AlterUserMapping(AlterUserMappingStmt *stmt); extern Oid RemoveUserMapping(DropUserMappingStmt *stmt); extern void RemoveUserMappingById(Oid umId); extern void CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid); +extern void ImportForeignSchema(ImportForeignSchemaStmt *stmt); extern Datum transformGenericOptions(Oid catalogId, Datum oldOptions, List *options, diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h index 1b735dacc6d..dc0a7fc7235 100644 --- a/src/include/foreign/fdwapi.h +++ b/src/include/foreign/fdwapi.h @@ -100,6 +100,9 @@ typedef bool (*AnalyzeForeignTable_function) (Relation relation, AcquireSampleRowsFunc *func, BlockNumber *totalpages); +typedef List *(*ImportForeignSchema_function) (ImportForeignSchemaStmt *stmt, + Oid serverOid); + /* * FdwRoutine is the struct returned by a foreign-data wrapper's handler * function. It provides pointers to the callback functions needed by the @@ -144,6 +147,9 @@ typedef struct FdwRoutine /* Support functions for ANALYZE */ AnalyzeForeignTable_function AnalyzeForeignTable; + + /* Support functions for IMPORT FOREIGN SCHEMA */ + ImportForeignSchema_function ImportForeignSchema; } FdwRoutine; @@ -151,5 +157,7 @@ typedef struct FdwRoutine extern FdwRoutine *GetFdwRoutine(Oid fdwhandler); extern FdwRoutine *GetFdwRoutineByRelId(Oid relid); extern FdwRoutine *GetFdwRoutineForRelation(Relation relation, bool makecopy); +extern bool IsImportableForeignTable(const char *tablename, + ImportForeignSchemaStmt *stmt); #endif /* FDWAPI_H */ diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 7b0088fdb50..067c7685f0d 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -357,6 +357,7 @@ typedef enum NodeTag T_AlterTableSpaceMoveStmt, T_SecLabelStmt, T_CreateForeignTableStmt, + T_ImportForeignSchemaStmt, T_CreateExtensionStmt, T_AlterExtensionStmt, T_AlterExtensionContentsStmt, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index ff126ebca47..8364bef79f5 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1791,7 +1791,7 @@ typedef struct AlterForeignServerStmt } AlterForeignServerStmt; /* ---------------------- - * Create FOREIGN TABLE Statements + * Create FOREIGN TABLE Statement * ---------------------- */ @@ -1832,6 +1832,29 @@ typedef struct DropUserMappingStmt } DropUserMappingStmt; /* ---------------------- + * Import Foreign Schema Statement + * ---------------------- + */ + +typedef enum ImportForeignSchemaType +{ + FDW_IMPORT_SCHEMA_ALL, /* all relations wanted */ + FDW_IMPORT_SCHEMA_LIMIT_TO, /* include only listed tables in import */ + FDW_IMPORT_SCHEMA_EXCEPT /* exclude listed tables from import */ +} ImportForeignSchemaType; + +typedef struct ImportForeignSchemaStmt +{ + NodeTag type; + char *server_name; /* FDW server name */ + char *remote_schema; /* remote schema name to query */ + char *local_schema; /* local schema to create objects in */ + ImportForeignSchemaType list_type; /* type of table list */ + List *table_list; /* List of RangeVar */ + List *options; /* list of options to pass to FDW */ +} ImportForeignSchemaStmt; + +/* ---------------------- * Create TRIGGER Statement * ---------------------- */ diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 04e98109635..b52e50757c8 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -184,6 +184,7 @@ PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD) PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD) PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD) +PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD) PG_KEYWORD("in", IN_P, RESERVED_KEYWORD) PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD) PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD) diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out index ff203b201fd..e4dedb0c3ba 100644 --- a/src/test/regress/expected/foreign_data.out +++ b/src/test/regress/expected/foreign_data.out @@ -1193,6 +1193,16 @@ DROP TRIGGER trigtest_before_row ON foreign_schema.foreign_table_1; DROP TRIGGER trigtest_after_stmt ON foreign_schema.foreign_table_1; DROP TRIGGER trigtest_after_row ON foreign_schema.foreign_table_1; DROP FUNCTION dummy_trigger(); +-- IMPORT FOREIGN SCHEMA +IMPORT FOREIGN SCHEMA s1 FROM SERVER s9 INTO public; -- ERROR +ERROR: foreign-data wrapper "foo" has no handler +IMPORT FOREIGN SCHEMA s1 LIMIT TO (t1) FROM SERVER s9 INTO public; --ERROR +ERROR: foreign-data wrapper "foo" has no handler +IMPORT FOREIGN SCHEMA s1 EXCEPT (t1) FROM SERVER s9 INTO public; -- ERROR +ERROR: foreign-data wrapper "foo" has no handler +IMPORT FOREIGN SCHEMA s1 EXCEPT (t1, t2) FROM SERVER s9 INTO public +OPTIONS (option1 'value1', option2 'value2'); -- ERROR +ERROR: foreign-data wrapper "foo" has no handler -- DROP FOREIGN TABLE DROP FOREIGN TABLE no_table; -- ERROR ERROR: foreign table "no_table" does not exist diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql index 0f0869ee268..de9dbc8f386 100644 --- a/src/test/regress/sql/foreign_data.sql +++ b/src/test/regress/sql/foreign_data.sql @@ -514,6 +514,13 @@ DROP TRIGGER trigtest_after_row ON foreign_schema.foreign_table_1; DROP FUNCTION dummy_trigger(); +-- IMPORT FOREIGN SCHEMA +IMPORT FOREIGN SCHEMA s1 FROM SERVER s9 INTO public; -- ERROR +IMPORT FOREIGN SCHEMA s1 LIMIT TO (t1) FROM SERVER s9 INTO public; --ERROR +IMPORT FOREIGN SCHEMA s1 EXCEPT (t1) FROM SERVER s9 INTO public; -- ERROR +IMPORT FOREIGN SCHEMA s1 EXCEPT (t1, t2) FROM SERVER s9 INTO public +OPTIONS (option1 'value1', option2 'value2'); -- ERROR + -- DROP FOREIGN TABLE DROP FOREIGN TABLE no_table; -- ERROR DROP FOREIGN TABLE IF EXISTS no_table; |