diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index bc1a826d38c48256db6ba29c957805ac471690db..2a8f978f85c34a3e893fd61b9ce05873bc32d2bd 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.197 2009/02/09 20:57:59 alvherre Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.198 2009/02/24 10:06:31 petere Exp $ -->
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
  -->
@@ -2466,10 +2466,16 @@
      </row>
 
      <row>
-      <entry><structfield>fdwlibrary</structfield></entry>
-      <entry><type>text</type></entry>
-      <entry></entry>
-      <entry>File name of the library implementing this foreign-data wrapper</entry>
+      <entry><structfield>fdwvalidator</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
+      <entry>
+       References a validator function that is responsible for
+       checking the validity of the generic options given to the
+       foreign-data wrapper, as well as to foreign servers and user
+       mappings using the foreign-data wrapper.  Zero if no validator
+       is provided.
+      </entry>
      </row>
 
      <row>
diff --git a/doc/src/sgml/keywords.sgml b/doc/src/sgml/keywords.sgml
index f7f7d649563162c7e1a04b7d8e3cdb63daa66811..5ea6da68a6843bee33a68f6d6d2de3fce4b25e3a 100644
--- a/doc/src/sgml/keywords.sgml
+++ b/doc/src/sgml/keywords.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/keywords.sgml,v 2.22 2008/12/19 16:25:16 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/keywords.sgml,v 2.23 2009/02/24 10:06:31 petere Exp $ -->
 
 <appendix id="sql-keywords-appendix">
  <title><acronym>SQL</acronym> Key Words</title>
@@ -2687,14 +2687,6 @@
     <entry>reserved</entry>
     <entry>reserved</entry>
    </row>
-   <row>
-    <entry><token>LIBRARY</token></entry>
-    <entry>non-reserved</entry>
-    <entry>non-reserved</entry>
-    <entry>non-reserved</entry>
-    <entry></entry>
-    <entry></entry>
-   </row>
    <row>
     <entry><token>LIKE</token></entry>
     <entry>reserved (can be function or type)</entry>
diff --git a/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml b/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml
index 877c475517064f4eaa421b47740bde1629c272cc..155c8944375035f74f0cbfdceb226155b6fe3e1c 100644
--- a/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml
+++ b/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml,v 1.2 2009/02/24 10:06:32 petere Exp $
 PostgreSQL documentation
 -->
 
@@ -21,7 +21,7 @@ PostgreSQL documentation
  <refsynopsisdiv>
 <synopsis>
 ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable>
-    [ LIBRARY '<replaceable class="parameter">libraryname</replaceable>' ]
+    [ VALIDATOR <replaceable class="parameter">valfunction</replaceable> | NO VALIDATOR ]
     [ OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ]) ]
 ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
 </synopsis>
@@ -58,14 +58,14 @@ ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> OWN
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">libraryname</replaceable></term>
+    <term><literal>VALIDATOR <replaceable class="parameter">valfunction</replaceable></literal></term>
     <listitem>
      <para>
-      New name of the foreign-data wrapper library.
+      Specifies a new foreign-data wrapper validator function.
      </para>
 
      <para>
-      Note that it is possible that after changing the library, the
+      Note that it is possible that after changing the validator the
       options to the foreign-data wrapper, servers, and user mappings
       have become invalid.   It is up to the user to make sure that
       these options are correct before using the foreign-data
@@ -74,6 +74,16 @@ ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> OWN
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><literal>NO VALIDATOR</literal></term>
+    <listitem>
+     <para>
+      This is used to specify that the foreign-data wrapper should no
+      longer have a validator function.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><literal>OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] )</literal></term>
     <listitem>
@@ -102,10 +112,10 @@ ALTER FOREIGN DATA WRAPPER dbi OPTIONS (ADD foo '1', DROP 'bar');
   </para>
 
   <para>
-   Change the foreign-data wrapper <literal>dbi</> library
-   to <literal>/home/bob/mylibrary.so</>:
+   Change the foreign-data wrapper <literal>dbi</> validator
+   to <literal>bob.myvalidator</>:
 <programlisting>
-ALTER FOREIGN DATA WRAPPER dbi LIBRARY '/home/bob/mylibrary.so';
+ALTER FOREIGN DATA WRAPPER dbi VALIDATOR bob.myvalidator;
 </programlisting>
   </para>
  </refsect1>
@@ -115,8 +125,9 @@ ALTER FOREIGN DATA WRAPPER dbi LIBRARY '/home/bob/mylibrary.so';
 
   <para>
    <command>ALTER FOREIGN DATA WRAPPER</command> conforms to ISO/IEC
-   9075-9 (SQL/MED).  The standard does not specify the <literal>OWNER
-   TO</> variant of the command.
+   9075-9 (SQL/MED).  The standard does not specify the <literal>
+   VALIDATOR</literal> and <literal>OWNER TO</> variants of the
+   command.
   </para>
  </refsect1>
 
diff --git a/doc/src/sgml/ref/create_foreign_data_wrapper.sgml b/doc/src/sgml/ref/create_foreign_data_wrapper.sgml
index d46e8e664065016fd69cdfdb95c70d0886bd1ab7..b881710388048cb7493ccf84b1c729f8e9a50522 100644
--- a/doc/src/sgml/ref/create_foreign_data_wrapper.sgml
+++ b/doc/src/sgml/ref/create_foreign_data_wrapper.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_foreign_data_wrapper.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_foreign_data_wrapper.sgml,v 1.2 2009/02/24 10:06:32 petere Exp $
 PostgreSQL documentation
 -->
 
@@ -21,8 +21,7 @@ PostgreSQL documentation
  <refsynopsisdiv>
 <synopsis>
 CREATE FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable>
-    LIBRARY '<replaceable class="parameter">libraryname</replaceable>'
-    LANGUAGE C
+    [ VALIDATOR <replaceable class="parameter">valfunction</replaceable> | NO VALIDATOR ]
     [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] ) ]
 </synopsis>
  </refsynopsisdiv>
@@ -59,25 +58,25 @@ CREATE FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable>
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">libraryname</replaceable></term>
+    <term><literal>VALIDATOR <replaceable class="parameter">valfunction</replaceable></literal></term>
     <listitem>
      <para>
-      The name of the shared library implementing the foreign-data
-      wrapper.  The file name is specified in the same way as for
-      shared library names in <xref linkend="sql-createfunction"
-      endterm="sql-createfunction-title">; in particular, one can rely
-      on a search path and automatic addition of the system's standard
-      shared library file name extension.
-     </para>
-    </listitem>
-   </varlistentry>
-
-   <varlistentry>
-    <term><literal>LANGUAGE C</literal></term>
-    <listitem>
-     <para>
-      Currently, only the C programming language is supported for
-      implementing foreign-data wrappers.
+      <replaceable class="parameter">valfunction</replaceable> is the
+      name of a previously registered function that will be called to
+      check the generic options given to the foreign-data wrapper, as
+      well as to foreign servers and user mappings using the
+      foreign-data wrapper.  If no validator function or <literal>NO
+      VALIDATOR</literal> is specified, then options will not be
+      checked at creation time.  (Foreign-data wrappers will possibly
+      ignore or reject invalid option specifications at run time,
+      depending on the implementation.)  The validator function must
+      take two arguments: one of type <type>text[]</type>, which will
+      contain the array of options as stored in the system catalogs,
+      and one of type <type>oid</type>, which will be the OID of the
+      system catalog containing the options, or zero if the context is
+      not known.  The return type is ignored; the function should
+      indicate invalid options using
+      the <function>ereport()</function> function.
      </para>
     </listitem>
    </varlistentry>
@@ -109,18 +108,11 @@ CREATE FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable>
   </para>
 
   <para>
-   The C language API for foreign-data wrappers is currently not
-   documented, stable, or complete.  Would-be authors of functionality
-   interfacing with the SQL/MED functionality are advised to contact
-   the PostgreSQL developers.
-  </para>
-
-  <para>
-   There are currently two foreign-data wrapper libraries
-   provided: <filename>dummy_fdw</filename>, which does nothing and
-   could be useful for testing,
-   and <filename>postgresql_fdw</filename>, which accepts options
-   corresponding to <application>libpq</> connection parameters.
+   There is currently one foreign-data wrapper validator function
+   provided:
+   <filename>postgresql_fdw_validator</filename>, which accepts
+   options corresponding to <application>libpq</> connection
+   parameters.
   </para>
  </refsect1>
 
@@ -128,28 +120,25 @@ CREATE FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable>
   <title>Examples</title>
 
   <para>
-   Create a foreign-data wrapper <literal>dummy</> with
-   library <literal>dummy_fdw</>:
+   Create a foreign-data wrapper <literal>dummy</>:
 <programlisting>
-CREATE FOREIGN DATA WRAPPER dummy LIBRARY 'dummy_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER dummy;
 </programlisting>
   </para>
 
   <para>
    Create a foreign-data wrapper <literal>postgresql</> with
-   library <literal>postgresql_fdw</>:
+   validator function <literal>postgresql_fdw_validator</>:
 <programlisting>
-CREATE FOREIGN DATA WRAPPER postgresql LIBRARY 'postgresql_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator;
 </programlisting>
   </para>
 
   <para>
-   Create a foreign-data wrapper <literal>mywrapper</> with library
-   <literal>/home/bob/mywrapper.so</> and some options:
+   Create a foreign-data wrapper <literal>mywrapper</> with some
+   options:
 <programlisting>
 CREATE FOREIGN DATA WRAPPER mywrapper
-    LIBRARY '/home/bob/mywrapper.so'
-    LANGUAGE C
     OPTIONS (debug 'true');
 </programlisting>
   </para>
@@ -161,8 +150,9 @@ CREATE FOREIGN DATA WRAPPER mywrapper
   <para>
    <command>CREATE FOREIGN DATA WRAPPER</command> conforms to ISO/IEC
    9075-9 (SQL/MED), with the exception that
-   the <literal>LIBRARY</literal> clause is not optional in
-   PostgreSQL.
+   the <literal>VALIDATOR</literal> clause is an extension and the
+   clauses <literal>LIBRARY</literal> and <literal>LANGUAGE</literal>
+   are not yet implemented in PostgreSQL.
   </para>
 
   <para>
diff --git a/src/Makefile b/src/Makefile
index 13cbeb973456f9aa94e3c4435fd89bbfcc11c15c..7b00776c4bdbc197ae3a6014e4a7b7565b536080 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -4,7 +4,7 @@
 #
 # Copyright (c) 1994, Regents of the University of California
 #
-# $PostgreSQL: pgsql/src/Makefile,v 1.44 2008/12/19 16:25:16 petere Exp $
+# $PostgreSQL: pgsql/src/Makefile,v 1.45 2009/02/24 10:06:32 petere Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -19,7 +19,6 @@ all install installdirs uninstall distprep:
 	$(MAKE) -C backend $@
 	$(MAKE) -C backend/utils/mb/conversion_procs $@
 	$(MAKE) -C backend/snowball $@
-	$(MAKE) -C backend/foreign $@-fdw
 	$(MAKE) -C include $@
 	$(MAKE) -C interfaces $@
 	$(MAKE) -C bin $@
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index 4206e9eaf525b7c32adba75b9667b641b3e8fa37..80132e27ea477b4f707f09bd0fd0db10438c4bc1 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2003-2009, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.52 2009/02/14 20:48:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.53 2009/02/24 10:06:32 petere Exp $
  */
 
 /*
@@ -2428,7 +2428,6 @@ CREATE VIEW _pg_foreign_data_wrappers AS
            CAST(current_database() AS sql_identifier) AS foreign_data_wrapper_catalog,
            CAST(fdwname AS sql_identifier) AS foreign_data_wrapper_name,
            CAST(u.rolname AS sql_identifier) AS authorization_identifier,
-           CAST(fdwlibrary AS character_data) AS library_name,
            CAST('c' AS character_data) AS foreign_data_wrapper_language
     FROM pg_foreign_data_wrapper w, pg_authid u
     WHERE u.oid = w.fdwowner
@@ -2458,7 +2457,7 @@ CREATE VIEW foreign_data_wrappers AS
     SELECT foreign_data_wrapper_catalog,
            foreign_data_wrapper_name,
            authorization_identifier,
-           library_name,
+           CAST(NULL AS character_data) AS library_name,
            foreign_data_wrapper_language
     FROM _pg_foreign_data_wrappers w;
 
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 0967001aa3f61fcb73d9d86d3d5cec7e26d0f932..24052556a4b000d126c35d8d44efc51c629d8c35 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/foreigncmds.c,v 1.5 2009/01/20 09:10:20 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/foreigncmds.c,v 1.6 2009/02/24 10:06:32 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,11 +20,13 @@
 #include "catalog/indexing.h"
 #include "catalog/pg_foreign_data_wrapper.h"
 #include "catalog/pg_foreign_server.h"
+#include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "catalog/pg_user_mapping.h"
 #include "commands/defrem.h"
 #include "foreign/foreign.h"
 #include "miscadmin.h"
+#include "parser/parse_func.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
@@ -90,10 +92,11 @@ transformGenericOptions(Datum oldOptions,
 						List *optionDefList,
 						GenericOptionFlags flags,
 						ForeignDataWrapper *fdw,
-						OptionListValidatorFunc validateOptionList)
+						Oid fdwvalidator)
 {
 	List	 *resultOptions = untransformRelOptions(oldOptions);
 	ListCell *optcell;
+	Datum	  result;
 
 	foreach(optcell, optionDefList)
 	{
@@ -157,10 +160,12 @@ transformGenericOptions(Datum oldOptions,
 		}
 	}
 
-	if (validateOptionList)
-		validateOptionList(fdw, flags, resultOptions);
+	result = optionListToArray(resultOptions);
 
-	return optionListToArray(resultOptions);
+	if (fdwvalidator)
+		OidFunctionCall2(fdwvalidator, result, 0);
+
+	return result;
 }
 
 
@@ -309,6 +314,21 @@ AlterForeignServerOwner(const char *name, Oid newOwnerId)
 }
 
 
+/*
+ * Convert a validator function name passed from the parser to an Oid.
+ */
+static Oid
+lookup_fdw_validator_func(List *validator)
+{
+	Oid			funcargtypes[2];
+
+	funcargtypes[0] = TEXTARRAYOID;
+	funcargtypes[1] = OIDOID;
+	return LookupFuncName(validator, 2, funcargtypes, false);
+	/* return value is ignored, so we don't check the type */
+}
+
+
 /*
  * Create a foreign-data wrapper
  */
@@ -320,9 +340,9 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
 	bool			nulls[Natts_pg_foreign_data_wrapper];
 	HeapTuple		tuple;
 	Oid				fdwId;
+	Oid				fdwvalidator;
 	Datum			fdwoptions;
 	Oid				ownerId;
-	ForeignDataWrapperLibrary  *fdwlib;
 
 	/* Must be super user */
 	if (!superuser())
@@ -355,18 +375,19 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
 	values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
 		DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname));
 	values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
-	values[Anum_pg_foreign_data_wrapper_fdwlibrary - 1] = CStringGetTextDatum(stmt->library);
-	nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
 
-	/*
-	 * See if the FDW library loads at all. We also might want to use it
-	 * later for validating the options.
-	 */
-	fdwlib = GetForeignDataWrapperLibrary(stmt->library);
+	if (stmt->validator)
+		fdwvalidator = lookup_fdw_validator_func(stmt->validator);
+	else
+		fdwvalidator = InvalidOid;
+
+	values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = fdwvalidator;
+
+	nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
 
 	fdwoptions = transformGenericOptions(PointerGetDatum(NULL), stmt->options,
 										 FdwOpt, NULL,
-										 fdwlib->validateOptionList);
+										 fdwvalidator);
 
 	if (PointerIsValid(DatumGetPointer(fdwoptions)))
 		values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
@@ -380,6 +401,21 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
 
 	heap_freetuple(tuple);
 
+	if (fdwvalidator)
+	{
+		ObjectAddress myself;
+		ObjectAddress referenced;
+
+		myself.classId = ForeignDataWrapperRelationId;
+		myself.objectId = fdwId;
+		myself.objectSubId = 0;
+
+		referenced.classId = ProcedureRelationId;
+		referenced.objectId = fdwvalidator;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	}
+
 	recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
 
 	heap_close(rel, NoLock);
@@ -400,7 +436,7 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 	Oid			fdwId;
 	bool		isnull;
 	Datum		datum;
-	ForeignDataWrapperLibrary *fdwlib;
+	Oid			fdwvalidator;
 
 	/* Must be super user */
 	if (!superuser())
@@ -425,36 +461,33 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 	memset(repl_null, false, sizeof(repl_null));
 	memset(repl_repl, false, sizeof(repl_repl));
 
-	if (stmt->library)
+	if (stmt->change_validator)
 	{
-		/*
-		 * New library specified -- load to see if valid.
-		 */
-		fdwlib = GetForeignDataWrapperLibrary(stmt->library);
-
-		repl_val[Anum_pg_foreign_data_wrapper_fdwlibrary - 1] = CStringGetTextDatum(stmt->library);
-		repl_repl[Anum_pg_foreign_data_wrapper_fdwlibrary - 1] = true;
+		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;
 
 		/*
 		 * It could be that the options for the FDW, SERVER and USER MAPPING
-		 * are no longer valid with the new library.  Warn about this.
+		 * are no longer valid with the new validator.  Warn about this.
 		 */
-		ereport(WARNING,
-				(errmsg("changing the foreign-data wrapper library can cause "
-						"the options for dependent objects to become invalid")));
+		if (stmt->validator)
+			ereport(WARNING,
+					(errmsg("changing the foreign-data wrapper validator can cause "
+							"the options for dependent objects to become invalid")));
 	}
 	else
 	{
 		/*
-		 * No LIBRARY clause specified, but we need to load it for validating
+		 * Validator is not changed, but we need it for validating
 		 * options.
 		 */
 		datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
 								tp,
-								Anum_pg_foreign_data_wrapper_fdwlibrary,
+								Anum_pg_foreign_data_wrapper_fdwvalidator,
 								&isnull);
 		Assert(!isnull);
-		fdwlib = GetForeignDataWrapperLibrary(TextDatumGetCString(datum));
+		fdwvalidator = DatumGetObjectId(datum);
 	}
 
 	/*
@@ -472,7 +505,7 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 
 		/* Transform the options */
 		datum = transformGenericOptions(datum, stmt->options, FdwOpt,
-										NULL, fdwlib->validateOptionList);
+										NULL, fdwvalidator);
 
 		if (PointerIsValid(DatumGetPointer(datum)))
 			repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
@@ -640,7 +673,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
 	/* Add server options */
 	srvoptions = transformGenericOptions(PointerGetDatum(NULL), stmt->options,
 										 ServerOpt, fdw,
-										 fdw->lib->validateOptionList);
+										 fdw->fdwvalidator);
 
 	if (PointerIsValid(DatumGetPointer(srvoptions)))
 		values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
@@ -738,7 +771,7 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
 
 		/* Prepare the options array */
 		datum = transformGenericOptions(datum, stmt->options, ServerOpt,
-										fdw, fdw->lib->validateOptionList);
+										fdw, fdw->fdwvalidator);
 
 		if (PointerIsValid(DatumGetPointer(datum)))
 			repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
@@ -910,7 +943,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
 	/* Add user options */
 	useoptions = transformGenericOptions(PointerGetDatum(NULL), stmt->options,
 										 UserMappingOpt,
-										 fdw, fdw->lib->validateOptionList);
+										 fdw, fdw->fdwvalidator);
 
 	if (PointerIsValid(DatumGetPointer(useoptions)))
 		values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
@@ -1005,7 +1038,7 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
 
 		/* Prepare the options array */
 		datum = transformGenericOptions(datum, stmt->options, UserMappingOpt,
-										fdw, fdw->lib->validateOptionList);
+										fdw, fdw->fdwvalidator);
 
 		if (PointerIsValid(DatumGetPointer(datum)))
 			repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
diff --git a/src/backend/foreign/Makefile b/src/backend/foreign/Makefile
index b3cc209c1611feefaaba5381aa84c4f860d9bc6d..dff0c775403b43efb7371bd22fdbfb13c40fbb62 100644
--- a/src/backend/foreign/Makefile
+++ b/src/backend/foreign/Makefile
@@ -4,7 +4,7 @@
 #    Makefile for foreign
 #
 # IDENTIFICATION
-#    $PostgreSQL: pgsql/src/backend/foreign/Makefile,v 1.1 2008/12/19 16:25:17 petere Exp $
+#    $PostgreSQL: pgsql/src/backend/foreign/Makefile,v 1.2 2009/02/24 10:06:32 petere Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -15,11 +15,3 @@ include $(top_builddir)/src/Makefile.global
 OBJS= foreign.o
 
 include $(top_srcdir)/src/backend/common.mk
-
-FDW = dummy postgresql
-
-$(addsuffix -fdw,all install installdirs uninstall distprep):
-	for dir in $(FDW); do $(MAKE) -C $$dir `echo $@ | sed 's/-fdw$$//'` || exit; done
-
-clean distclean maintainer-clean:
-	for dir in $(FDW); do $(MAKE) -C $$dir $@ || exit; done
diff --git a/src/backend/foreign/dummy/Makefile b/src/backend/foreign/dummy/Makefile
deleted file mode 100644
index 8a05ada0197eaf37ca5d64757a29af29b1225762..0000000000000000000000000000000000000000
--- a/src/backend/foreign/dummy/Makefile
+++ /dev/null
@@ -1,27 +0,0 @@
-#-------------------------------------------------------------------------
-#
-# Makefile--
-#    Makefile for dummy foreign-data wrapper
-#
-# IDENTIFICATION
-#    $PostgreSQL: pgsql/src/backend/foreign/dummy/Makefile,v 1.1 2008/12/19 16:25:17 petere Exp $
-#
-#-------------------------------------------------------------------------
-
-subdir = src/backend/foreign/dummy
-top_builddir = ../../../..
-include $(top_builddir)/src/Makefile.global
-
-NAME = dummy_fdw
-OBJS = dummy_fdw.o
-
-include $(top_srcdir)/src/Makefile.shlib
-
-all: all-shared-lib
-
-install: all install-lib
-
-installdirs: installdirs-lib
-
-clean distclean maintainer-clean: clean-lib
-	rm -f $(OBJS)
diff --git a/src/backend/foreign/dummy/dummy_fdw.c b/src/backend/foreign/dummy/dummy_fdw.c
deleted file mode 100644
index a89d68e0ae23dce42e59352df8a1fcd8fcf00054..0000000000000000000000000000000000000000
--- a/src/backend/foreign/dummy/dummy_fdw.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * dummy_fdw.c
- *        "dummy" foreign-data wrapper
- *
- * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- *        $PostgreSQL: pgsql/src/backend/foreign/dummy/dummy_fdw.c,v 1.2 2009/01/01 17:23:42 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "fmgr.h"
-#include "foreign/foreign.h"
-
-PG_MODULE_MAGIC;
-
-/*
- * This looks like a complete waste right now, but it is useful for
- * testing, and will become more interesting as more parts of the
- * interface are implemented.
- */
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index b5b502cc03285535118ec09563d912a7d665ece2..3ec425067773cd1c95f1ad395cb5a4cf5a328c5d 100644
--- a/src/backend/foreign/foreign.c
+++ b/src/backend/foreign/foreign.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *        $PostgreSQL: pgsql/src/backend/foreign/foreign.c,v 1.2 2009/01/01 17:23:42 momjian Exp $
+ *        $PostgreSQL: pgsql/src/backend/foreign/foreign.c,v 1.3 2009/02/24 10:06:32 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,66 +31,12 @@
 
 
 extern Datum pg_options_to_table(PG_FUNCTION_ARGS);
+extern Datum postgresql_fdw_validator(PG_FUNCTION_ARGS);
 
 
-/* list of currently loaded foreign-data wrapper interfaces */
-static List *loaded_fdw_interfaces = NIL;
-
-
-/*
- * GetForeignDataWrapperLibrary - return the named FDW library.  If it
- * is already loaded, use that.  Otherwise allocate, initialize, and
- * store in cache.
- */
-ForeignDataWrapperLibrary *
-GetForeignDataWrapperLibrary(const char *libname)
-{
-	MemoryContext					oldcontext;
-	void		   				   *libhandle = NULL;
-	ForeignDataWrapperLibrary	   *fdwl = NULL;
-	ListCell		   			   *cell;
-
-	/* See if we have the FDW library is already loaded */
-	foreach (cell, loaded_fdw_interfaces)
-	{
-		fdwl = lfirst(cell);
-		if (strcmp(fdwl->libname, libname) == 0)
-			return fdwl;
-	}
-
-	/*
-	 * We don't have it yet, so load and add.  Attempt a load_file()
-	 * first to filter out any missing or unloadable libraries.
-	 */
-	load_file(libname, false);
-
-	oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-
-	fdwl = palloc(sizeof(*fdwl));
-	fdwl->libname = pstrdup(libname);
-	loaded_fdw_interfaces = lappend(loaded_fdw_interfaces, fdwl);
-
-	MemoryContextSwitchTo(oldcontext);
-
-	/*
-	 * Now look up the foreign data wrapper functions.
-	 */
-#define LOOKUP_FUNCTION(name) \
-	(void *)(libhandle ? \
-		lookup_external_function(libhandle, name) \
-		: load_external_function(fdwl->libname, name, false, &libhandle))
-
-	fdwl->validateOptionList = LOOKUP_FUNCTION("_pg_validateOptionList");
-
-	return fdwl;
-}
-
 
 /*
  * GetForeignDataWrapper -  look up the foreign-data wrapper by OID.
- *
- * Here we also deal with loading the FDW library and looking up the
- * actual functions.
  */
 ForeignDataWrapper *
 GetForeignDataWrapper(Oid fdwid)
@@ -114,15 +60,7 @@ GetForeignDataWrapper(Oid fdwid)
 	fdw->fdwid = fdwid;
 	fdw->owner = fdwform->fdwowner;
 	fdw->fdwname = pstrdup(NameStr(fdwform->fdwname));
-
-	/* Extract library name */
-	datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
-							tp,
-							Anum_pg_foreign_data_wrapper_fdwlibrary,
-							&isnull);
-	fdw->fdwlibrary = pstrdup(TextDatumGetCString(datum));
-
-	fdw->lib = GetForeignDataWrapperLibrary(fdw->fdwlibrary);
+	fdw->fdwvalidator = fdwform->fdwvalidator;
 
 	/* Extract the options */
 	datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
@@ -387,3 +325,100 @@ pg_options_to_table(PG_FUNCTION_ARGS)
 
 	return (Datum) 0;
 }
+
+
+/*
+ * 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 || context == InvalidOid) && 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 == InvalidOid || 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/src/backend/foreign/postgresql/Makefile b/src/backend/foreign/postgresql/Makefile
deleted file mode 100644
index 40ed90f8d7090f8a234ace8ab139e5e4ffccf424..0000000000000000000000000000000000000000
--- a/src/backend/foreign/postgresql/Makefile
+++ /dev/null
@@ -1,27 +0,0 @@
-#-------------------------------------------------------------------------
-#
-# Makefile--
-#    Makefile for postgresql foreign-data wrapper
-#
-# IDENTIFICATION
-#    $PostgreSQL: pgsql/src/backend/foreign/postgresql/Makefile,v 1.1 2008/12/19 16:25:17 petere Exp $
-#
-#-------------------------------------------------------------------------
-
-subdir = src/backend/foreign/postgresql
-top_builddir = ../../../..
-include $(top_builddir)/src/Makefile.global
-
-NAME = postgresql_fdw
-OBJS = postgresql_fdw.o
-
-include $(top_srcdir)/src/Makefile.shlib
-
-all: all-shared-lib
-
-install: all install-lib
-
-installdirs: installdirs-lib
-
-clean distclean maintainer-clean: clean-lib
-	rm -f $(OBJS)
diff --git a/src/backend/foreign/postgresql/postgresql_fdw.c b/src/backend/foreign/postgresql/postgresql_fdw.c
deleted file mode 100644
index 3fb4d2f863140bf19e06276fc367d434865411e5..0000000000000000000000000000000000000000
--- a/src/backend/foreign/postgresql/postgresql_fdw.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * postgresql_fdw.c
- *        foreign-data wrapper for postgresql (libpq) connections.
- *
- * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- *        $PostgreSQL: pgsql/src/backend/foreign/postgresql/postgresql_fdw.c,v 1.2 2009/01/01 17:23:42 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "fmgr.h"
-#include "lib/stringinfo.h"
-#include "nodes/value.h"
-#include "nodes/parsenodes.h"
-#include "nodes/makefuncs.h"
-#include "foreign/foreign.h"
-
-PG_MODULE_MAGIC;
-
-
-/*
- * Describes the valid options for postgresql FDW, server and user mapping.
- */
-typedef struct ConnectionOptions {
-	const char		   *optname;		/* Option name */
-	GenericOptionFlags	optflags;		/* Option usage bitmap */
-} ConnectionOptions;
-
-/*
- * Copied from fe-connect.c PQconninfoOptions.
- *
- * The list is small - don't bother with bsearch if it stays so.
- */
-static ConnectionOptions libpq_conninfo_options[] = {
-	{ "authtype",			ServerOpt		},
-	{ "service",			ServerOpt		},
-	{ "user",				UserMappingOpt	},
-	{ "password",			UserMappingOpt	},
-	{ "connect_timeout", 	ServerOpt		},
-	{ "dbname",				ServerOpt		},
-	{ "host",				ServerOpt		},
-	{ "hostaddr",			ServerOpt		},
-	{ "port",				ServerOpt		},
-	{ "tty",				ServerOpt		},
-	{ "options",			ServerOpt		},
-	{ "requiressl",			ServerOpt		},
-	{ "sslmode",			ServerOpt		},
-	{ "gsslib",				ServerOpt		},
-	{ NULL,					InvalidOpt		}
-};
-
-void _PG_fini(void);
-
-
-/*
- * Check if the provided option is one of libpq conninfo options.
- * We look at only options with matching flags.
- */
-static bool
-is_conninfo_option(const char *option, GenericOptionFlags flags)
-{
-	ConnectionOptions *opt;
-
-	for (opt = libpq_conninfo_options; opt->optname != NULL; opt++)
-		if (flags & opt->optflags && 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.
- */
-void
-_pg_validateOptionList(ForeignDataWrapper *fdw, GenericOptionFlags flags,
-				   List *options)
-{
-	ListCell *cell;
-
-	foreach (cell, options)
-	{
-		DefElem    *def = lfirst(cell);
-
-		if (!is_conninfo_option(def->defname, flags))
-		{
-			ConnectionOptions  *opt;
-			StringInfoData		buf;
-			const char		   *objtype;
-
-			/*
-			 * 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 != NULL; opt++)
-				if (flags & opt->optflags)
-					appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "",
-									 opt->optname);
-
-			if (flags & ServerOpt)
-				objtype = "server";
-			else if (flags & UserMappingOpt)
-				objtype = "user mapping";
-			else if (flags & FdwOpt)
-				objtype = "foreign-data wrapper";
-			else
-				objtype = "???";
-
-			ereport(ERROR,
-					(errcode(ERRCODE_SYNTAX_ERROR),
-					 errmsg("invalid option \"%s\" to %s", def->defname, objtype),
-					 errhint("valid %s options are: %s", objtype, buf.data)));
-		}
-	}
-}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bc4232bdc8bc6de3c24a53da9319ea50cc217e17..2175e0c0fc056e6189a8283b2ffe162985fd0fa4 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.423 2009/02/06 23:43:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.424 2009/02/24 10:06:32 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2994,7 +2994,7 @@ _copyCreateFdwStmt(CreateFdwStmt *from)
 	CreateFdwStmt *newnode = makeNode(CreateFdwStmt);
 
 	COPY_STRING_FIELD(fdwname);
-	COPY_STRING_FIELD(library);
+	COPY_NODE_FIELD(validator);
 	COPY_NODE_FIELD(options);
 
 	return newnode;
@@ -3006,7 +3006,8 @@ _copyAlterFdwStmt(AlterFdwStmt *from)
 	AlterFdwStmt *newnode = makeNode(AlterFdwStmt);
 
 	COPY_STRING_FIELD(fdwname);
-	COPY_STRING_FIELD(library);
+	COPY_NODE_FIELD(validator);
+	COPY_SCALAR_FIELD(change_validator);
 	COPY_NODE_FIELD(options);
 
 	return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 2b8b542e7494e8abb805c415cf3c505c00cce97e..4d905dc945ef34445e46e939dafb2880fac927e1 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -22,7 +22,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.347 2009/02/02 19:31:39 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.348 2009/02/24 10:06:32 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1548,7 +1548,7 @@ static bool
 _equalCreateFdwStmt(CreateFdwStmt *a, CreateFdwStmt *b)
 {
 	COMPARE_STRING_FIELD(fdwname);
-	COMPARE_STRING_FIELD(library);
+	COMPARE_NODE_FIELD(validator);
 	COMPARE_NODE_FIELD(options);
 
 	return true;
@@ -1558,7 +1558,8 @@ static bool
 _equalAlterFdwStmt(AlterFdwStmt *a, AlterFdwStmt *b)
 {
 	COMPARE_STRING_FIELD(fdwname);
-	COMPARE_STRING_FIELD(library);
+	COMPARE_NODE_FIELD(validator);
+	COMPARE_SCALAR_FIELD(change_validator);
 	COMPARE_NODE_FIELD(options);
 
 	return true;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 6688324e05ab8f2ba43ed2421f6570ca5bd23b19..3dadbcffdeb24d6afb704f7f4a130fd8cd3e43e3 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.658 2009/02/11 21:11:16 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.659 2009/02/24 10:06:33 petere Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -254,7 +254,7 @@ static TypeName *TableFuncTypeName(List *columns);
 				index_name name file_name cluster_index_specification
 
 %type <list>	func_name handler_name qual_Op qual_all_Op subquery_Op
-				opt_class opt_validator
+				opt_class opt_validator validator_clause
 
 %type <range>	qualified_name OptConstrFromTable
 
@@ -469,7 +469,7 @@ static TypeName *TableFuncTypeName(List *columns);
 	KEY
 
 	LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEAST LEFT LEVEL
-	LIBRARY LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
+	LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
 	LOCK_P LOGIN_P
 
 	MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
@@ -2724,8 +2724,13 @@ handler_name:
 			| name attrs				{ $$ = lcons(makeString($1), $2); }
 		;
 
-opt_validator:
+validator_clause:
 			VALIDATOR handler_name					{ $$ = $2; }
+			| NO VALIDATOR							{ $$ = NIL; }
+		;
+
+opt_validator:
+			validator_clause						{ $$ = $1; }
 			| /*EMPTY*/								{ $$ = NIL; }
 		;
 
@@ -2808,23 +2813,17 @@ DropTableSpaceStmt: DROP TABLESPACE name
 /*****************************************************************************
  *
  * 		QUERY:
- *             CREATE FOREIGN DATA WRAPPER name LIBRARY 'library_name' LANGUAGE C
+ *             CREATE FOREIGN DATA WRAPPER name [ VALIDATOR name ]
  *
  *****************************************************************************/
 
-CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name LIBRARY Sconst LANGUAGE ColId create_generic_options
+CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_validator create_generic_options
 				{
 					CreateFdwStmt *n = makeNode(CreateFdwStmt);
 					n->fdwname = $5;
-					n->library = $7;
-					n->options = $10;
+					n->validator = $6;
+					n->options = $7;
 					$$ = (Node *) n;
-
-					if (pg_strcasecmp($9, "C") != 0)
-						ereport(ERROR,
-								(errcode(ERRCODE_SYNTAX_ERROR),
-								 errmsg("language for foreign-data wrapper must be C"),
-								 scanner_errposition(@9)));
 				}
 		;
 
@@ -2860,19 +2859,21 @@ DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior
  *
  ****************************************************************************/
 
-AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name LIBRARY Sconst alter_generic_options
+AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name validator_clause alter_generic_options
 				{
 					AlterFdwStmt *n = makeNode(AlterFdwStmt);
 					n->fdwname = $5;
-					n->library = $7;
-					n->options = $8;
+					n->validator = $6;
+					n->change_validator = true;
+					n->options = $7;
 					$$ = (Node *) n;
 				}
-			| ALTER FOREIGN DATA_P WRAPPER name LIBRARY Sconst
+			| ALTER FOREIGN DATA_P WRAPPER name validator_clause
 				{
 					AlterFdwStmt *n = makeNode(AlterFdwStmt);
 					n->fdwname = $5;
-					n->library = $7;
+					n->validator = $6;
+					n->change_validator = true;
 					$$ = (Node *) n;
 				}
 			| ALTER FOREIGN DATA_P WRAPPER name alter_generic_options
@@ -10231,7 +10232,6 @@ unreserved_keyword:
 			| INVOKER
 			| ISOLATION
 			| KEY
-			| LIBRARY
 			| LANCOMPILER
 			| LANGUAGE
 			| LARGE_P
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 3f3388e7fefc75b99fab15024054999c7bc8e840..48218df9c4b03825b3b89b7f5e40c51c46821c78 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.209 2009/01/01 17:23:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.210 2009/02/24 10:06:33 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -230,7 +230,6 @@ const ScanKeyword ScanKeywords[] = {
 	{"least", LEAST, COL_NAME_KEYWORD},
 	{"left", LEFT, TYPE_FUNC_NAME_KEYWORD},
 	{"level", LEVEL, UNRESERVED_KEYWORD},
-	{"library", LIBRARY, UNRESERVED_KEYWORD},
 	{"like", LIKE, TYPE_FUNC_NAME_KEYWORD},
 	{"limit", LIMIT, RESERVED_KEYWORD},
 	{"listen", LISTEN, UNRESERVED_KEYWORD},
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 824f2fb090492eb19ee9cc3283c681e049a563bf..1e971bc37cd05fe8ecbfba46ee33dc52c0a01679 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12,7 +12,7 @@
  *	by PostgreSQL
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.524 2009/02/18 12:07:07 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.525 2009/02/24 10:06:33 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -5394,7 +5394,7 @@ getForeignDataWrappers(int *numForeignDataWrappers)
 	int			i_oid;
 	int			i_fdwname;
 	int			i_rolname;
-	int			i_fdwlibrary;
+	int			i_fdwvalidator;
 	int			i_fdwacl;
 	int			i_fdwoptions;
 
@@ -5409,7 +5409,7 @@ getForeignDataWrappers(int *numForeignDataWrappers)
 	selectSourceSchema("pg_catalog");
 
 	appendPQExpBuffer(query, "SELECT oid, fdwname, "
-					  "(%s fdwowner) AS rolname, fdwlibrary, fdwacl,"
+					  "(%s fdwowner) AS rolname, fdwvalidator::pg_catalog.regproc, fdwacl,"
 					  "array_to_string(ARRAY("
 					  "		SELECT option_name || ' ' || quote_literal(option_value) "
 					  "		FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
@@ -5427,7 +5427,7 @@ getForeignDataWrappers(int *numForeignDataWrappers)
 	i_oid = PQfnumber(res, "oid");
 	i_fdwname = PQfnumber(res, "fdwname");
 	i_rolname = PQfnumber(res, "rolname");
-	i_fdwlibrary = PQfnumber(res, "fdwlibrary");
+	i_fdwvalidator = PQfnumber(res, "fdwvalidator");
 	i_fdwacl = PQfnumber(res, "fdwacl");
 	i_fdwoptions = PQfnumber(res, "fdwoptions");
 
@@ -5439,7 +5439,7 @@ getForeignDataWrappers(int *numForeignDataWrappers)
 		fdwinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_fdwname));
 		fdwinfo[i].dobj.namespace = NULL;
 		fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
-		fdwinfo[i].fdwlibrary = strdup(PQgetvalue(res, i, i_fdwlibrary));
+		fdwinfo[i].fdwvalidator = strdup(PQgetvalue(res, i, i_fdwvalidator));
 		fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions));
 		fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl));
 
@@ -9308,8 +9308,13 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 	q = createPQExpBuffer();
 	delq = createPQExpBuffer();
 
-	appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s LIBRARY '%s' LANGUAGE C",
-					  fmtId(fdwinfo->dobj.name), fdwinfo->fdwlibrary);
+	appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
+					  fmtId(fdwinfo->dobj.name));
+
+	if (fdwinfo->fdwvalidator && strcmp(fdwinfo->fdwvalidator, "-") != 0)
+		appendPQExpBuffer(q, " VALIDATOR %s",
+						  fdwinfo->fdwvalidator);
+
 	if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0)
 		appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
 
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 9a38645fd532815e6d1887b9ae9c0a523a6a2fe7..6c5e48f273a68008833787feb38696f86c9ab306 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.152 2009/02/18 12:07:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.153 2009/02/24 10:06:34 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -409,7 +409,7 @@ typedef struct _fdwInfo
 {
 	DumpableObject dobj;
 	char	   *rolname;
-	char	   *fdwlibrary;
+	char	   *fdwvalidator;
 	char	   *fdwoptions;
 	char	   *fdwacl;
 } FdwInfo;
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index beab9ca5281eceffd8848574e27a1826420da3ad..0cc52c8b71a21892b16e87edadee38a9314a2347 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -8,7 +8,7 @@
  *
  * Copyright (c) 2000-2009, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.200 2009/02/23 15:59:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.201 2009/02/24 10:06:34 petere Exp $
  */
 #include "postgres_fe.h"
 
@@ -2894,10 +2894,10 @@ listForeignDataWrappers(const char *pattern, bool verbose)
 	printfPQExpBuffer(&buf,
 					  "SELECT fdwname AS \"%s\",\n"
 					  "  pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n"
-					  "  fdwlibrary AS \"%s\"",
+					  "  fdwvalidator::pg_catalog.regproc AS \"%s\"",
 					  gettext_noop("Name"),
 					  gettext_noop("Owner"),
-					  gettext_noop("Library"));
+					  gettext_noop("Validator"));
 
 	if (verbose)
 	{
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index d4b977bd6d2f833a13f37360fe56d7d5b73ddce2..363857542eaa45930cd27fde5897e28d2cb3a3b6 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2009, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.179 2009/01/01 17:23:55 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.180 2009/02/24 10:06:34 petere Exp $
  */
 
 /*----------------------------------------------------------------------
@@ -749,7 +749,7 @@ psql_completion(char *text, int start, int end)
 			 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
 	{
 		static const char *const list_ALTER_FDW[] =
-		{"LIBRARY", "OPTIONS", "OWNER TO", NULL};
+		{"VALIDATOR", "OPTIONS", "OWNER TO", NULL};
 
 		COMPLETE_WITH_LIST(list_ALTER_FDW);
 	}
@@ -1258,12 +1258,7 @@ psql_completion(char *text, int start, int end)
 			 pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
 			 pg_strcasecmp(prev3_wd, "DATA") == 0 &&
 			 pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
-		COMPLETE_WITH_CONST("LIBRARY");
-
-	else if (pg_strcasecmp(prev5_wd, "DATA") == 0 &&
-			 pg_strcasecmp(prev4_wd, "WRAPPER") == 0 &&
-			 pg_strcasecmp(prev2_wd, "LIBRARY") == 0)
-		COMPLETE_WITH_CONST("LANGUAGE C");
+		COMPLETE_WITH_CONST("VALIDATOR");
 
 	/* CREATE INDEX */
 	/* First off we complete CREATE UNIQUE with "INDEX" */
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 08b2969d96f8798aa6608523272841f252a06c2a..784ba6889193b76345a649674027797967df791d 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.523 2009/02/09 21:18:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.524 2009/02/24 10:06:34 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200902092
+#define CATALOG_VERSION_NO	200902242
 
 #endif
diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h
index c6d905ca1b99e6aceb24333b8e56daf4aab23869..bb7e903db3690bea403834e70d8bd74b902eaa67 100644
--- a/src/include/catalog/pg_foreign_data_wrapper.h
+++ b/src/include/catalog/pg_foreign_data_wrapper.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_foreign_data_wrapper.h,v 1.2 2009/01/01 17:23:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_foreign_data_wrapper.h,v 1.3 2009/02/24 10:06:34 petere Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -32,10 +32,10 @@ CATALOG(pg_foreign_data_wrapper,2328)
 {
 	NameData	fdwname;		/* foreign-data wrapper name */
 	Oid			fdwowner;		/* FDW owner */
+	Oid			fdwvalidator;	/* optional validation function */
 
 	/* VARIABLE LENGTH FIELDS start here. */
 
-	text		fdwlibrary;		/* FDW shared library location */
 	aclitem		fdwacl[1];		/* access permissions */
 	text		fdwoptions[1];	/* FDW options */
 } FormData_pg_foreign_data_wrapper;
@@ -55,7 +55,7 @@ typedef FormData_pg_foreign_data_wrapper *Form_pg_foreign_data_wrapper;
 #define Natts_pg_foreign_data_wrapper				5
 #define Anum_pg_foreign_data_wrapper_fdwname		1
 #define Anum_pg_foreign_data_wrapper_fdwowner		2
-#define Anum_pg_foreign_data_wrapper_fdwlibrary		3
+#define Anum_pg_foreign_data_wrapper_fdwvalidator	3
 #define Anum_pg_foreign_data_wrapper_fdwacl			4
 #define Anum_pg_foreign_data_wrapper_fdwoptions		5
 
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index d657e9826c3f4809488d67e289c8162d38a1da36..b0c5be4323f3893a75ba220a5e5da787c259e8e3 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.536 2009/02/06 21:15:11 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.537 2009/02/24 10:06:34 petere Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -3682,6 +3682,8 @@ DESCR("total disk space usage for the specified table and associated indexes and
 DATA(insert OID = 2288 ( pg_size_pretty			PGNSP PGUID 12 1 0 0 f f f t f v 1 0 25 "20" _null_ _null_ _null_ _null_ pg_size_pretty _null_ _null_ _null_ ));
 DESCR("convert a long int to a human readable text using size units");
 
+DATA(insert OID = 2316 ( postgresql_fdw_validator PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "1009 26" _null_ _null_ _null_ _null_ postgresql_fdw_validator _null_ _null_ _null_));
+
 DATA(insert OID = 2290 (  record_in			PGNSP PGUID 12 1 0 0 f f f t f v 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 f f f t f v 1 0 2275 "2249" _null_ _null_ _null_ _null_ record_out _null_ _null_ _null_ ));
diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h
index 5792903aa41ddbf8cd89ac8ab4a075863aa97b04..dc5d2af87d09e1a83c30fc425023cd83fa9818a0 100644
--- a/src/include/foreign/foreign.h
+++ b/src/include/foreign/foreign.h
@@ -6,7 +6,7 @@
  *
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/foreign/foreign.h,v 1.2 2009/01/01 17:23:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/foreign/foreign.h,v 1.3 2009/02/24 10:06:35 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,17 +33,13 @@ typedef enum {
 	FdwOpt = 4,					/* options for FOREIGN DATA WRAPPER */
 } GenericOptionFlags;
 
-typedef struct ForeignDataWrapperLibrary ForeignDataWrapperLibrary;
-
 typedef struct ForeignDataWrapper
 {
 	Oid		fdwid;				/* FDW Oid */
 	Oid		owner;				/* FDW owner user Oid */
 	char   *fdwname;			/* Name of the FDW */
-	char   *fdwlibrary;			/* Library name */
+	Oid		fdwvalidator;
 	List   *options;			/* fdwoptions as DefElem list */
-
-	ForeignDataWrapperLibrary *lib;	/* interface to the FDW functions */
 } ForeignDataWrapper;
 
 typedef struct ForeignServer
@@ -65,25 +61,6 @@ typedef struct UserMapping
 } UserMapping;
 
 
-/*
- * Foreign-data wrapper library function types.
- */
-typedef void (*OptionListValidatorFunc)(ForeignDataWrapper *,
-										GenericOptionFlags,
-										List *);
-
-/*
- * Interface functions to the foreign-data wrapper. This is decoupled
- * from the FDW as there maybe several FDW-s accessing the same library.
- */
-struct ForeignDataWrapperLibrary
-{
-	char 	   *libname;		/* name of the library file */
-
-	OptionListValidatorFunc	validateOptionList;
-};
-
-
 extern ForeignServer *GetForeignServer(Oid serverid);
 extern ForeignServer *GetForeignServerByName(const char *name, bool missing_ok);
 extern Oid GetForeignServerOidByName(const char *name, bool missing_ok);
@@ -92,7 +69,6 @@ extern ForeignDataWrapper *GetForeignDataWrapper(Oid fdwid);
 extern ForeignDataWrapper *GetForeignDataWrapperByName(const char *name,
 													   bool missing_ok);
 extern Oid GetForeignDataWrapperOidByName(const char *name, bool missing_ok);
-extern ForeignDataWrapperLibrary *GetForeignDataWrapperLibrary(const char *libname);
 
 /* Foreign data wrapper interface functions */
 extern void _pg_validateOptionList(ForeignDataWrapper *fdw,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 23ffaabb4e11aa664115e9bab707238d3845f2ad..a7f1514f617eb0190a22208a8409423d58d20484 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.391 2009/02/11 21:11:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.392 2009/02/24 10:06:35 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1468,7 +1468,7 @@ typedef struct CreateFdwStmt
 {
 	NodeTag		type;
 	char	   *fdwname;		/* foreign-data wrapper name */
-	char	   *library;		/* libray name */
+	List	   *validator;		/* optional validator function (qual. name) */
 	List	   *options;		/* generic options to FDW */
 } CreateFdwStmt;
 
@@ -1476,7 +1476,8 @@ typedef struct AlterFdwStmt
 {
 	NodeTag		type;
 	char	   *fdwname;		/* foreign-data wrapper name */
-	char	   *library;		/* libray name */
+	List	   *validator;		/* optional validator function (qual. name) */
+	bool		change_validator;
 	List	   *options;		/* generic options to FDW */
 } AlterFdwStmt;
 
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index 351c2d07822ec979fb05b81a42bca4c12202d709..229d57a09a7081bc005065dcc75a3cd8a9865ca9 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -13,14 +13,14 @@ CREATE ROLE regress_test_role2;
 CREATE ROLE regress_test_role_super SUPERUSER;
 CREATE ROLE regress_test_indirect;
 CREATE ROLE unprivileged_role;
-CREATE FOREIGN DATA WRAPPER dummy LIBRARY 'dummy_fdw' LANGUAGE C;
-CREATE FOREIGN DATA WRAPPER postgresql LIBRARY 'postgresql_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER dummy;
+CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator;
 -- At this point we should have 2 built-in wrappers and no servers.
-SELECT fdwname, fdwlibrary, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3;
-  fdwname   |   fdwlibrary   | fdwoptions 
-------------+----------------+------------
- dummy      | dummy_fdw      | 
- postgresql | postgresql_fdw | 
+SELECT fdwname, fdwvalidator::regproc, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3;
+  fdwname   |       fdwvalidator       | fdwoptions 
+------------+--------------------------+------------
+ dummy      | -                        | 
+ postgresql | postgresql_fdw_validator | 
 (2 rows)
 
 SELECT srvname, srvoptions FROM pg_foreign_server;
@@ -34,78 +34,75 @@ SELECT * FROM pg_user_mapping;
 (0 rows)
 
 -- CREATE FOREIGN DATA WRAPPER
-CREATE FOREIGN DATA WRAPPER foo LIBRARY '' LANGUAGE C;            -- ERROR
-ERROR:  could not access file "": No such file or directory
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql' LANGUAGE C;
-DROP FOREIGN DATA WRAPPER foo;
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER foo VALIDATOR bar;            -- ERROR
+ERROR:  function bar(text[], oid) does not exist
+CREATE FOREIGN DATA WRAPPER foo;
 \dew
-          List of foreign-data wrappers
-    Name    |       Owner       |    Library     
-------------+-------------------+----------------
- dummy      | foreign_data_user | dummy_fdw
- foo        | foreign_data_user | dummy_fdw
- postgresql | foreign_data_user | postgresql_fdw
+               List of foreign-data wrappers
+    Name    |       Owner       |        Validator         
+------------+-------------------+--------------------------
+ dummy      | foreign_data_user | -
+ foo        | foreign_data_user | -
+ postgresql | foreign_data_user | postgresql_fdw_validator
 (3 rows)
 
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C; -- duplicate
+CREATE FOREIGN DATA WRAPPER foo; -- duplicate
 ERROR:  foreign-data wrapper "foo" already exists
-CREATE FOREIGN DATA WRAPPER "Foo" LIBRARY 'dummy_fdw' LANGUAGE C;
-DROP FOREIGN DATA WRAPPER "Foo";
 DROP FOREIGN DATA WRAPPER foo;
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1');
+CREATE FOREIGN DATA WRAPPER foo OPTIONS (testing '1');
 \dew+
-                           List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges |   Options   
-------------+-------------------+----------------+-------------------+-------------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- foo        | foreign_data_user | dummy_fdw      |                   | {testing=1}
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                                List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges |   Options   
+------------+-------------------+--------------------------+-------------------+-------------
+ dummy      | foreign_data_user | -                        |                   | 
+ foo        | foreign_data_user | -                        |                   | {testing=1}
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (3 rows)
 
 DROP FOREIGN DATA WRAPPER foo;
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1', testing '2');   -- ERROR
+CREATE FOREIGN DATA WRAPPER foo OPTIONS (testing '1', testing '2');   -- ERROR
 ERROR:  option "testing" provided more than once
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1', another '2');
+CREATE FOREIGN DATA WRAPPER foo OPTIONS (testing '1', another '2');
 \dew+
-                                List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges |        Options        
-------------+-------------------+----------------+-------------------+-----------------------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- foo        | foreign_data_user | dummy_fdw      |                   | {testing=1,another=2}
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                                     List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges |        Options        
+------------+-------------------+--------------------------+-------------------+-----------------------
+ dummy      | foreign_data_user | -                        |                   | 
+ foo        | foreign_data_user | -                        |                   | {testing=1,another=2}
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (3 rows)
 
 DROP FOREIGN DATA WRAPPER foo;
 SET ROLE regress_test_role;
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+CREATE FOREIGN DATA WRAPPER foo; -- ERROR
 ERROR:  permission denied to create foreign-data wrapper "foo"
 HINT:  Must be superuser to create a foreign-data wrapper.
 RESET ROLE;
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'postgresql_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER foo VALIDATOR postgresql_fdw_validator;
 \dew+
-                         List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges | Options 
-------------+-------------------+----------------+-------------------+---------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- foo        | foreign_data_user | postgresql_fdw |                   | 
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                              List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges | Options 
+------------+-------------------+--------------------------+-------------------+---------
+ dummy      | foreign_data_user | -                        |                   | 
+ foo        | foreign_data_user | postgresql_fdw_validator |                   | 
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (3 rows)
 
 -- ALTER FOREIGN DATA WRAPPER
-ALTER FOREIGN DATA WRAPPER foo LIBRARY '';                  -- ERROR
-ERROR:  could not access file "": No such file or directory
-ALTER FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql';
-WARNING:  changing the foreign-data wrapper library can cause the options for dependent objects to become invalid
-ALTER FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw';
-WARNING:  changing the foreign-data wrapper library can cause the options for dependent objects to become invalid
+ALTER FOREIGN DATA WRAPPER foo;                             -- ERROR
+ERROR:  syntax error at or near ";"
+LINE 1: ALTER FOREIGN DATA WRAPPER foo;
+                                      ^
+ALTER FOREIGN DATA WRAPPER foo VALIDATOR bar;               -- ERROR
+ERROR:  function bar(text[], oid) does not exist
+ALTER FOREIGN DATA WRAPPER foo NO VALIDATOR;
 \dew+
-                         List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges | Options 
-------------+-------------------+----------------+-------------------+---------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- foo        | foreign_data_user | dummy_fdw      |                   | 
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                              List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges | Options 
+------------+-------------------+--------------------------+-------------------+---------
+ dummy      | foreign_data_user | -                        |                   | 
+ foo        | foreign_data_user | -                        |                   | 
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (3 rows)
 
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (a '1', b '2');
@@ -115,34 +112,34 @@ ALTER FOREIGN DATA WRAPPER foo OPTIONS (DROP c);            -- ERROR
 ERROR:  option "c" not found
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD x '1', DROP x);
 \dew+
-                          List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges |  Options  
-------------+-------------------+----------------+-------------------+-----------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- foo        | foreign_data_user | dummy_fdw      |                   | {a=1,b=2}
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                               List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges |  Options  
+------------+-------------------+--------------------------+-------------------+-----------
+ dummy      | foreign_data_user | -                        |                   | 
+ foo        | foreign_data_user | -                        |                   | {a=1,b=2}
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (3 rows)
 
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (DROP a, SET b '3', ADD c '4');
 \dew+
-                          List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges |  Options  
-------------+-------------------+----------------+-------------------+-----------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- foo        | foreign_data_user | dummy_fdw      |                   | {b=3,c=4}
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                               List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges |  Options  
+------------+-------------------+--------------------------+-------------------+-----------
+ dummy      | foreign_data_user | -                        |                   | 
+ foo        | foreign_data_user | -                        |                   | {b=3,c=4}
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (3 rows)
 
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (a '2');
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (b '4');             -- ERROR
 ERROR:  option "b" provided more than once
 \dew+
-                            List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges |    Options    
-------------+-------------------+----------------+-------------------+---------------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- foo        | foreign_data_user | dummy_fdw      |                   | {b=3,c=4,a=2}
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                                 List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges |    Options    
+------------+-------------------+--------------------------+-------------------+---------------
+ dummy      | foreign_data_user | -                        |                   | 
+ foo        | foreign_data_user | -                        |                   | {b=3,c=4,a=2}
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (3 rows)
 
 SET ROLE regress_test_role;
@@ -152,12 +149,12 @@ HINT:  Must be superuser to alter a foreign-data wrapper.
 SET ROLE regress_test_role_super;
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD d '5');
 \dew+
-                              List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges |      Options      
-------------+-------------------+----------------+-------------------+-------------------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- foo        | foreign_data_user | dummy_fdw      |                   | {b=3,c=4,a=2,d=5}
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                                   List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges |      Options      
+------------+-------------------+--------------------------+-------------------+-------------------
+ dummy      | foreign_data_user | -                        |                   | 
+ foo        | foreign_data_user | -                        |                   | {b=3,c=4,a=2,d=5}
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (3 rows)
 
 ALTER FOREIGN DATA WRAPPER foo OWNER TO regress_test_role;  -- ERROR
@@ -171,12 +168,12 @@ ERROR:  permission denied to alter foreign-data wrapper "foo"
 HINT:  Must be superuser to alter a foreign-data wrapper.
 RESET ROLE;
 \dew+
-                                 List of foreign-data wrappers
-    Name    |          Owner          |    Library     | Access privileges |      Options      
-------------+-------------------------+----------------+-------------------+-------------------
- dummy      | foreign_data_user       | dummy_fdw      |                   | 
- foo        | regress_test_role_super | dummy_fdw      |                   | {b=3,c=4,a=2,d=5}
- postgresql | foreign_data_user       | postgresql_fdw |                   | 
+                                      List of foreign-data wrappers
+    Name    |          Owner          |        Validator         | Access privileges |      Options      
+------------+-------------------------+--------------------------+-------------------+-------------------
+ dummy      | foreign_data_user       | -                        |                   | 
+ foo        | regress_test_role_super | -                        |                   | {b=3,c=4,a=2,d=5}
+ postgresql | foreign_data_user       | postgresql_fdw_validator |                   | 
 (3 rows)
 
 -- DROP FOREIGN DATA WRAPPER
@@ -185,12 +182,12 @@ ERROR:  foreign-data wrapper "nonexistent" does not exist
 DROP FOREIGN DATA WRAPPER IF EXISTS nonexistent;
 NOTICE:  foreign-data wrapper "nonexistent" does not exist, skipping
 \dew+
-                                 List of foreign-data wrappers
-    Name    |          Owner          |    Library     | Access privileges |      Options      
-------------+-------------------------+----------------+-------------------+-------------------
- dummy      | foreign_data_user       | dummy_fdw      |                   | 
- foo        | regress_test_role_super | dummy_fdw      |                   | {b=3,c=4,a=2,d=5}
- postgresql | foreign_data_user       | postgresql_fdw |                   | 
+                                      List of foreign-data wrappers
+    Name    |          Owner          |        Validator         | Access privileges |      Options      
+------------+-------------------------+--------------------------+-------------------+-------------------
+ dummy      | foreign_data_user       | -                        |                   | 
+ foo        | regress_test_role_super | -                        |                   | {b=3,c=4,a=2,d=5}
+ postgresql | foreign_data_user       | postgresql_fdw_validator |                   | 
 (3 rows)
 
 DROP ROLE regress_test_role_super;                          -- ERROR
@@ -205,23 +202,23 @@ ALTER ROLE regress_test_role_super SUPERUSER;
 DROP FOREIGN DATA WRAPPER foo;
 DROP ROLE regress_test_role_super;
 \dew+
-                         List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges | Options 
-------------+-------------------+----------------+-------------------+---------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                              List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges | Options 
+------------+-------------------+--------------------------+-------------------+---------
+ dummy      | foreign_data_user | -                        |                   | 
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (2 rows)
 
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER foo;
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
 CREATE USER MAPPING FOR current_user SERVER s1;
 \dew+
-                         List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges | Options 
-------------+-------------------+----------------+-------------------+---------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- foo        | foreign_data_user | dummy_fdw      |                   | 
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                              List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges | Options 
+------------+-------------------+--------------------------+-------------------+---------
+ dummy      | foreign_data_user | -                        |                   | 
+ foo        | foreign_data_user | -                        |                   | 
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (3 rows)
 
 \des+
@@ -253,11 +250,11 @@ NOTICE:  drop cascades to 2 other objects
 DETAIL:  drop cascades to server s1
 drop cascades to user mapping for foreign_data_user
 \dew+
-                         List of foreign-data wrappers
-    Name    |       Owner       |    Library     | Access privileges | Options 
-------------+-------------------+----------------+-------------------+---------
- dummy      | foreign_data_user | dummy_fdw      |                   | 
- postgresql | foreign_data_user | postgresql_fdw |                   | 
+                              List of foreign-data wrappers
+    Name    |       Owner       |        Validator         | Access privileges | Options 
+------------+-------------------+--------------------------+-------------------+---------
+ dummy      | foreign_data_user | -                        |                   | 
+ postgresql | foreign_data_user | postgresql_fdw_validator |                   | 
 (2 rows)
 
 \des+
@@ -275,7 +272,7 @@ drop cascades to user mapping for foreign_data_user
 -- exercise CREATE SERVER
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;                  -- ERROR
 ERROR:  foreign-data wrapper "foo" does not exist
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (test_wrapper 'true');
+CREATE FOREIGN DATA WRAPPER foo OPTIONS (test_wrapper 'true');
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;                  -- ERROR
 ERROR:  server "s1" already exists
@@ -286,8 +283,8 @@ CREATE SERVER s5 VERSION '15.0' FOREIGN DATA WRAPPER foo;
 CREATE SERVER s6 VERSION '16.0' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
 CREATE SERVER s7 TYPE 'oracle' VERSION '17.0' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
 CREATE SERVER s8 FOREIGN DATA WRAPPER postgresql OPTIONS (foo '1'); -- ERROR
-ERROR:  invalid option "foo" to server
-HINT:  valid server options are: authtype, service, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib
+ERROR:  invalid option "foo"
+HINT:  Valid options in this context are: authtype, service, user, password, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib
 CREATE SERVER s8 FOREIGN DATA WRAPPER postgresql OPTIONS (host 'localhost', dbname 's8db');
 \des+
                                                 List of foreign servers
@@ -397,8 +394,8 @@ ALTER SERVER s1 OWNER TO regress_test_role2;                -- ERROR
 ERROR:  permission denied for foreign-data wrapper foo
 RESET ROLE;
 ALTER SERVER s8 OPTIONS (foo '1');                          -- ERROR option validation
-ERROR:  invalid option "foo" to server
-HINT:  valid server options are: authtype, service, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib
+ERROR:  invalid option "foo"
+HINT:  Valid options in this context are: authtype, service, user, password, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib
 ALTER SERVER s8 OPTIONS (connect_timeout '30', SET dbname 'db1', DROP host);
 SET ROLE regress_test_role;
 ALTER SERVER s1 OWNER TO regress_test_indirect;             -- ERROR
@@ -536,8 +533,8 @@ CREATE USER MAPPING FOR user SERVER s4;                     -- ERROR duplicate
 ERROR:  user mapping "foreign_data_user" already exists for server s4
 CREATE USER MAPPING FOR public SERVER s4 OPTIONS (mapping 'is public');
 CREATE USER MAPPING FOR user SERVER s8 OPTIONS (username 'test', password 'secret');    -- ERROR
-ERROR:  invalid option "username" to user mapping
-HINT:  valid user mapping options are: user, password
+ERROR:  invalid option "username"
+HINT:  Valid options in this context are: authtype, service, user, password, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib
 CREATE USER MAPPING FOR user SERVER s8 OPTIONS (user 'test', password 'secret');
 ALTER SERVER s5 OWNER TO regress_test_role;
 ALTER SERVER s6 OWNER TO regress_test_indirect;
@@ -575,8 +572,8 @@ ERROR:  server "ss4" does not exist
 ALTER USER MAPPING FOR public SERVER s5 OPTIONS (gotcha 'true');            -- ERROR
 ERROR:  user mapping "public" does not exist for the server
 ALTER USER MAPPING FOR current_user SERVER s8 OPTIONS (username 'test');    -- ERROR
-ERROR:  invalid option "username" to user mapping
-HINT:  valid user mapping options are: user, password
+ERROR:  invalid option "username"
+HINT:  Valid options in this context are: authtype, service, user, password, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib
 ALTER USER MAPPING FOR current_user SERVER s8 OPTIONS (DROP user, SET password 'public');
 SET ROLE regress_test_role;
 ALTER USER MAPPING FOR current_user SERVER s5 OPTIONS (ADD modified '1');
@@ -632,11 +629,11 @@ DROP SERVER s7;
 
 -- Information schema
 SELECT * FROM information_schema.foreign_data_wrappers ORDER BY 1, 2;
- foreign_data_wrapper_catalog | foreign_data_wrapper_name | authorization_identifier |  library_name  | foreign_data_wrapper_language 
-------------------------------+---------------------------+--------------------------+----------------+-------------------------------
- regression                   | dummy                     | foreign_data_user        | dummy_fdw      | c
- regression                   | foo                       | foreign_data_user        | dummy_fdw      | c
- regression                   | postgresql                | foreign_data_user        | postgresql_fdw | c
+ foreign_data_wrapper_catalog | foreign_data_wrapper_name | authorization_identifier | library_name | foreign_data_wrapper_language 
+------------------------------+---------------------------+--------------------------+--------------+-------------------------------
+ regression                   | dummy                     | foreign_data_user        |              | c
+ regression                   | foo                       | foreign_data_user        |              | c
+ regression                   | postgresql                | foreign_data_user        |              | c
 (3 rows)
 
 SELECT * FROM information_schema.foreign_data_wrapper_options ORDER BY 1, 2, 3;
@@ -847,13 +844,11 @@ GRANT USAGE ON FOREIGN SERVER s4 TO regress_test_role;
 DROP USER MAPPING FOR public SERVER s4;
 ALTER SERVER s6 OPTIONS (DROP host, DROP dbname);
 ALTER USER MAPPING FOR regress_test_role SERVER s6 OPTIONS (DROP username);
-ALTER FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql';
-WARNING:  changing the foreign-data wrapper library can cause the options for dependent objects to become invalid
-ALTER FOREIGN DATA WRAPPER foo LIBRARY 'default_fdw';
-ERROR:  could not access file "default_fdw": No such file or directory
+ALTER FOREIGN DATA WRAPPER foo VALIDATOR postgresql_fdw_validator;
+WARNING:  changing the foreign-data wrapper validator can cause the options for dependent objects to become invalid
 -- Privileges
 SET ROLE unprivileged_role;
-CREATE FOREIGN DATA WRAPPER foobar LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+CREATE FOREIGN DATA WRAPPER foobar;                             -- ERROR
 ERROR:  permission denied to create foreign-data wrapper "foobar"
 HINT:  Must be superuser to create a foreign-data wrapper.
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (gotcha 'true');         -- ERROR
@@ -887,7 +882,7 @@ RESET ROLE;
 GRANT USAGE ON FOREIGN DATA WRAPPER postgresql TO unprivileged_role;
 GRANT USAGE ON FOREIGN DATA WRAPPER foo TO unprivileged_role WITH GRANT OPTION;
 SET ROLE unprivileged_role;
-CREATE FOREIGN DATA WRAPPER foobar LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+CREATE FOREIGN DATA WRAPPER foobar;                             -- ERROR
 ERROR:  permission denied to create foreign-data wrapper "foobar"
 HINT:  Must be superuser to create a foreign-data wrapper.
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (gotcha 'true');         -- ERROR
@@ -982,9 +977,9 @@ DROP FOREIGN DATA WRAPPER dummy CASCADE;
 \c
 DROP ROLE foreign_data_user;
 -- At this point we should have no wrappers, no servers, and no mappings.
-SELECT fdwname, fdwlibrary, fdwoptions FROM pg_foreign_data_wrapper;
- fdwname | fdwlibrary | fdwoptions 
----------+------------+------------
+SELECT fdwname, fdwvalidator, fdwoptions FROM pg_foreign_data_wrapper;
+ fdwname | fdwvalidator | fdwoptions 
+---------+--------------+------------
 (0 rows)
 
 SELECT srvname, srvoptions FROM pg_foreign_server;
diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql
index c52fe912c1d128b65ce93fbc871f59cbae567eb3..4318de5c7c7a1557b6c73b5edf3bf3a4b50c8492 100644
--- a/src/test/regress/sql/foreign_data.sql
+++ b/src/test/regress/sql/foreign_data.sql
@@ -20,44 +20,40 @@ CREATE ROLE regress_test_role_super SUPERUSER;
 CREATE ROLE regress_test_indirect;
 CREATE ROLE unprivileged_role;
 
-CREATE FOREIGN DATA WRAPPER dummy LIBRARY 'dummy_fdw' LANGUAGE C;
-CREATE FOREIGN DATA WRAPPER postgresql LIBRARY 'postgresql_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER dummy;
+CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator;
 
 -- At this point we should have 2 built-in wrappers and no servers.
-SELECT fdwname, fdwlibrary, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3;
+SELECT fdwname, fdwvalidator::regproc, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3;
 SELECT srvname, srvoptions FROM pg_foreign_server;
 SELECT * FROM pg_user_mapping;
 
 -- CREATE FOREIGN DATA WRAPPER
-CREATE FOREIGN DATA WRAPPER foo LIBRARY '' LANGUAGE C;            -- ERROR
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql' LANGUAGE C;
-DROP FOREIGN DATA WRAPPER foo;
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER foo VALIDATOR bar;            -- ERROR
+CREATE FOREIGN DATA WRAPPER foo;
 \dew
 
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C; -- duplicate
-CREATE FOREIGN DATA WRAPPER "Foo" LIBRARY 'dummy_fdw' LANGUAGE C;
-DROP FOREIGN DATA WRAPPER "Foo";
+CREATE FOREIGN DATA WRAPPER foo; -- duplicate
 DROP FOREIGN DATA WRAPPER foo;
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1');
+CREATE FOREIGN DATA WRAPPER foo OPTIONS (testing '1');
 \dew+
 
 DROP FOREIGN DATA WRAPPER foo;
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1', testing '2');   -- ERROR
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1', another '2');
+CREATE FOREIGN DATA WRAPPER foo OPTIONS (testing '1', testing '2');   -- ERROR
+CREATE FOREIGN DATA WRAPPER foo OPTIONS (testing '1', another '2');
 \dew+
 
 DROP FOREIGN DATA WRAPPER foo;
 SET ROLE regress_test_role;
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+CREATE FOREIGN DATA WRAPPER foo; -- ERROR
 RESET ROLE;
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'postgresql_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER foo VALIDATOR postgresql_fdw_validator;
 \dew+
 
 -- ALTER FOREIGN DATA WRAPPER
-ALTER FOREIGN DATA WRAPPER foo LIBRARY '';                  -- ERROR
-ALTER FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql';
-ALTER FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw';
+ALTER FOREIGN DATA WRAPPER foo;                             -- ERROR
+ALTER FOREIGN DATA WRAPPER foo VALIDATOR bar;               -- ERROR
+ALTER FOREIGN DATA WRAPPER foo NO VALIDATOR;
 \dew+
 
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (a '1', b '2');
@@ -101,7 +97,7 @@ DROP FOREIGN DATA WRAPPER foo;
 DROP ROLE regress_test_role_super;
 \dew+
 
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER foo;
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
 CREATE USER MAPPING FOR current_user SERVER s1;
 \dew+
@@ -118,7 +114,7 @@ DROP FOREIGN DATA WRAPPER foo CASCADE;
 
 -- exercise CREATE SERVER
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;                  -- ERROR
-CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (test_wrapper 'true');
+CREATE FOREIGN DATA WRAPPER foo OPTIONS (test_wrapper 'true');
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;                  -- ERROR
 CREATE SERVER s2 FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
@@ -313,12 +309,11 @@ GRANT USAGE ON FOREIGN SERVER s4 TO regress_test_role;
 DROP USER MAPPING FOR public SERVER s4;
 ALTER SERVER s6 OPTIONS (DROP host, DROP dbname);
 ALTER USER MAPPING FOR regress_test_role SERVER s6 OPTIONS (DROP username);
-ALTER FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql';
-ALTER FOREIGN DATA WRAPPER foo LIBRARY 'default_fdw';
+ALTER FOREIGN DATA WRAPPER foo VALIDATOR postgresql_fdw_validator;
 
 -- Privileges
 SET ROLE unprivileged_role;
-CREATE FOREIGN DATA WRAPPER foobar LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+CREATE FOREIGN DATA WRAPPER foobar;                             -- ERROR
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (gotcha 'true');         -- ERROR
 ALTER FOREIGN DATA WRAPPER foo OWNER TO unprivileged_role;      -- ERROR
 DROP FOREIGN DATA WRAPPER foo;                                  -- ERROR
@@ -336,7 +331,7 @@ RESET ROLE;
 GRANT USAGE ON FOREIGN DATA WRAPPER postgresql TO unprivileged_role;
 GRANT USAGE ON FOREIGN DATA WRAPPER foo TO unprivileged_role WITH GRANT OPTION;
 SET ROLE unprivileged_role;
-CREATE FOREIGN DATA WRAPPER foobar LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+CREATE FOREIGN DATA WRAPPER foobar;                             -- ERROR
 ALTER FOREIGN DATA WRAPPER foo OPTIONS (gotcha 'true');         -- ERROR
 DROP FOREIGN DATA WRAPPER foo;                                  -- ERROR
 GRANT USAGE ON FOREIGN DATA WRAPPER postgresql TO regress_test_role; -- WARNING
@@ -391,6 +386,6 @@ DROP FOREIGN DATA WRAPPER dummy CASCADE;
 DROP ROLE foreign_data_user;
 
 -- At this point we should have no wrappers, no servers, and no mappings.
-SELECT fdwname, fdwlibrary, fdwoptions FROM pg_foreign_data_wrapper;
+SELECT fdwname, fdwvalidator, fdwoptions FROM pg_foreign_data_wrapper;
 SELECT srvname, srvoptions FROM pg_foreign_server;
 SELECT * FROM pg_user_mapping;