move_validator.patch

text/plain

Filename: move_validator.patch
Type: text/plain
Part: 0
Message: Re: pgsql_fdw, FDW for PostgreSQL server

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
contrib/dblink/dblink--1.0--1.1.sql 0 0
contrib/dblink/dblink--1.1.sql 0 0
contrib/dblink/dblink.c 0 0
contrib/dblink/dblink.control 0 0
contrib/dblink/dblink.h 0 0
contrib/dblink/expected/dblink.out 0 0
contrib/dblink/Makefile 0 0
contrib/dblink/sql/dblink.sql 0 0
doc/src/sgml/dblink.sgml 0 0
doc/src/sgml/ref/create_foreign_data_wrapper.sgml 0 0
src/backend/foreign/foreign.c 0 0
src/include/catalog/pg_proc.h 0 0
src/test/regress/expected/foreign_data.out 0 0
src/test/regress/sql/foreign_data.sql 0 0
diff --git a/contrib/dblink/Makefile b/contrib/dblink/Makefile
index ac63748..a27db88 100644
*** a/contrib/dblink/Makefile
--- b/contrib/dblink/Makefile
*************** SHLIB_LINK = $(libpq)
*** 7,13 ****
  SHLIB_PREREQS = submake-libpq
  
  EXTENSION = dblink
! DATA = dblink--1.0.sql dblink--unpackaged--1.0.sql
  
  REGRESS = dblink
  
--- 7,13 ----
  SHLIB_PREREQS = submake-libpq
  
  EXTENSION = dblink
! DATA = dblink--1.1.sql dblink--1.0--1.1.sql dblink--unpackaged--1.0.sql
  
  REGRESS = dblink
  
diff --git a/contrib/dblink/dblink--1.0--1.1.sql b/contrib/dblink/dblink--1.0--1.1.sql
index ...3dd02a0 .
*** a/contrib/dblink/dblink--1.0--1.1.sql
--- b/contrib/dblink/dblink--1.0--1.1.sql
***************
*** 0 ****
--- 1,17 ----
+ /* contrib/dblink/dblink--1.0--1.1.sql */
+ 
+ -- complain if script is sourced in psql, rather than via ALTER EXTENSION
+ \echo Use "ALTER EXTENSION dblink UPDATE" to load this file. \quit
+ 
+ /* First we have to create validator function */
+ CREATE FUNCTION dblink_fdw_validator(
+     options text[],
+     catalog oid
+ )
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'dblink_fdw_validator'
+ LANGUAGE C STRICT;
+ 
+ /* Then we add the validator */
+ ALTER EXTENSION dblink ADD FUNCTION dblink_fdw_validator(text[], oid);
+ 
diff --git a/contrib/dblink/dblink--1.1.sql b/contrib/dblink/dblink--1.1.sql
index ...ec02498 .
*** a/contrib/dblink/dblink--1.1.sql
--- b/contrib/dblink/dblink--1.1.sql
***************
*** 0 ****
--- 1,231 ----
+ /* contrib/dblink/dblink--1.1.sql */
+ 
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION dblink" to load this file. \quit
+ 
+ -- dblink_connect now restricts non-superusers to password
+ -- authenticated connections
+ CREATE FUNCTION dblink_connect (text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_connect'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_connect (text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_connect'
+ LANGUAGE C STRICT;
+ 
+ -- dblink_connect_u allows non-superusers to use
+ -- non-password authenticated connections, but initially
+ -- privileges are revoked from public
+ CREATE FUNCTION dblink_connect_u (text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_connect'
+ LANGUAGE C STRICT SECURITY DEFINER;
+ 
+ CREATE FUNCTION dblink_connect_u (text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_connect'
+ LANGUAGE C STRICT SECURITY DEFINER;
+ 
+ REVOKE ALL ON FUNCTION dblink_connect_u (text) FROM public;
+ REVOKE ALL ON FUNCTION dblink_connect_u (text, text) FROM public;
+ 
+ CREATE FUNCTION dblink_disconnect ()
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_disconnect'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_disconnect (text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_disconnect'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_open (text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_open'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_open (text, text, boolean)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_open'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_open (text, text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_open'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_open (text, text, text, boolean)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_open'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_fetch (text, int)
+ RETURNS setof record
+ AS 'MODULE_PATHNAME','dblink_fetch'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_fetch (text, int, boolean)
+ RETURNS setof record
+ AS 'MODULE_PATHNAME','dblink_fetch'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_fetch (text, text, int)
+ RETURNS setof record
+ AS 'MODULE_PATHNAME','dblink_fetch'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_fetch (text, text, int, boolean)
+ RETURNS setof record
+ AS 'MODULE_PATHNAME','dblink_fetch'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_close (text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_close'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_close (text, boolean)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_close'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_close (text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_close'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_close (text, text, boolean)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_close'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink (text, text)
+ RETURNS setof record
+ AS 'MODULE_PATHNAME','dblink_record'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink (text, text, boolean)
+ RETURNS setof record
+ AS 'MODULE_PATHNAME','dblink_record'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink (text)
+ RETURNS setof record
+ AS 'MODULE_PATHNAME','dblink_record'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink (text, boolean)
+ RETURNS setof record
+ AS 'MODULE_PATHNAME','dblink_record'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_exec (text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_exec'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_exec (text, text, boolean)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_exec'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_exec (text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_exec'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_exec (text,boolean)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_exec'
+ LANGUAGE C STRICT;
+ 
+ CREATE TYPE dblink_pkey_results AS (position int, colname text);
+ 
+ CREATE FUNCTION dblink_get_pkey (text)
+ RETURNS setof dblink_pkey_results
+ AS 'MODULE_PATHNAME','dblink_get_pkey'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_build_sql_insert (text, int2vector, int, _text, _text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_build_sql_insert'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_build_sql_delete (text, int2vector, int, _text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_build_sql_delete'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_build_sql_update (text, int2vector, int, _text, _text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_build_sql_update'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_current_query ()
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_current_query'
+ LANGUAGE C;
+ 
+ CREATE FUNCTION dblink_send_query(text, text)
+ RETURNS int4
+ AS 'MODULE_PATHNAME', 'dblink_send_query'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_is_busy(text)
+ RETURNS int4
+ AS 'MODULE_PATHNAME', 'dblink_is_busy'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_get_result(text)
+ RETURNS SETOF record
+ AS 'MODULE_PATHNAME', 'dblink_get_result'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_get_result(text, bool)
+ RETURNS SETOF record
+ AS 'MODULE_PATHNAME', 'dblink_get_result'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_get_connections()
+ RETURNS text[]
+ AS 'MODULE_PATHNAME', 'dblink_get_connections'
+ LANGUAGE C;
+ 
+ CREATE FUNCTION dblink_cancel_query(text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'dblink_cancel_query'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_error_message(text)
+ RETURNS text
+ AS 'MODULE_PATHNAME', 'dblink_error_message'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_get_notify(
+     OUT notify_name TEXT,
+     OUT be_pid INT4,
+     OUT extra TEXT
+ )
+ RETURNS setof record
+ AS 'MODULE_PATHNAME', 'dblink_get_notify'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_get_notify(
+     conname TEXT,
+     OUT notify_name TEXT,
+     OUT be_pid INT4,
+     OUT extra TEXT
+ )
+ RETURNS setof record
+ AS 'MODULE_PATHNAME', 'dblink_get_notify'
+ LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION dblink_fdw_validator(
+     options text[],
+     catalog oid
+ )
+ RETURNS boolean
+ AS 'MODULE_PATHNAME', 'dblink_fdw_validator'
+ LANGUAGE C STRICT;
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 36a8e3e..1687c53 100644
*** a/contrib/dblink/dblink.c
--- b/contrib/dblink/dblink.c
***************
*** 36,43 ****
--- 36,46 ----
  
  #include "libpq-fe.h"
  #include "funcapi.h"
+ #include "access/reloptions.h"
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
+ #include "catalog/pg_foreign_server.h"
+ #include "catalog/pg_user_mapping.h"
  #include "catalog/pg_type.h"
  #include "executor/spi.h"
  #include "foreign/foreign.h"
*************** validate_pkattnums(Relation rel,
*** 2411,2413 ****
--- 2414,2516 ----
  					 errmsg("invalid attribute number %d", pkattnum)));
  	}
  }
+ 
+ 
+ /*
+  * Describes the valid options for postgresql FDW, server, and user mapping.
+  */
+ struct ConnectionOption
+ {
+ 	const char *optname;
+ 	Oid			optcontext;		/* Oid of catalog in which option may appear */
+ };
+ 
+ /*
+  * Copied from fe-connect.c PQconninfoOptions.
+  *
+  * The list is small - don't bother with bsearch if it stays so.
+  */
+ static struct ConnectionOption libpq_conninfo_options[] = {
+ 	{"authtype", ForeignServerRelationId},
+ 	{"service", ForeignServerRelationId},
+ 	{"user", UserMappingRelationId},
+ 	{"password", UserMappingRelationId},
+ 	{"connect_timeout", ForeignServerRelationId},
+ 	{"dbname", ForeignServerRelationId},
+ 	{"host", ForeignServerRelationId},
+ 	{"hostaddr", ForeignServerRelationId},
+ 	{"port", ForeignServerRelationId},
+ 	{"tty", ForeignServerRelationId},
+ 	{"options", ForeignServerRelationId},
+ 	{"requiressl", ForeignServerRelationId},
+ 	{"sslmode", ForeignServerRelationId},
+ 	{"gsslib", ForeignServerRelationId},
+ 	{NULL, InvalidOid}
+ };
+ 
+ 
+ /*
+  * Check if the provided option is one of libpq conninfo options.
+  * context is the Oid of the catalog the option came from, or 0 if we
+  * don't care.
+  */
+ static bool
+ is_conninfo_option(const char *option, Oid context)
+ {
+ 	struct ConnectionOption *opt;
+ 
+ 	for (opt = libpq_conninfo_options; opt->optname; opt++)
+ 		if (context == opt->optcontext && strcmp(opt->optname, option) == 0)
+ 			return true;
+ 	return false;
+ }
+ 
+ 
+ /*
+  * Validate the generic option given to SERVER or USER MAPPING.
+  * Raise an ERROR if the option or its value is considered
+  * invalid.
+  *
+  * Valid server options are all libpq conninfo options except
+  * user and password -- these may only appear in USER MAPPING options.
+  */
+ PG_FUNCTION_INFO_V1(dblink_fdw_validator);
+ Datum
+ dblink_fdw_validator(PG_FUNCTION_ARGS)
+ {
+ 	List	   *options_list = untransformRelOptions(PG_GETARG_DATUM(0));
+ 	Oid			catalog = PG_GETARG_OID(1);
+ 
+ 	ListCell   *cell;
+ 
+ 	foreach(cell, options_list)
+ 	{
+ 		DefElem    *def = lfirst(cell);
+ 
+ 		if (!is_conninfo_option(def->defname, catalog))
+ 		{
+ 			struct ConnectionOption *opt;
+ 			StringInfoData buf;
+ 
+ 			/*
+ 			 * Unknown option specified, complain about it. Provide a hint
+ 			 * with list of valid options for the object.
+ 			 */
+ 			initStringInfo(&buf);
+ 			for (opt = libpq_conninfo_options; opt->optname; opt++)
+ 				if (catalog == opt->optcontext)
+ 					appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "",
+ 									 opt->optname);
+ 
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_SYNTAX_ERROR),
+ 					 errmsg("invalid option \"%s\"", def->defname),
+ 					 errhint("Valid options in this context are: %s",
+ 							 buf.data)));
+ 
+ 			PG_RETURN_BOOL(false);
+ 		}
+ 	}
+ 
+ 	PG_RETURN_BOOL(true);
+ }
diff --git a/contrib/dblink/dblink.control b/contrib/dblink/dblink.control
index 4333a9b..39f439a 100644
*** a/contrib/dblink/dblink.control
--- b/contrib/dblink/dblink.control
***************
*** 1,5 ****
  # dblink extension
  comment = 'connect to other PostgreSQL databases from within a database'
! default_version = '1.0'
  module_pathname = '$libdir/dblink'
  relocatable = true
--- 1,5 ----
  # dblink extension
  comment = 'connect to other PostgreSQL databases from within a database'
! default_version = '1.1'
  module_pathname = '$libdir/dblink'
  relocatable = true
diff --git a/contrib/dblink/dblink.h b/contrib/dblink/dblink.h
index 935d283..fd11658 100644
*** a/contrib/dblink/dblink.h
--- b/contrib/dblink/dblink.h
*************** extern Datum dblink_build_sql_delete(PG_
*** 58,62 ****
--- 58,63 ----
  extern Datum dblink_build_sql_update(PG_FUNCTION_ARGS);
  extern Datum dblink_current_query(PG_FUNCTION_ARGS);
  extern Datum dblink_get_notify(PG_FUNCTION_ARGS);
+ extern Datum dblink_fdw_validator(PG_FUNCTION_ARGS);
  
  #endif   /* DBLINK_H */
diff --git a/contrib/dblink/expected/dblink.out b/contrib/dblink/expected/dblink.out
index 511dd5e..0605354 100644
*** a/contrib/dblink/expected/dblink.out
--- b/contrib/dblink/expected/dblink.out
*************** SELECT dblink_disconnect('dtest1');
*** 785,792 ****
  
  -- test foreign data wrapper functionality
  CREATE USER dblink_regression_test;
! CREATE FOREIGN DATA WRAPPER postgresql;
! CREATE SERVER fdtest FOREIGN DATA WRAPPER postgresql OPTIONS (dbname 'contrib_regression');
  CREATE USER MAPPING FOR public SERVER fdtest;
  GRANT USAGE ON FOREIGN SERVER fdtest TO dblink_regression_test;
  GRANT EXECUTE ON FUNCTION dblink_connect_u(text, text) TO dblink_regression_test;
--- 785,792 ----
  
  -- test foreign data wrapper functionality
  CREATE USER dblink_regression_test;
! CREATE FOREIGN DATA WRAPPER dblink_fdw VALIDATOR dblink_fdw_validator;
! CREATE SERVER fdtest FOREIGN DATA WRAPPER dblink_fdw OPTIONS (dbname 'contrib_regression');
  CREATE USER MAPPING FOR public SERVER fdtest;
  GRANT USAGE ON FOREIGN SERVER fdtest TO dblink_regression_test;
  GRANT EXECUTE ON FUNCTION dblink_connect_u(text, text) TO dblink_regression_test;
*************** REVOKE EXECUTE ON FUNCTION dblink_connec
*** 825,831 ****
  DROP USER dblink_regression_test;
  DROP USER MAPPING FOR public SERVER fdtest;
  DROP SERVER fdtest;
! DROP FOREIGN DATA WRAPPER postgresql;
  -- test asynchronous notifications
  SELECT dblink_connect('dbname=contrib_regression');
   dblink_connect 
--- 825,831 ----
  DROP USER dblink_regression_test;
  DROP USER MAPPING FOR public SERVER fdtest;
  DROP SERVER fdtest;
! DROP FOREIGN DATA WRAPPER dblink_fdw;
  -- test asynchronous notifications
  SELECT dblink_connect('dbname=contrib_regression');
   dblink_connect 
diff --git a/contrib/dblink/sql/dblink.sql b/contrib/dblink/sql/dblink.sql
index 8c8ffe2..288ebf8 100644
*** a/contrib/dblink/sql/dblink.sql
--- b/contrib/dblink/sql/dblink.sql
*************** SELECT dblink_disconnect('dtest1');
*** 361,368 ****
  -- test foreign data wrapper functionality
  CREATE USER dblink_regression_test;
  
! CREATE FOREIGN DATA WRAPPER postgresql;
! CREATE SERVER fdtest FOREIGN DATA WRAPPER postgresql OPTIONS (dbname 'contrib_regression');
  CREATE USER MAPPING FOR public SERVER fdtest;
  GRANT USAGE ON FOREIGN SERVER fdtest TO dblink_regression_test;
  GRANT EXECUTE ON FUNCTION dblink_connect_u(text, text) TO dblink_regression_test;
--- 361,368 ----
  -- test foreign data wrapper functionality
  CREATE USER dblink_regression_test;
  
! CREATE FOREIGN DATA WRAPPER dblink_fdw VALIDATOR dblink_fdw_validator;
! CREATE SERVER fdtest FOREIGN DATA WRAPPER dblink_fdw OPTIONS (dbname 'contrib_regression');
  CREATE USER MAPPING FOR public SERVER fdtest;
  GRANT USAGE ON FOREIGN SERVER fdtest TO dblink_regression_test;
  GRANT EXECUTE ON FUNCTION dblink_connect_u(text, text) TO dblink_regression_test;
*************** REVOKE EXECUTE ON FUNCTION dblink_connec
*** 381,387 ****
  DROP USER dblink_regression_test;
  DROP USER MAPPING FOR public SERVER fdtest;
  DROP SERVER fdtest;
! DROP FOREIGN DATA WRAPPER postgresql;
  
  -- test asynchronous notifications
  SELECT dblink_connect('dbname=contrib_regression');
--- 381,387 ----
  DROP USER dblink_regression_test;
  DROP USER MAPPING FOR public SERVER fdtest;
  DROP SERVER fdtest;
! DROP FOREIGN DATA WRAPPER dblink_fdw;
  
  -- test asynchronous notifications
  SELECT dblink_connect('dbname=contrib_regression');
diff --git a/doc/src/sgml/dblink.sgml b/doc/src/sgml/dblink.sgml
index 855495c..613f447 100644
*** a/doc/src/sgml/dblink.sgml
--- b/doc/src/sgml/dblink.sgml
*************** dblink_connect(text connname, text conns
*** 47,55 ****
     <para>
      The connection string may also be the name of an existing foreign
      server.  It is recommended to use
!     the <function>postgresql_fdw_validator</function> when defining
!     the corresponding foreign-data wrapper.  See the example below, as
!     well as the following:
      <simplelist type="inline">
       <member><xref linkend="sql-createforeigndatawrapper"></member>
       <member><xref linkend="sql-createserver"></member>
--- 47,58 ----
     <para>
      The connection string may also be the name of an existing foreign
      server.  It is recommended to use
!     the <function>dblink_fdw_validator</function> when defining
!     the corresponding foreign-data wrapper.
!     This validator function was added in <productname>PostgreSQL</> 9.2, and
!     it has been called <function>postgresql_fdw_validator</function> in older
!     versions.
!     See the example below, as well as the following:
      <simplelist type="inline">
       <member><xref linkend="sql-createforeigndatawrapper"></member>
       <member><xref linkend="sql-createserver"></member>
*************** SELECT dblink_connect('myconn', 'dbname=
*** 136,143 ****
  --       DETAIL:  Non-superuser cannot connect if the server does not request a password.
  --       HINT:  Target server's authentication method must be changed.
  CREATE USER dblink_regression_test WITH PASSWORD 'secret';
! CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator;
! CREATE SERVER fdtest FOREIGN DATA WRAPPER postgresql OPTIONS (hostaddr '127.0.0.1', dbname 'contrib_regression');
  
  CREATE USER MAPPING FOR dblink_regression_test SERVER fdtest OPTIONS (user 'dblink_regression_test', password 'secret');
  GRANT USAGE ON FOREIGN SERVER fdtest TO dblink_regression_test;
--- 139,146 ----
  --       DETAIL:  Non-superuser cannot connect if the server does not request a password.
  --       HINT:  Target server's authentication method must be changed.
  CREATE USER dblink_regression_test WITH PASSWORD 'secret';
! CREATE FOREIGN DATA WRAPPER dblink_fdw VALIDATOR dblink_fdw_validator;
! CREATE SERVER fdtest FOREIGN DATA WRAPPER dblink_fdw OPTIONS (hostaddr '127.0.0.1', dbname 'contrib_regression');
  
  CREATE USER MAPPING FOR dblink_regression_test SERVER fdtest OPTIONS (user 'dblink_regression_test', password 'secret');
  GRANT USAGE ON FOREIGN SERVER fdtest TO dblink_regression_test;
*************** REVOKE SELECT ON TABLE foo FROM  dblink_
*** 173,179 ****
  DROP USER MAPPING FOR dblink_regression_test SERVER fdtest;
  DROP USER dblink_regression_test;
  DROP SERVER fdtest;
! DROP FOREIGN DATA WRAPPER postgresql;
  </screen>
    </refsect1>
   </refentry>
--- 176,182 ----
  DROP USER MAPPING FOR dblink_regression_test SERVER fdtest;
  DROP USER dblink_regression_test;
  DROP SERVER fdtest;
! DROP FOREIGN DATA WRAPPER dblink_fdw;
  </screen>
    </refsect1>
   </refentry>
diff --git a/doc/src/sgml/ref/create_foreign_data_wrapper.sgml b/doc/src/sgml/ref/create_foreign_data_wrapper.sgml
index 804fb47..0d346fd 100644
*** a/doc/src/sgml/ref/create_foreign_data_wrapper.sgml
--- b/doc/src/sgml/ref/create_foreign_data_wrapper.sgml
*************** CREATE FOREIGN DATA WRAPPER <replaceable
*** 123,133 ****
    </para>
  
    <para>
!    There is one built-in foreign-data wrapper validator function
!    provided:
!    <filename>postgresql_fdw_validator</filename>, which accepts
     options corresponding to <application>libpq</> connection
!    parameters.
    </para>
   </refsect1>
  
--- 123,134 ----
    </para>
  
    <para>
!    Until <productname>PostgreSQL</productname> 9.1, there was one built-in
!    foreign-data wrapper validator function provided:
!    <function>postgresql_fdw_validator</function>, which accepts
     options corresponding to <application>libpq</> connection
!    parameters.  But it has been moved to <filename>contrib/dblink</> with
!    renaming to <function>dblink_fdw_validator</function>.
    </para>
   </refsect1>
  
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index c4c2a61..6831c70 100644
*** a/src/backend/foreign/foreign.c
--- b/src/backend/foreign/foreign.c
***************
*** 25,31 ****
  
  
  extern Datum pg_options_to_table(PG_FUNCTION_ARGS);
- extern Datum postgresql_fdw_validator(PG_FUNCTION_ARGS);
  
  
  
--- 25,30 ----
*************** pg_options_to_table(PG_FUNCTION_ARGS)
*** 401,504 ****
  
  
  /*
-  * Describes the valid options for postgresql FDW, server, and user mapping.
-  */
- struct ConnectionOption
- {
- 	const char *optname;
- 	Oid			optcontext;		/* Oid of catalog in which option may appear */
- };
- 
- /*
-  * Copied from fe-connect.c PQconninfoOptions.
-  *
-  * The list is small - don't bother with bsearch if it stays so.
-  */
- static struct ConnectionOption libpq_conninfo_options[] = {
- 	{"authtype", ForeignServerRelationId},
- 	{"service", ForeignServerRelationId},
- 	{"user", UserMappingRelationId},
- 	{"password", UserMappingRelationId},
- 	{"connect_timeout", ForeignServerRelationId},
- 	{"dbname", ForeignServerRelationId},
- 	{"host", ForeignServerRelationId},
- 	{"hostaddr", ForeignServerRelationId},
- 	{"port", ForeignServerRelationId},
- 	{"tty", ForeignServerRelationId},
- 	{"options", ForeignServerRelationId},
- 	{"requiressl", ForeignServerRelationId},
- 	{"sslmode", ForeignServerRelationId},
- 	{"gsslib", ForeignServerRelationId},
- 	{NULL, InvalidOid}
- };
- 
- 
- /*
-  * Check if the provided option is one of libpq conninfo options.
-  * context is the Oid of the catalog the option came from, or 0 if we
-  * don't care.
-  */
- static bool
- is_conninfo_option(const char *option, Oid context)
- {
- 	struct ConnectionOption *opt;
- 
- 	for (opt = libpq_conninfo_options; opt->optname; opt++)
- 		if (context == opt->optcontext && strcmp(opt->optname, option) == 0)
- 			return true;
- 	return false;
- }
- 
- 
- /*
-  * Validate the generic option given to SERVER or USER MAPPING.
-  * Raise an ERROR if the option or its value is considered
-  * invalid.
-  *
-  * Valid server options are all libpq conninfo options except
-  * user and password -- these may only appear in USER MAPPING options.
-  */
- Datum
- postgresql_fdw_validator(PG_FUNCTION_ARGS)
- {
- 	List	   *options_list = untransformRelOptions(PG_GETARG_DATUM(0));
- 	Oid			catalog = PG_GETARG_OID(1);
- 
- 	ListCell   *cell;
- 
- 	foreach(cell, options_list)
- 	{
- 		DefElem    *def = lfirst(cell);
- 
- 		if (!is_conninfo_option(def->defname, catalog))
- 		{
- 			struct ConnectionOption *opt;
- 			StringInfoData buf;
- 
- 			/*
- 			 * Unknown option specified, complain about it. Provide a hint
- 			 * with list of valid options for the object.
- 			 */
- 			initStringInfo(&buf);
- 			for (opt = libpq_conninfo_options; opt->optname; opt++)
- 				if (catalog == opt->optcontext)
- 					appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "",
- 									 opt->optname);
- 
- 			ereport(ERROR,
- 					(errcode(ERRCODE_SYNTAX_ERROR),
- 					 errmsg("invalid option \"%s\"", def->defname),
- 					 errhint("Valid options in this context are: %s",
- 							 buf.data)));
- 
- 			PG_RETURN_BOOL(false);
- 		}
- 	}
- 
- 	PG_RETURN_BOOL(true);
- }
- 
- /*
   * get_foreign_data_wrapper_oid - given a FDW name, look up the OID
   *
   * If missing_ok is false, throw an error if name not found.  If true, just
--- 400,405 ----
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 8700d0d..8970998 100644
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("filenode identifier of relation")
*** 3399,3407 ****
  DATA(insert OID = 3034 ( pg_relation_filepath	PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 25 "2205" _null_ _null_ _null_ _null_ pg_relation_filepath _null_ _null_ _null_ ));
  DESCR("file path of relation");
  
- DATA(insert OID = 2316 ( postgresql_fdw_validator PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1009 26" _null_ _null_ _null_ _null_ postgresql_fdw_validator _null_ _null_ _null_));
- DESCR("(internal)");
- 
  DATA(insert OID = 2290 (  record_in			PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 2249 "2275 26 23" _null_ _null_ _null_ _null_	record_in _null_ _null_ _null_ ));
  DESCR("I/O");
  DATA(insert OID = 2291 (  record_out		PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "2249" _null_ _null_ _null_ _null_ record_out _null_ _null_ _null_ ));
--- 3399,3404 ----
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index ba86883..161fbe7 100644
*** a/src/test/regress/expected/foreign_data.out
--- b/src/test/regress/expected/foreign_data.out
*************** CREATE ROLE regress_test_role2;
*** 13,18 ****
--- 13,33 ----
  CREATE ROLE regress_test_role_super SUPERUSER;
  CREATE ROLE regress_test_indirect;
  CREATE ROLE unprivileged_role;
+ -- validator for this test
+ CREATE FUNCTION postgresql_fdw_validator(text[], oid) RETURNS boolean AS $$
+ DECLARE
+ BEGIN
+ 	IF $1::text LIKE '%foo%' THEN
+ 		RAISE 'invalid option "foo"'
+ 			USING HINT = 'Valid options in this context are: authtype, service, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib';
+ 	ELSIF $1::text LIKE '%username%' THEN
+ 		RAISE 'invalid option "username"'
+ 			USING HINT = 'Valid options in this context are: user, password';
+ 	END IF;
+ 
+ 	RETURN true;
+ END
+ $$ LANGUAGE plpgsql;
  CREATE FOREIGN DATA WRAPPER dummy;
  COMMENT ON FOREIGN DATA WRAPPER dummy IS 'useless';
  CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator;
*************** DROP FOREIGN DATA WRAPPER postgresql CAS
*** 1201,1206 ****
--- 1216,1222 ----
  DROP FOREIGN DATA WRAPPER dummy CASCADE;
  NOTICE:  drop cascades to server s0
  \c
+ DROP FUNCTION postgresql_fdw_validator(text[], oid);
  DROP ROLE foreign_data_user;
  -- At this point we should have no wrappers, no servers, and no mappings.
  SELECT fdwname, fdwhandler, fdwvalidator, fdwoptions FROM pg_foreign_data_wrapper;
diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql
index 0c95672..9cf9ca7 100644
*** a/src/test/regress/sql/foreign_data.sql
--- b/src/test/regress/sql/foreign_data.sql
*************** CREATE ROLE regress_test_role_super SUPE
*** 20,25 ****
--- 20,41 ----
  CREATE ROLE regress_test_indirect;
  CREATE ROLE unprivileged_role;
  
+ -- validator for this test
+ CREATE FUNCTION postgresql_fdw_validator(text[], oid) RETURNS boolean AS $$
+ DECLARE
+ BEGIN
+ 	IF $1::text LIKE '%foo%' THEN
+ 		RAISE 'invalid option "foo"'
+ 			USING HINT = 'Valid options in this context are: authtype, service, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib';
+ 	ELSIF $1::text LIKE '%username%' THEN
+ 		RAISE 'invalid option "username"'
+ 			USING HINT = 'Valid options in this context are: user, password';
+ 	END IF;
+ 
+ 	RETURN true;
+ END
+ $$ LANGUAGE plpgsql;
+ 
  CREATE FOREIGN DATA WRAPPER dummy;
  COMMENT ON FOREIGN DATA WRAPPER dummy IS 'useless';
  CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator;
*************** DROP ROLE regress_test_role2;
*** 495,500 ****
--- 511,517 ----
  DROP FOREIGN DATA WRAPPER postgresql CASCADE;
  DROP FOREIGN DATA WRAPPER dummy CASCADE;
  \c
+ DROP FUNCTION postgresql_fdw_validator(text[], oid);
  DROP ROLE foreign_data_user;
  
  -- At this point we should have no wrappers, no servers, and no mappings.