<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.postgresql.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hanada</id>
	<title>PostgreSQL wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.postgresql.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hanada"/>
	<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/wiki/Special:Contributions/Hanada"/>
	<updated>2026-06-09T09:55:16Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=FOSDEM/PGDay_2017_Developer_Meeting&amp;diff=29130</id>
		<title>FOSDEM/PGDay 2017 Developer Meeting</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=FOSDEM/PGDay_2017_Developer_Meeting&amp;diff=29130"/>
		<updated>2017-01-04T14:27:28Z</updated>

		<summary type="html">&lt;p&gt;Hanada: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A meeting of the interested PostgreSQL developers is being planned for Thursday 2nd February, 2017 at the Brussels Marriott Hotel, prior to FOSDEM/PGDay 2017. In order to keep the numbers manageable, this meeting is by &#039;&#039;&#039;invitation only&#039;&#039;&#039;. Unfortunately it is quite possible that we&#039;ve overlooked important individuals during the planning of the event - if you feel you fall into this category and would like to attend, please contact Dave Page (dpage@pgadmin.org).&lt;br /&gt;
&lt;br /&gt;
Please note that the attendee numbers have been kept low in order to keep the meeting more productive. Invitations have been sent only to developers that have been highly active on the database server over the 9.6 and 10 release cycles. We have not invited any contributors based on their contributions to related projects, or seniority in regional user groups or sponsoring companies.&lt;br /&gt;
&lt;br /&gt;
This is a PostgreSQL Community event.&lt;br /&gt;
&lt;br /&gt;
== Meeting Goals ==&lt;br /&gt;
&lt;br /&gt;
* Review the progress of the 10.0 schedule, and formulate plans to address any issues&lt;br /&gt;
* Address any proposed timing, policy, or procedure issues&lt;br /&gt;
* Address any proposed [http://en.wikipedia.org/wiki/Wicked_problem Wicked problems]&lt;br /&gt;
&lt;br /&gt;
== Time &amp;amp; Location ==&lt;br /&gt;
&lt;br /&gt;
The meeting will be:&lt;br /&gt;
&lt;br /&gt;
* 9:00AM to 5:00PM&lt;br /&gt;
* Brussels Marriott Hotel&lt;br /&gt;
&lt;br /&gt;
Coffee, tea and snacks will be served starting at 8:45am.  Lunch will be provided.&lt;br /&gt;
&lt;br /&gt;
== RSVPs ==&lt;br /&gt;
&lt;br /&gt;
The following people have RSVPed to the meeting (in alphabetical order, by surname) and will be attending:&lt;br /&gt;
&lt;br /&gt;
* Oleg Bartunov&lt;br /&gt;
* Andrew Dunstan&lt;br /&gt;
* Etsuro Fujita&lt;br /&gt;
* Magnus Hagander&lt;br /&gt;
* Petr Jelinek&lt;br /&gt;
* Alexander Korotkov&lt;br /&gt;
* Noah Misch&lt;br /&gt;
* Bruce Momjian&lt;br /&gt;
* Simon Riggs&lt;br /&gt;
* Dave Page&lt;br /&gt;
* Masahiko Sawada&lt;br /&gt;
* Teodor Sigaev&lt;br /&gt;
* Tomas Vondra&lt;br /&gt;
&lt;br /&gt;
The following people have sent their apologies:&lt;br /&gt;
&lt;br /&gt;
* Dimitri Fontaine&lt;br /&gt;
* Kyotaro Horiguchi&lt;br /&gt;
* Shigeru Hanada&lt;br /&gt;
* Amit Kapila&lt;br /&gt;
* Tom Lane&lt;br /&gt;
* Thomas Munro&lt;br /&gt;
* Michael Paquier&lt;br /&gt;
* Craig Ringer&lt;br /&gt;
&lt;br /&gt;
==Agenda Items==&lt;br /&gt;
&lt;br /&gt;
Please add agenda items here!&lt;br /&gt;
&lt;br /&gt;
* Sharding update&lt;br /&gt;
&lt;br /&gt;
* Setting up the Release Management Team for Postgres 10.0 (Simon)&lt;br /&gt;
&lt;br /&gt;
==Agenda==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
!Time&lt;br /&gt;
!Item&lt;br /&gt;
!Presenter&lt;br /&gt;
|- style=&amp;quot;font-style:italic;background-color:lightgray;&amp;quot;&lt;br /&gt;
|09:00 - 09:10&lt;br /&gt;
|Welcome and introductions&lt;br /&gt;
|Dave&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
|09:10 - 09:30&lt;br /&gt;
|10.0 Release Schedule&lt;br /&gt;
|All&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;font-style:italic;background-color:lightgray;&amp;quot;&lt;br /&gt;
|10:30 - 11:00&lt;br /&gt;
|Coffee break&lt;br /&gt;
|All&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;font-style:italic;background-color:lightgray;&amp;quot;&lt;br /&gt;
|12:30 - 13:30&lt;br /&gt;
|Lunch&lt;br /&gt;
|All&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;font-style:italic;background-color:lightgray;&amp;quot;&lt;br /&gt;
|15:00 - 15:30&lt;br /&gt;
|Tea break&lt;br /&gt;
|All&lt;br /&gt;
&lt;br /&gt;
|- &lt;br /&gt;
|16:30 - 17:00&lt;br /&gt;
|Any other business&lt;br /&gt;
|Dave&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;font-style:italic;background-color:lightgray;&amp;quot;&lt;br /&gt;
|17:00&lt;br /&gt;
|Finish&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Minutes ==&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=PgCon2015ClusterSummit&amp;diff=25218</id>
		<title>PgCon2015ClusterSummit</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=PgCon2015ClusterSummit&amp;diff=25218"/>
		<updated>2015-06-18T18:01:20Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* pgCon 2015 Cluster Hacker Summit */ Remove duplicate item&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=pgCon 2015 Cluster Hacker Summit=&lt;br /&gt;
&lt;br /&gt;
This year&#039;s Cluster Hacker Summit will be part of the [[PgCon_2015_Developer_Unconference]].  As such, this page will be used to coordinate sessions to propose for the Unconference, and eventually to list an agenda for the Clustering Track.&lt;br /&gt;
&lt;br /&gt;
The Cluster Summit covers both general PostgreSQL clustering, as well as PostgresXC and PostgresXL development.&lt;br /&gt;
&lt;br /&gt;
As it is part of the Developer Unconference, Clustering sessions will take place starting in the afternoon of Tuesday, June 16 through 5pm on Wednesday, June 17.  If you are participating, and will not be able to make it on Tuesday, please note that in your attendance comments.&lt;br /&gt;
&lt;br /&gt;
== Attendee RSVPs ==&lt;br /&gt;
&lt;br /&gt;
* Josh Berkus (both days)&lt;br /&gt;
* Koichi Suzuki&lt;br /&gt;
* Tatsuo Ishii&lt;br /&gt;
* Yugo Nagata&lt;br /&gt;
* Steve Singer (arrive tuesday mid-afternoon)&lt;br /&gt;
* Jan Wieck (arrive tuesday evening)&lt;br /&gt;
* Shigeru Hanada&lt;br /&gt;
* Ahsan Hadi&lt;br /&gt;
* Ashutosh Bapat&lt;br /&gt;
* Bruce Momjian&lt;br /&gt;
* Etsuro Fujita&lt;br /&gt;
* Tetsuo Sakata&lt;br /&gt;
* Amit Langote&lt;br /&gt;
* Kyotaro Horiguchi&lt;br /&gt;
* Ozgun Erdogan (Wednesday)&lt;br /&gt;
* Marco Slot (Wednesday)&lt;br /&gt;
* Simon Riggs&lt;br /&gt;
&lt;br /&gt;
== Suggested Sessions ==&lt;br /&gt;
&lt;br /&gt;
For each session below please provide a title and a moderator/leader/speaker for the session. &lt;br /&gt;
&lt;br /&gt;
=== Pgpool-II: toward next major version 3.5 ===&lt;br /&gt;
&lt;br /&gt;
Firstly we report the project progress since last year&#039;s Cluster Summit: introducing pgpool-II 3.4. Then we explain the current status of pgpool-II 3.5 which is under development.&lt;br /&gt;
&lt;br /&gt;
Session Leader: Tatsuo Ishii&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
=== Horizontal Scalability and Sharding ===&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Ahsan Hadi, Ashutosh Bapat &lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
=== Slony ===&lt;br /&gt;
&lt;br /&gt;
What is the future for Slony development?  Are users interested in a new Slony based on Logical Decoding?  Who&#039;s going to work on this?&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Steve Singer, Chris Browne, Jan Wieck&lt;br /&gt;
&lt;br /&gt;
==== Session Notes ====&lt;br /&gt;
&lt;br /&gt;
Slony Development&lt;br /&gt;
&lt;br /&gt;
Leader: Steve Singer, Chris Browne, Jan Wieck&lt;br /&gt;
&lt;br /&gt;
Note-taker: Josh Berkus&lt;br /&gt;
&lt;br /&gt;
In the past year Slony development has been pretty stagnant.  Steve has worked on a prototype with Logical Decoding.  Works for a demo, but not all features work, and performance was not all that impressive.  Part of that is that how much we&#039;ve optimized the Slony log.  Logical slony has some lower write overhead, but the latency for assembly on the other side is not insignificant.  &lt;br /&gt;
&lt;br /&gt;
The stability of slony and features are OK, but will it survive with modern features of Postgres.  With some features it will be different.  It does something which others don&#039;t.&lt;br /&gt;
&lt;br /&gt;
Chris: only takes a few hours of work per year to keep up with Postgres releases.  But we&#039;ve been forgetting how to do releases and management.  &lt;br /&gt;
&lt;br /&gt;
Jan: mentioned limitations of UDR/BDR.  But most users are on older versions.  Even if 9.6 has everything built in, people will still be using older versions for 5 years.  Slony was built to allow upgrading.  If it doesn&#039;t make sense to maintain them then we won&#039;t.&lt;br /&gt;
&lt;br /&gt;
Slony is still useful for upgrading across architectures and character decodings.  Josh mentioned the early stage of development of UDR.  Steve said that it would take more than one year to get slony working with Logical Decoding and to make it as stable as trigger-based replication.&lt;br /&gt;
&lt;br /&gt;
Chris asked what the issues were with LD and Slony development.  Jan pointed out that for partial replication ... where you&#039;re replicating a few low-volume tables ... then saving all the WAL for the replication slot is a big loss.  So LD and classic Slony log table need to coexist.&lt;br /&gt;
&lt;br /&gt;
Josh said there&#039;s two reasons why he wants LD: (1) easier installation and (2) bloat in the queue tables caused by long-running transactions (3) removal overhead.  &lt;br /&gt;
&lt;br /&gt;
Re: bloat Jan mentioned Grittner&#039;s snapshot-too-old work.  Josh said that work is partly because of Slony.   You can&#039;t even truncate segments if there&#039;s a long-running transaction.  Chris mentioned the idea of per-table logs. &lt;br /&gt;
&lt;br /&gt;
Moving the reporting queries onto the replica can fix this issue, but it just moves the bloat around.  More discussion around this.  Doing this against a non-forwarding replica would prevent bloat.  &lt;br /&gt;
&lt;br /&gt;
Other requests:&lt;br /&gt;
&lt;br /&gt;
* Parallel initial data copy.  &lt;br /&gt;
* Call Slony as a library (mostly Python)&lt;br /&gt;
* Add tables to multiple versions of databases&lt;br /&gt;
* No table locks&lt;br /&gt;
* More visibility commands via Slonik, once it&#039;s a library&lt;br /&gt;
* Cancel subscribe set in progress&lt;br /&gt;
&lt;br /&gt;
Libraries: one way to get around the multiple library issue is to expose the function API.  But according to Jan the function API is not complete.  Steve would rather have Slonik as a shared library.  Calling the slony SPs directly isn&#039;t safe.  Dave Cramer asked if we do a Python library how are we going to call it from Java?  We&#039;ll create a C shared library.&lt;br /&gt;
&lt;br /&gt;
Valentin suggestes exposing the shared libaries via stored procedures.  Chris pointed out that the lack of autonomous transactions prevents this.  But if the library is wrapped in functions it can be exposed.  Or create some kind of REST API.  Jan said that they&#039;re planning on supporting pgAdmin4, so an abstracted libary would support this.  This is a good idea.  Some people use GUIs, but some don&#039;t.  &lt;br /&gt;
&lt;br /&gt;
Steve asked if people are using it for DR.  Josh mentioned one multi-region case.  Valintin said more availability than DR.  &lt;br /&gt;
&lt;br /&gt;
Jan said that more visibility functions for Slonik is a must once it&#039;s a library.  And it would make the API more stable because you wouldn&#039;t have to use the Slony catalog.&lt;br /&gt;
&lt;br /&gt;
Steve asked if Slony could take one exclusive lock at a time would help.  One user said no, they don&#039;t get enough downtime. But others said yes.  Rod really wants an add trigger command which takes an access exclusive lock. That&#039;s a major postgres issue in terms of locking and tables.  Jan speculated how that would be possible.  Valintin tries to resolve this by setting statement_timeout and having it fail.  The Slony team has some idea of how to do this.  This is similar to concurrent index creation.  Jan will look at doing CREATE TRIGGER CONCURRENTLY.  Suggested that there should be a general lock state where you ask for a lock concurrently.  This should be a function call.  Kevin suggested that we should call this &amp;quot;deferrable&amp;quot; rather than Concurrent.  With timeouts.&lt;br /&gt;
&lt;br /&gt;
Steve appealed for people to help implement some of these things.  Jan will sign up for LOCK TABLE DEFERRABLE.  Josh said that he&#039;s help test/spec the API.  Biggest issues with syntax is varadic arguments.  &lt;br /&gt;
&lt;br /&gt;
Chris asked if anyone was using logshipping, and someone said yes, and they&#039;re using the daemon to apply the logs.&lt;br /&gt;
&lt;br /&gt;
Chris asked about DDL.  Change in 2.2 which allows passing in the DDL string instead of needing a file.  PostgresQL 9.5 will have DDL event replication.  Do we care about building this?  Chris said the most easy change would be to allow dropping a table to automatically drop it from replication.  Rejecting DDL not run through execute script would be even better.  It should be an option, which you can override.  Josh voted on blocking DDL.&lt;br /&gt;
&lt;br /&gt;
Steve&#039;s concern with blocking DDL is that people do this for legitimate reasons.  Josh mentioned stupid dev tricks where they bring slony down by running rake on the production cluster.  Also a library would be compatible with rake.&lt;br /&gt;
&lt;br /&gt;
Do people see Slony as still being relevant in 2-3 years if BDR/UDR succeeds?  Hard to be sure, since it&#039;s not mature yet.&lt;br /&gt;
&lt;br /&gt;
They then set some targets:&lt;br /&gt;
&lt;br /&gt;
* Parallel initial data copy: Slony 2.3+, requires Postgres 9.3+  &lt;br /&gt;
* Call Slony as a library (mostly Python): Slony 2.3&lt;br /&gt;
* Add tables to multiple versions of databases: works with library&lt;br /&gt;
* No table locks: Postgres 9.6+&lt;br /&gt;
* More visibility commands via Slonik, once it&#039;s a library: Slony 2.4?&lt;br /&gt;
* Cancel subscribe set in progress&lt;br /&gt;
* Prevent DDL: Postgres 9.4, slony 2.3&lt;br /&gt;
&lt;br /&gt;
Not likely to work on Slony + Logical Decoding, because it&#039;s bigger than all of the features above.  Making it stable would take years, and it doesnt&#039; perform better.  Valintin is working on LD systems and building libaries on top of LD like a python library and replication to Kafka.  Steve&#039;s code is on Github.  Particularly, being able to switch between LD and triggers would be really complex.&lt;br /&gt;
&lt;br /&gt;
Josh mentioned the issue around WAL log volume from the slony buffers.  One user requested the ability to execute a command on a group of slaves.  So an kind of EXECUTE SCRIPT on a group of nodes.&lt;br /&gt;
&lt;br /&gt;
=== Bi Directional Replication &amp;amp; Logical Decoding ===&lt;br /&gt;
&lt;br /&gt;
Including DDL replication, Online Upgrade, Logical Replication, Bi Directional Replication etc&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Simon Riggs, Andres Freund&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
BDR and UDR etc.&lt;br /&gt;
&lt;br /&gt;
Leader: Simon&lt;br /&gt;
&lt;br /&gt;
Note-taker: Josh Berkus&lt;br /&gt;
&lt;br /&gt;
This will be about development of BDR, not using BDR.  Will be only 10 minutes about BDR.&lt;br /&gt;
&lt;br /&gt;
BDR stands for Bi-Directional Replication, has been put together across a couple years.  Has been released a couple months ago.  Is being used in production at some sites.  Have released 0.9.1 bugfixing 0.9. But it&#039;s not 1.0 yet.  We want to get it into Postgres.&lt;br /&gt;
&lt;br /&gt;
BDR allows replication to flow in two directions.  It&#039;s logical replication which permits making changes to the data as it&#039;s replicated.  Translating the WAL stream (transaction log stream) and uses Logical Decoding to take action and stream changes.  Works on a commit-by-commit basis.&lt;br /&gt;
&lt;br /&gt;
Each server has a sender process which talks to an apply process on another server.  These are implemented as background workers, a 9.3 feature.  9.4 with the BDR plugin supports one-way replication.&lt;br /&gt;
&lt;br /&gt;
Two-way replication requires handling conflicts.  This requests patches on postgres, so they have a &amp;quot;spoon&amp;quot; of Postgres (not quite a fork).  Most of this is in 9.5, but there&#039;s a couple things still waiting for 9.6.  Sequence AM was not included in 9.5, also WAL messaging, to send non-transactional WAL messages.  Implemented logical replication, then built upon that to make bi-directional replication possible.  Now building a system to handle DDL so that it can be replicated.  The DDL is hard because we need it in &amp;quot;absolute form&amp;quot;.  The DDL deparse code is still in a module.&lt;br /&gt;
&lt;br /&gt;
The other part of the system is zero-downtime upgrade.  This uses UDR.  It works with version 9.4.&lt;br /&gt;
&lt;br /&gt;
Discussion of logical vs. binary replication.  Grant asked what about parallelism on the apply side of the replication. Andres tested this, and it wasn&#039;t really a problem; the applier is much faster than the writes on the origin nodes.  &lt;br /&gt;
&lt;br /&gt;
Kevin took issue with the assertion that commit order of application doesn&#039;t allow seeing anoninalies.  He brought up an example case where that&#039;s not true with batch processing.  &lt;br /&gt;
&lt;br /&gt;
Discussion of features required in core started.&lt;br /&gt;
&lt;br /&gt;
Open items for including features in core are:&lt;br /&gt;
&lt;br /&gt;
* SEQAM - ready for commit&lt;br /&gt;
* WAL messages - need to discuss and have a flamewar but otherwise there.&lt;br /&gt;
* Metadata - where do we store metadata for the replication system?  Connection information?&lt;br /&gt;
* Control - still use functions, or implement special-case DDL?&lt;br /&gt;
* DDL Replication Code&lt;br /&gt;
&lt;br /&gt;
Metadata is currently stored in a mix of security labels and metadata tables.  Is this a conflict with RLS?  Shouldn&#039;t be, but it&#039;s a bit of a hack; it&#039;s done because it&#039;s extra data which is created and deleted with a table.&lt;br /&gt;
&lt;br /&gt;
UDR Functions:&lt;br /&gt;
* subscribue&lt;br /&gt;
&lt;br /&gt;
BDR:&lt;br /&gt;
* create group&lt;br /&gt;
* join group&lt;br /&gt;
&lt;br /&gt;
Robert asked a question about synchronizing timestamps.  This motivated some of the patches to 9.5.&lt;br /&gt;
&lt;br /&gt;
Should we have full DDL for this, or should we have functions?  Simon thinks functions are fine.  Haas likes DDL because it&#039;s more self-documenting.  Simon argued that there&#039;s been a lot of changes to the functions. It&#039;s been iterating.  But once it&#039;s in core (Haas), people expect very stable APIs, so you won&#039;t be able to change them anyway.  Some discussion about dump and restore followed.  There are some things which can&#039;t be restored.  Replication slots is a good example of this, Haas feels like that&#039;s kind of unfinished.  There&#039;s a pretty good argument that you want to be able to restore your replication sets.  &lt;br /&gt;
&lt;br /&gt;
The problem of deprecating APIs (Smith) already exists.  We can add more arguments. Which model do you want?   As soon as you put it into syntax, it&#039;s  a lot harder to change parameters etc. There&#039;s also the question of to what extent we want to keep backwards compatibility of replication stuff.  &lt;br /&gt;
&lt;br /&gt;
Do we need a generic concept of a supervisor worker, because people keep reinventing this concept?  &lt;br /&gt;
&lt;br /&gt;
What about the metadata?  We want it to work even if people rename tables, etc.  Does this work reasonably well for 100,000 table cases?  Should work with relcache, should be fine.  &lt;br /&gt;
&lt;br /&gt;
Currently subscribe/group uses pgdump, which requires passing in connections string so that we can dump out the database.  That&#039;s not the only problem with the dependancy on pgdump.  Dependancies on external binaries is kind of an issue.  Abstracting out pgdump has been a TODO forever.  Slony needs self-connection information too.  You could have BDR GUCs, but that didn&#039;t work really well.  This is different for each database.&lt;br /&gt;
&lt;br /&gt;
pgdump is used to create the initial snapshot of the data and structure.  You can use pgbasebackup instead, but that copies everything.  Other database tools do it table-by-table.  Getting sufficient administration tools into core is critical.  We don&#039;t want to have 5 separate sets of tools like we do now most of which are buggy.  Grant says: make the APIs really well, it&#039;s easy to build the tools on top of the APIs.  He doesn&#039;t want tools which work on the base stuff.   We have different sets of tools because they have different use cases.&lt;br /&gt;
&lt;br /&gt;
=== pg_shard v2.0 and Lessons Learned from NoSQL Databases ===&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Ozgun Erdogan, Marco Slot&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
pg_shard 2.0&lt;br /&gt;
&lt;br /&gt;
Ozgun explained how pg_shard is put together.  There&#039;s a metadata node, which connects to a bunch of backend nodes.  Each backend node contains multiple shards in one database. The shards are tables.&lt;br /&gt;
&lt;br /&gt;
In pg_shard 2.0, the metadata will be fully distributed.&lt;br /&gt;
&lt;br /&gt;
The metatdata node tracks where shards are located.  And shards can be redistributed.&lt;br /&gt;
&lt;br /&gt;
So there are a few proposals for how to distribute metadata.  There are several use-cases they are trying to answer:&lt;br /&gt;
* NoSQL use-case on the eventual consistency model&lt;br /&gt;
** real-time analytics over log data&lt;br /&gt;
* SAP Hana-like use case.  ACID-compliant scalable RDBMS database.&lt;br /&gt;
&lt;br /&gt;
Not like OracleRAC which is shared disk.  &lt;br /&gt;
&lt;br /&gt;
The proposals for sharing metadata:&lt;br /&gt;
# replication metadata to all nodes assuming communtative writes ... that is write order doesn&#039;t matter.  So replicate change statements between all nodes.  Use BDR.&lt;br /&gt;
# Shard health is decoupled shard health from metadata.  Delegate health to replication groups. Could be enhanced by streaming replication.  Basically failover between pairs of nodes.&lt;br /&gt;
&lt;br /&gt;
They explained the first proposal.  If they get inserts onto one table, if an insert fails, that node is marked invalid. Josh questioned whether or not this would ever become consistent.  You would need to buffer the writes and replay them or resync-from the one healthy replica.  Also requires that events can never conflict.  It pretty much only supports the insert-only use case, because all writes have to be incremental.  This is the AP proposal out of CAP.&lt;br /&gt;
&lt;br /&gt;
For the 2nd proposal, then RDS could handle that for us.  The 2nd proposal relies on having small replication groups, which would fail over in the event of a node failure.  Streaming replication could be used between replicas.  You&#039;d need small groups with at least 3 nodes.&lt;br /&gt;
&lt;br /&gt;
Josh made a third proposal, using RAFT-like semantics to share metadata and make it mostly consistent.  Various issues were pointed out with this.&lt;br /&gt;
&lt;br /&gt;
Alvaro suggested requiring quorum every time you do a read.  Some discussion of Paxos etc. ensued.&lt;br /&gt;
&lt;br /&gt;
=== FDW Enhancements ===&lt;br /&gt;
&lt;br /&gt;
[http://www.slideshare.net/babystarmonja/foreign-data-wrapper-enhancements Slides used for this session]&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Shigheru Hanada and Esteru Fujita&lt;br /&gt;
&lt;br /&gt;
Note-taker: Josh Berkus&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
Enhancements proposed for 9.5:&lt;br /&gt;
* Inheritance Support: Committed: foreign table can be parent or child of other tables&lt;br /&gt;
* Update push-down: Returned with feedback: updated against Foreign tables without fetching data from the remote node.  &lt;br /&gt;
* Join Push-down: API committed: allows joining on the remote server.&lt;br /&gt;
&lt;br /&gt;
Update pushdown requires certain conditions in the Update statement.  Also it requires a new FDW API, called from nodeModifyTable.&lt;br /&gt;
&lt;br /&gt;
Currently joins are performed on the local server, which can be very slow.  If both tables on on the external server and joins are supported we should be able to join over there.  The FDW API is committed, but pgsql_fdw changes were not committed.  The major issue was &amp;quot;how do we construct the remote query?&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Should we use a parse tree?  They would like to support in Oracle and MySQL FDWs.  A general SQL deparser would be idea for this, but we don&#039;t have one.&lt;br /&gt;
&lt;br /&gt;
We also want sort push-down.  But there is a problem selecting the key for the sort.  Josh asked why.  Shigheru explained that FDW sees only plan tree, and the plan tree generates path information for each key, which includes multiple candidates.  &lt;br /&gt;
&lt;br /&gt;
Other possible enhancements:&lt;br /&gt;
* sort push-down&lt;br /&gt;
* aggregate push-down&lt;br /&gt;
* more aggressive join push-down&lt;br /&gt;
&lt;br /&gt;
For sort push-down, we also need to mark a Foreign Scan as sorted.  But problems: limiting sort key candidates.  Do we need to introduce FOREIGN INDEX concepts?  Should we have FDW catalogs?  Also, how can we be sure that sorting on the target and the local server are identical (collations etc.)?  And what about pre-sorted join results?  He asked for ideas on how to implement this.&lt;br /&gt;
&lt;br /&gt;
Tom suggested that if you took the overhead of doing an explain, you could check and see if it&#039;s doing a merge join on the remote node.  It might be expensive to see the explain plan.&lt;br /&gt;
&lt;br /&gt;
He doesn&#039;t have a really concrete idea how to implement aggregate push-down.  Maybe they should implement a new FDW API, and replace the Aggregate node with a ForeignScan.   Issues include how to determine the semantics of the GROUP BY clause.  Also how do we map local functions to remote ones?  THere&#039;s stuff in the SQL standard for this but not very well defined.&lt;br /&gt;
&lt;br /&gt;
More aggressive join push down would support doing a foreign nestloop scan.  One way to do that is with local small tables we can push materialized data cross the FDW and join against it.  Or we could do a temporary table or VALUES statement.  If we know that the table is replicated on the remote side, we could join against it.&lt;br /&gt;
&lt;br /&gt;
Other ideas?&lt;br /&gt;
 &lt;br /&gt;
Paul asked about extended types, like for PostGIS.  Geometry operators aren&#039;t allowed to pass down through pgsql_fdw.  He had to hack pgsql_fdw in order to pass those through.  Maybe when you declare a server, you could declare which extensions are installed in the server, which would be checked in FDW.  Shigheru thinks this is a good idea.  Right now we don&#039;t push them down because the operator might be different on the target.  &lt;br /&gt;
&lt;br /&gt;
Is an extension a useful unit for this?  Tom and Paul think yes.  Also we don&#039;t actually need to check versions.  We also want to create mappings for individual functions though.&lt;br /&gt;
&lt;br /&gt;
Marco asked about CSTORE_FDW.  The FDWAPI requires us to read row-by-row, which kills some of the advantages of the column store.  Josh asked about COPY protocol; it would be good to copy into remote tables.   &lt;br /&gt;
&lt;br /&gt;
They also talked about pushing down pre-aggregates instead of finished aggregates.  That is, count/sum instead of AVG.  That way it will work with partitioned foreign tables.  Basically, we would export the transition function somehow, like a MapReduce system.  No idea how to do this.  Also, how would it work with non-postgres systems?&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=PgCon2015ClusterSummit&amp;diff=25217</id>
		<title>PgCon2015ClusterSummit</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=PgCon2015ClusterSummit&amp;diff=25217"/>
		<updated>2015-06-18T18:00:13Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* FDW Enhancements */ Link the slides&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=pgCon 2015 Cluster Hacker Summit=&lt;br /&gt;
&lt;br /&gt;
This year&#039;s Cluster Hacker Summit will be part of the [[PgCon_2015_Developer_Unconference]].  As such, this page will be used to coordinate sessions to propose for the Unconference, and eventually to list an agenda for the Clustering Track.&lt;br /&gt;
&lt;br /&gt;
The Cluster Summit covers both general PostgreSQL clustering, as well as PostgresXC and PostgresXL development.&lt;br /&gt;
&lt;br /&gt;
As it is part of the Developer Unconference, Clustering sessions will take place starting in the afternoon of Tuesday, June 16 through 5pm on Wednesday, June 17.  If you are participating, and will not be able to make it on Tuesday, please note that in your attendance comments.&lt;br /&gt;
&lt;br /&gt;
== Attendee RSVPs ==&lt;br /&gt;
&lt;br /&gt;
* Josh Berkus (both days)&lt;br /&gt;
* Koichi Suzuki&lt;br /&gt;
* Tatsuo Ishii&lt;br /&gt;
* Yugo Nagata&lt;br /&gt;
* Steve Singer (arrive tuesday mid-afternoon)&lt;br /&gt;
* Jan Wieck (arrive tuesday evening)&lt;br /&gt;
* Shigeru Hanada&lt;br /&gt;
* Ahsan Hadi&lt;br /&gt;
* Ashutosh Bapat&lt;br /&gt;
* Bruce Momjian&lt;br /&gt;
* Etsuro Fujita&lt;br /&gt;
* Tetsuo Sakata&lt;br /&gt;
* Amit Langote&lt;br /&gt;
* Kyotaro Horiguchi&lt;br /&gt;
* Ozgun Erdogan (Wednesday)&lt;br /&gt;
* Marco Slot (Wednesday)&lt;br /&gt;
* Simon Riggs&lt;br /&gt;
&lt;br /&gt;
== Suggested Sessions ==&lt;br /&gt;
&lt;br /&gt;
For each session below please provide a title and a moderator/leader/speaker for the session. &lt;br /&gt;
&lt;br /&gt;
=== Pgpool-II: toward next major version 3.5 ===&lt;br /&gt;
&lt;br /&gt;
Firstly we report the project progress since last year&#039;s Cluster Summit: introducing pgpool-II 3.4. Then we explain the current status of pgpool-II 3.5 which is under development.&lt;br /&gt;
&lt;br /&gt;
Session Leader: Tatsuo Ishii&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
=== FDW Enhancements ===&lt;br /&gt;
&lt;br /&gt;
Session Leader: Shigeru Hanada and Etsuro Fujita&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
=== Horizontal Scalability and Sharding ===&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Ahsan Hadi, Ashutosh Bapat &lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
=== Slony ===&lt;br /&gt;
&lt;br /&gt;
What is the future for Slony development?  Are users interested in a new Slony based on Logical Decoding?  Who&#039;s going to work on this?&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Steve Singer, Chris Browne, Jan Wieck&lt;br /&gt;
&lt;br /&gt;
==== Session Notes ====&lt;br /&gt;
&lt;br /&gt;
Slony Development&lt;br /&gt;
&lt;br /&gt;
Leader: Steve Singer, Chris Browne, Jan Wieck&lt;br /&gt;
&lt;br /&gt;
Note-taker: Josh Berkus&lt;br /&gt;
&lt;br /&gt;
In the past year Slony development has been pretty stagnant.  Steve has worked on a prototype with Logical Decoding.  Works for a demo, but not all features work, and performance was not all that impressive.  Part of that is that how much we&#039;ve optimized the Slony log.  Logical slony has some lower write overhead, but the latency for assembly on the other side is not insignificant.  &lt;br /&gt;
&lt;br /&gt;
The stability of slony and features are OK, but will it survive with modern features of Postgres.  With some features it will be different.  It does something which others don&#039;t.&lt;br /&gt;
&lt;br /&gt;
Chris: only takes a few hours of work per year to keep up with Postgres releases.  But we&#039;ve been forgetting how to do releases and management.  &lt;br /&gt;
&lt;br /&gt;
Jan: mentioned limitations of UDR/BDR.  But most users are on older versions.  Even if 9.6 has everything built in, people will still be using older versions for 5 years.  Slony was built to allow upgrading.  If it doesn&#039;t make sense to maintain them then we won&#039;t.&lt;br /&gt;
&lt;br /&gt;
Slony is still useful for upgrading across architectures and character decodings.  Josh mentioned the early stage of development of UDR.  Steve said that it would take more than one year to get slony working with Logical Decoding and to make it as stable as trigger-based replication.&lt;br /&gt;
&lt;br /&gt;
Chris asked what the issues were with LD and Slony development.  Jan pointed out that for partial replication ... where you&#039;re replicating a few low-volume tables ... then saving all the WAL for the replication slot is a big loss.  So LD and classic Slony log table need to coexist.&lt;br /&gt;
&lt;br /&gt;
Josh said there&#039;s two reasons why he wants LD: (1) easier installation and (2) bloat in the queue tables caused by long-running transactions (3) removal overhead.  &lt;br /&gt;
&lt;br /&gt;
Re: bloat Jan mentioned Grittner&#039;s snapshot-too-old work.  Josh said that work is partly because of Slony.   You can&#039;t even truncate segments if there&#039;s a long-running transaction.  Chris mentioned the idea of per-table logs. &lt;br /&gt;
&lt;br /&gt;
Moving the reporting queries onto the replica can fix this issue, but it just moves the bloat around.  More discussion around this.  Doing this against a non-forwarding replica would prevent bloat.  &lt;br /&gt;
&lt;br /&gt;
Other requests:&lt;br /&gt;
&lt;br /&gt;
* Parallel initial data copy.  &lt;br /&gt;
* Call Slony as a library (mostly Python)&lt;br /&gt;
* Add tables to multiple versions of databases&lt;br /&gt;
* No table locks&lt;br /&gt;
* More visibility commands via Slonik, once it&#039;s a library&lt;br /&gt;
* Cancel subscribe set in progress&lt;br /&gt;
&lt;br /&gt;
Libraries: one way to get around the multiple library issue is to expose the function API.  But according to Jan the function API is not complete.  Steve would rather have Slonik as a shared library.  Calling the slony SPs directly isn&#039;t safe.  Dave Cramer asked if we do a Python library how are we going to call it from Java?  We&#039;ll create a C shared library.&lt;br /&gt;
&lt;br /&gt;
Valentin suggestes exposing the shared libaries via stored procedures.  Chris pointed out that the lack of autonomous transactions prevents this.  But if the library is wrapped in functions it can be exposed.  Or create some kind of REST API.  Jan said that they&#039;re planning on supporting pgAdmin4, so an abstracted libary would support this.  This is a good idea.  Some people use GUIs, but some don&#039;t.  &lt;br /&gt;
&lt;br /&gt;
Steve asked if people are using it for DR.  Josh mentioned one multi-region case.  Valintin said more availability than DR.  &lt;br /&gt;
&lt;br /&gt;
Jan said that more visibility functions for Slonik is a must once it&#039;s a library.  And it would make the API more stable because you wouldn&#039;t have to use the Slony catalog.&lt;br /&gt;
&lt;br /&gt;
Steve asked if Slony could take one exclusive lock at a time would help.  One user said no, they don&#039;t get enough downtime. But others said yes.  Rod really wants an add trigger command which takes an access exclusive lock. That&#039;s a major postgres issue in terms of locking and tables.  Jan speculated how that would be possible.  Valintin tries to resolve this by setting statement_timeout and having it fail.  The Slony team has some idea of how to do this.  This is similar to concurrent index creation.  Jan will look at doing CREATE TRIGGER CONCURRENTLY.  Suggested that there should be a general lock state where you ask for a lock concurrently.  This should be a function call.  Kevin suggested that we should call this &amp;quot;deferrable&amp;quot; rather than Concurrent.  With timeouts.&lt;br /&gt;
&lt;br /&gt;
Steve appealed for people to help implement some of these things.  Jan will sign up for LOCK TABLE DEFERRABLE.  Josh said that he&#039;s help test/spec the API.  Biggest issues with syntax is varadic arguments.  &lt;br /&gt;
&lt;br /&gt;
Chris asked if anyone was using logshipping, and someone said yes, and they&#039;re using the daemon to apply the logs.&lt;br /&gt;
&lt;br /&gt;
Chris asked about DDL.  Change in 2.2 which allows passing in the DDL string instead of needing a file.  PostgresQL 9.5 will have DDL event replication.  Do we care about building this?  Chris said the most easy change would be to allow dropping a table to automatically drop it from replication.  Rejecting DDL not run through execute script would be even better.  It should be an option, which you can override.  Josh voted on blocking DDL.&lt;br /&gt;
&lt;br /&gt;
Steve&#039;s concern with blocking DDL is that people do this for legitimate reasons.  Josh mentioned stupid dev tricks where they bring slony down by running rake on the production cluster.  Also a library would be compatible with rake.&lt;br /&gt;
&lt;br /&gt;
Do people see Slony as still being relevant in 2-3 years if BDR/UDR succeeds?  Hard to be sure, since it&#039;s not mature yet.&lt;br /&gt;
&lt;br /&gt;
They then set some targets:&lt;br /&gt;
&lt;br /&gt;
* Parallel initial data copy: Slony 2.3+, requires Postgres 9.3+  &lt;br /&gt;
* Call Slony as a library (mostly Python): Slony 2.3&lt;br /&gt;
* Add tables to multiple versions of databases: works with library&lt;br /&gt;
* No table locks: Postgres 9.6+&lt;br /&gt;
* More visibility commands via Slonik, once it&#039;s a library: Slony 2.4?&lt;br /&gt;
* Cancel subscribe set in progress&lt;br /&gt;
* Prevent DDL: Postgres 9.4, slony 2.3&lt;br /&gt;
&lt;br /&gt;
Not likely to work on Slony + Logical Decoding, because it&#039;s bigger than all of the features above.  Making it stable would take years, and it doesnt&#039; perform better.  Valintin is working on LD systems and building libaries on top of LD like a python library and replication to Kafka.  Steve&#039;s code is on Github.  Particularly, being able to switch between LD and triggers would be really complex.&lt;br /&gt;
&lt;br /&gt;
Josh mentioned the issue around WAL log volume from the slony buffers.  One user requested the ability to execute a command on a group of slaves.  So an kind of EXECUTE SCRIPT on a group of nodes.&lt;br /&gt;
&lt;br /&gt;
=== Bi Directional Replication &amp;amp; Logical Decoding ===&lt;br /&gt;
&lt;br /&gt;
Including DDL replication, Online Upgrade, Logical Replication, Bi Directional Replication etc&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Simon Riggs, Andres Freund&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
BDR and UDR etc.&lt;br /&gt;
&lt;br /&gt;
Leader: Simon&lt;br /&gt;
&lt;br /&gt;
Note-taker: Josh Berkus&lt;br /&gt;
&lt;br /&gt;
This will be about development of BDR, not using BDR.  Will be only 10 minutes about BDR.&lt;br /&gt;
&lt;br /&gt;
BDR stands for Bi-Directional Replication, has been put together across a couple years.  Has been released a couple months ago.  Is being used in production at some sites.  Have released 0.9.1 bugfixing 0.9. But it&#039;s not 1.0 yet.  We want to get it into Postgres.&lt;br /&gt;
&lt;br /&gt;
BDR allows replication to flow in two directions.  It&#039;s logical replication which permits making changes to the data as it&#039;s replicated.  Translating the WAL stream (transaction log stream) and uses Logical Decoding to take action and stream changes.  Works on a commit-by-commit basis.&lt;br /&gt;
&lt;br /&gt;
Each server has a sender process which talks to an apply process on another server.  These are implemented as background workers, a 9.3 feature.  9.4 with the BDR plugin supports one-way replication.&lt;br /&gt;
&lt;br /&gt;
Two-way replication requires handling conflicts.  This requests patches on postgres, so they have a &amp;quot;spoon&amp;quot; of Postgres (not quite a fork).  Most of this is in 9.5, but there&#039;s a couple things still waiting for 9.6.  Sequence AM was not included in 9.5, also WAL messaging, to send non-transactional WAL messages.  Implemented logical replication, then built upon that to make bi-directional replication possible.  Now building a system to handle DDL so that it can be replicated.  The DDL is hard because we need it in &amp;quot;absolute form&amp;quot;.  The DDL deparse code is still in a module.&lt;br /&gt;
&lt;br /&gt;
The other part of the system is zero-downtime upgrade.  This uses UDR.  It works with version 9.4.&lt;br /&gt;
&lt;br /&gt;
Discussion of logical vs. binary replication.  Grant asked what about parallelism on the apply side of the replication. Andres tested this, and it wasn&#039;t really a problem; the applier is much faster than the writes on the origin nodes.  &lt;br /&gt;
&lt;br /&gt;
Kevin took issue with the assertion that commit order of application doesn&#039;t allow seeing anoninalies.  He brought up an example case where that&#039;s not true with batch processing.  &lt;br /&gt;
&lt;br /&gt;
Discussion of features required in core started.&lt;br /&gt;
&lt;br /&gt;
Open items for including features in core are:&lt;br /&gt;
&lt;br /&gt;
* SEQAM - ready for commit&lt;br /&gt;
* WAL messages - need to discuss and have a flamewar but otherwise there.&lt;br /&gt;
* Metadata - where do we store metadata for the replication system?  Connection information?&lt;br /&gt;
* Control - still use functions, or implement special-case DDL?&lt;br /&gt;
* DDL Replication Code&lt;br /&gt;
&lt;br /&gt;
Metadata is currently stored in a mix of security labels and metadata tables.  Is this a conflict with RLS?  Shouldn&#039;t be, but it&#039;s a bit of a hack; it&#039;s done because it&#039;s extra data which is created and deleted with a table.&lt;br /&gt;
&lt;br /&gt;
UDR Functions:&lt;br /&gt;
* subscribue&lt;br /&gt;
&lt;br /&gt;
BDR:&lt;br /&gt;
* create group&lt;br /&gt;
* join group&lt;br /&gt;
&lt;br /&gt;
Robert asked a question about synchronizing timestamps.  This motivated some of the patches to 9.5.&lt;br /&gt;
&lt;br /&gt;
Should we have full DDL for this, or should we have functions?  Simon thinks functions are fine.  Haas likes DDL because it&#039;s more self-documenting.  Simon argued that there&#039;s been a lot of changes to the functions. It&#039;s been iterating.  But once it&#039;s in core (Haas), people expect very stable APIs, so you won&#039;t be able to change them anyway.  Some discussion about dump and restore followed.  There are some things which can&#039;t be restored.  Replication slots is a good example of this, Haas feels like that&#039;s kind of unfinished.  There&#039;s a pretty good argument that you want to be able to restore your replication sets.  &lt;br /&gt;
&lt;br /&gt;
The problem of deprecating APIs (Smith) already exists.  We can add more arguments. Which model do you want?   As soon as you put it into syntax, it&#039;s  a lot harder to change parameters etc. There&#039;s also the question of to what extent we want to keep backwards compatibility of replication stuff.  &lt;br /&gt;
&lt;br /&gt;
Do we need a generic concept of a supervisor worker, because people keep reinventing this concept?  &lt;br /&gt;
&lt;br /&gt;
What about the metadata?  We want it to work even if people rename tables, etc.  Does this work reasonably well for 100,000 table cases?  Should work with relcache, should be fine.  &lt;br /&gt;
&lt;br /&gt;
Currently subscribe/group uses pgdump, which requires passing in connections string so that we can dump out the database.  That&#039;s not the only problem with the dependancy on pgdump.  Dependancies on external binaries is kind of an issue.  Abstracting out pgdump has been a TODO forever.  Slony needs self-connection information too.  You could have BDR GUCs, but that didn&#039;t work really well.  This is different for each database.&lt;br /&gt;
&lt;br /&gt;
pgdump is used to create the initial snapshot of the data and structure.  You can use pgbasebackup instead, but that copies everything.  Other database tools do it table-by-table.  Getting sufficient administration tools into core is critical.  We don&#039;t want to have 5 separate sets of tools like we do now most of which are buggy.  Grant says: make the APIs really well, it&#039;s easy to build the tools on top of the APIs.  He doesn&#039;t want tools which work on the base stuff.   We have different sets of tools because they have different use cases.&lt;br /&gt;
&lt;br /&gt;
=== pg_shard v2.0 and Lessons Learned from NoSQL Databases ===&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Ozgun Erdogan, Marco Slot&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
pg_shard 2.0&lt;br /&gt;
&lt;br /&gt;
Ozgun explained how pg_shard is put together.  There&#039;s a metadata node, which connects to a bunch of backend nodes.  Each backend node contains multiple shards in one database. The shards are tables.&lt;br /&gt;
&lt;br /&gt;
In pg_shard 2.0, the metadata will be fully distributed.&lt;br /&gt;
&lt;br /&gt;
The metatdata node tracks where shards are located.  And shards can be redistributed.&lt;br /&gt;
&lt;br /&gt;
So there are a few proposals for how to distribute metadata.  There are several use-cases they are trying to answer:&lt;br /&gt;
* NoSQL use-case on the eventual consistency model&lt;br /&gt;
** real-time analytics over log data&lt;br /&gt;
* SAP Hana-like use case.  ACID-compliant scalable RDBMS database.&lt;br /&gt;
&lt;br /&gt;
Not like OracleRAC which is shared disk.  &lt;br /&gt;
&lt;br /&gt;
The proposals for sharing metadata:&lt;br /&gt;
# replication metadata to all nodes assuming communtative writes ... that is write order doesn&#039;t matter.  So replicate change statements between all nodes.  Use BDR.&lt;br /&gt;
# Shard health is decoupled shard health from metadata.  Delegate health to replication groups. Could be enhanced by streaming replication.  Basically failover between pairs of nodes.&lt;br /&gt;
&lt;br /&gt;
They explained the first proposal.  If they get inserts onto one table, if an insert fails, that node is marked invalid. Josh questioned whether or not this would ever become consistent.  You would need to buffer the writes and replay them or resync-from the one healthy replica.  Also requires that events can never conflict.  It pretty much only supports the insert-only use case, because all writes have to be incremental.  This is the AP proposal out of CAP.&lt;br /&gt;
&lt;br /&gt;
For the 2nd proposal, then RDS could handle that for us.  The 2nd proposal relies on having small replication groups, which would fail over in the event of a node failure.  Streaming replication could be used between replicas.  You&#039;d need small groups with at least 3 nodes.&lt;br /&gt;
&lt;br /&gt;
Josh made a third proposal, using RAFT-like semantics to share metadata and make it mostly consistent.  Various issues were pointed out with this.&lt;br /&gt;
&lt;br /&gt;
Alvaro suggested requiring quorum every time you do a read.  Some discussion of Paxos etc. ensued.&lt;br /&gt;
&lt;br /&gt;
=== FDW Enhancements ===&lt;br /&gt;
&lt;br /&gt;
[http://www.slideshare.net/babystarmonja/foreign-data-wrapper-enhancements Slides used for this session]&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Shigheru Hanada and Esteru Fujita&lt;br /&gt;
&lt;br /&gt;
Note-taker: Josh Berkus&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
Enhancements proposed for 9.5:&lt;br /&gt;
* Inheritance Support: Committed: foreign table can be parent or child of other tables&lt;br /&gt;
* Update push-down: Returned with feedback: updated against Foreign tables without fetching data from the remote node.  &lt;br /&gt;
* Join Push-down: API committed: allows joining on the remote server.&lt;br /&gt;
&lt;br /&gt;
Update pushdown requires certain conditions in the Update statement.  Also it requires a new FDW API, called from nodeModifyTable.&lt;br /&gt;
&lt;br /&gt;
Currently joins are performed on the local server, which can be very slow.  If both tables on on the external server and joins are supported we should be able to join over there.  The FDW API is committed, but pgsql_fdw changes were not committed.  The major issue was &amp;quot;how do we construct the remote query?&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Should we use a parse tree?  They would like to support in Oracle and MySQL FDWs.  A general SQL deparser would be idea for this, but we don&#039;t have one.&lt;br /&gt;
&lt;br /&gt;
We also want sort push-down.  But there is a problem selecting the key for the sort.  Josh asked why.  Shigheru explained that FDW sees only plan tree, and the plan tree generates path information for each key, which includes multiple candidates.  &lt;br /&gt;
&lt;br /&gt;
Other possible enhancements:&lt;br /&gt;
* sort push-down&lt;br /&gt;
* aggregate push-down&lt;br /&gt;
* more aggressive join push-down&lt;br /&gt;
&lt;br /&gt;
For sort push-down, we also need to mark a Foreign Scan as sorted.  But problems: limiting sort key candidates.  Do we need to introduce FOREIGN INDEX concepts?  Should we have FDW catalogs?  Also, how can we be sure that sorting on the target and the local server are identical (collations etc.)?  And what about pre-sorted join results?  He asked for ideas on how to implement this.&lt;br /&gt;
&lt;br /&gt;
Tom suggested that if you took the overhead of doing an explain, you could check and see if it&#039;s doing a merge join on the remote node.  It might be expensive to see the explain plan.&lt;br /&gt;
&lt;br /&gt;
He doesn&#039;t have a really concrete idea how to implement aggregate push-down.  Maybe they should implement a new FDW API, and replace the Aggregate node with a ForeignScan.   Issues include how to determine the semantics of the GROUP BY clause.  Also how do we map local functions to remote ones?  THere&#039;s stuff in the SQL standard for this but not very well defined.&lt;br /&gt;
&lt;br /&gt;
More aggressive join push down would support doing a foreign nestloop scan.  One way to do that is with local small tables we can push materialized data cross the FDW and join against it.  Or we could do a temporary table or VALUES statement.  If we know that the table is replicated on the remote side, we could join against it.&lt;br /&gt;
&lt;br /&gt;
Other ideas?&lt;br /&gt;
 &lt;br /&gt;
Paul asked about extended types, like for PostGIS.  Geometry operators aren&#039;t allowed to pass down through pgsql_fdw.  He had to hack pgsql_fdw in order to pass those through.  Maybe when you declare a server, you could declare which extensions are installed in the server, which would be checked in FDW.  Shigheru thinks this is a good idea.  Right now we don&#039;t push them down because the operator might be different on the target.  &lt;br /&gt;
&lt;br /&gt;
Is an extension a useful unit for this?  Tom and Paul think yes.  Also we don&#039;t actually need to check versions.  We also want to create mappings for individual functions though.&lt;br /&gt;
&lt;br /&gt;
Marco asked about CSTORE_FDW.  The FDWAPI requires us to read row-by-row, which kills some of the advantages of the column store.  Josh asked about COPY protocol; it would be good to copy into remote tables.   &lt;br /&gt;
&lt;br /&gt;
They also talked about pushing down pre-aggregates instead of finished aggregates.  That is, count/sum instead of AVG.  That way it will work with partitioned foreign tables.  Basically, we would export the transition function somehow, like a MapReduce system.  No idea how to do this.  Also, how would it work with non-postgres systems?&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=PgCon2015ClusterSummit&amp;diff=25216</id>
		<title>PgCon2015ClusterSummit</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=PgCon2015ClusterSummit&amp;diff=25216"/>
		<updated>2015-06-18T17:59:02Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* FDW Enhancements */ Format&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=pgCon 2015 Cluster Hacker Summit=&lt;br /&gt;
&lt;br /&gt;
This year&#039;s Cluster Hacker Summit will be part of the [[PgCon_2015_Developer_Unconference]].  As such, this page will be used to coordinate sessions to propose for the Unconference, and eventually to list an agenda for the Clustering Track.&lt;br /&gt;
&lt;br /&gt;
The Cluster Summit covers both general PostgreSQL clustering, as well as PostgresXC and PostgresXL development.&lt;br /&gt;
&lt;br /&gt;
As it is part of the Developer Unconference, Clustering sessions will take place starting in the afternoon of Tuesday, June 16 through 5pm on Wednesday, June 17.  If you are participating, and will not be able to make it on Tuesday, please note that in your attendance comments.&lt;br /&gt;
&lt;br /&gt;
== Attendee RSVPs ==&lt;br /&gt;
&lt;br /&gt;
* Josh Berkus (both days)&lt;br /&gt;
* Koichi Suzuki&lt;br /&gt;
* Tatsuo Ishii&lt;br /&gt;
* Yugo Nagata&lt;br /&gt;
* Steve Singer (arrive tuesday mid-afternoon)&lt;br /&gt;
* Jan Wieck (arrive tuesday evening)&lt;br /&gt;
* Shigeru Hanada&lt;br /&gt;
* Ahsan Hadi&lt;br /&gt;
* Ashutosh Bapat&lt;br /&gt;
* Bruce Momjian&lt;br /&gt;
* Etsuro Fujita&lt;br /&gt;
* Tetsuo Sakata&lt;br /&gt;
* Amit Langote&lt;br /&gt;
* Kyotaro Horiguchi&lt;br /&gt;
* Ozgun Erdogan (Wednesday)&lt;br /&gt;
* Marco Slot (Wednesday)&lt;br /&gt;
* Simon Riggs&lt;br /&gt;
&lt;br /&gt;
== Suggested Sessions ==&lt;br /&gt;
&lt;br /&gt;
For each session below please provide a title and a moderator/leader/speaker for the session. &lt;br /&gt;
&lt;br /&gt;
=== Pgpool-II: toward next major version 3.5 ===&lt;br /&gt;
&lt;br /&gt;
Firstly we report the project progress since last year&#039;s Cluster Summit: introducing pgpool-II 3.4. Then we explain the current status of pgpool-II 3.5 which is under development.&lt;br /&gt;
&lt;br /&gt;
Session Leader: Tatsuo Ishii&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
=== FDW Enhancements ===&lt;br /&gt;
&lt;br /&gt;
Session Leader: Shigeru Hanada and Etsuro Fujita&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
=== Horizontal Scalability and Sharding ===&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Ahsan Hadi, Ashutosh Bapat &lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
=== Slony ===&lt;br /&gt;
&lt;br /&gt;
What is the future for Slony development?  Are users interested in a new Slony based on Logical Decoding?  Who&#039;s going to work on this?&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Steve Singer, Chris Browne, Jan Wieck&lt;br /&gt;
&lt;br /&gt;
==== Session Notes ====&lt;br /&gt;
&lt;br /&gt;
Slony Development&lt;br /&gt;
&lt;br /&gt;
Leader: Steve Singer, Chris Browne, Jan Wieck&lt;br /&gt;
&lt;br /&gt;
Note-taker: Josh Berkus&lt;br /&gt;
&lt;br /&gt;
In the past year Slony development has been pretty stagnant.  Steve has worked on a prototype with Logical Decoding.  Works for a demo, but not all features work, and performance was not all that impressive.  Part of that is that how much we&#039;ve optimized the Slony log.  Logical slony has some lower write overhead, but the latency for assembly on the other side is not insignificant.  &lt;br /&gt;
&lt;br /&gt;
The stability of slony and features are OK, but will it survive with modern features of Postgres.  With some features it will be different.  It does something which others don&#039;t.&lt;br /&gt;
&lt;br /&gt;
Chris: only takes a few hours of work per year to keep up with Postgres releases.  But we&#039;ve been forgetting how to do releases and management.  &lt;br /&gt;
&lt;br /&gt;
Jan: mentioned limitations of UDR/BDR.  But most users are on older versions.  Even if 9.6 has everything built in, people will still be using older versions for 5 years.  Slony was built to allow upgrading.  If it doesn&#039;t make sense to maintain them then we won&#039;t.&lt;br /&gt;
&lt;br /&gt;
Slony is still useful for upgrading across architectures and character decodings.  Josh mentioned the early stage of development of UDR.  Steve said that it would take more than one year to get slony working with Logical Decoding and to make it as stable as trigger-based replication.&lt;br /&gt;
&lt;br /&gt;
Chris asked what the issues were with LD and Slony development.  Jan pointed out that for partial replication ... where you&#039;re replicating a few low-volume tables ... then saving all the WAL for the replication slot is a big loss.  So LD and classic Slony log table need to coexist.&lt;br /&gt;
&lt;br /&gt;
Josh said there&#039;s two reasons why he wants LD: (1) easier installation and (2) bloat in the queue tables caused by long-running transactions (3) removal overhead.  &lt;br /&gt;
&lt;br /&gt;
Re: bloat Jan mentioned Grittner&#039;s snapshot-too-old work.  Josh said that work is partly because of Slony.   You can&#039;t even truncate segments if there&#039;s a long-running transaction.  Chris mentioned the idea of per-table logs. &lt;br /&gt;
&lt;br /&gt;
Moving the reporting queries onto the replica can fix this issue, but it just moves the bloat around.  More discussion around this.  Doing this against a non-forwarding replica would prevent bloat.  &lt;br /&gt;
&lt;br /&gt;
Other requests:&lt;br /&gt;
&lt;br /&gt;
* Parallel initial data copy.  &lt;br /&gt;
* Call Slony as a library (mostly Python)&lt;br /&gt;
* Add tables to multiple versions of databases&lt;br /&gt;
* No table locks&lt;br /&gt;
* More visibility commands via Slonik, once it&#039;s a library&lt;br /&gt;
* Cancel subscribe set in progress&lt;br /&gt;
&lt;br /&gt;
Libraries: one way to get around the multiple library issue is to expose the function API.  But according to Jan the function API is not complete.  Steve would rather have Slonik as a shared library.  Calling the slony SPs directly isn&#039;t safe.  Dave Cramer asked if we do a Python library how are we going to call it from Java?  We&#039;ll create a C shared library.&lt;br /&gt;
&lt;br /&gt;
Valentin suggestes exposing the shared libaries via stored procedures.  Chris pointed out that the lack of autonomous transactions prevents this.  But if the library is wrapped in functions it can be exposed.  Or create some kind of REST API.  Jan said that they&#039;re planning on supporting pgAdmin4, so an abstracted libary would support this.  This is a good idea.  Some people use GUIs, but some don&#039;t.  &lt;br /&gt;
&lt;br /&gt;
Steve asked if people are using it for DR.  Josh mentioned one multi-region case.  Valintin said more availability than DR.  &lt;br /&gt;
&lt;br /&gt;
Jan said that more visibility functions for Slonik is a must once it&#039;s a library.  And it would make the API more stable because you wouldn&#039;t have to use the Slony catalog.&lt;br /&gt;
&lt;br /&gt;
Steve asked if Slony could take one exclusive lock at a time would help.  One user said no, they don&#039;t get enough downtime. But others said yes.  Rod really wants an add trigger command which takes an access exclusive lock. That&#039;s a major postgres issue in terms of locking and tables.  Jan speculated how that would be possible.  Valintin tries to resolve this by setting statement_timeout and having it fail.  The Slony team has some idea of how to do this.  This is similar to concurrent index creation.  Jan will look at doing CREATE TRIGGER CONCURRENTLY.  Suggested that there should be a general lock state where you ask for a lock concurrently.  This should be a function call.  Kevin suggested that we should call this &amp;quot;deferrable&amp;quot; rather than Concurrent.  With timeouts.&lt;br /&gt;
&lt;br /&gt;
Steve appealed for people to help implement some of these things.  Jan will sign up for LOCK TABLE DEFERRABLE.  Josh said that he&#039;s help test/spec the API.  Biggest issues with syntax is varadic arguments.  &lt;br /&gt;
&lt;br /&gt;
Chris asked if anyone was using logshipping, and someone said yes, and they&#039;re using the daemon to apply the logs.&lt;br /&gt;
&lt;br /&gt;
Chris asked about DDL.  Change in 2.2 which allows passing in the DDL string instead of needing a file.  PostgresQL 9.5 will have DDL event replication.  Do we care about building this?  Chris said the most easy change would be to allow dropping a table to automatically drop it from replication.  Rejecting DDL not run through execute script would be even better.  It should be an option, which you can override.  Josh voted on blocking DDL.&lt;br /&gt;
&lt;br /&gt;
Steve&#039;s concern with blocking DDL is that people do this for legitimate reasons.  Josh mentioned stupid dev tricks where they bring slony down by running rake on the production cluster.  Also a library would be compatible with rake.&lt;br /&gt;
&lt;br /&gt;
Do people see Slony as still being relevant in 2-3 years if BDR/UDR succeeds?  Hard to be sure, since it&#039;s not mature yet.&lt;br /&gt;
&lt;br /&gt;
They then set some targets:&lt;br /&gt;
&lt;br /&gt;
* Parallel initial data copy: Slony 2.3+, requires Postgres 9.3+  &lt;br /&gt;
* Call Slony as a library (mostly Python): Slony 2.3&lt;br /&gt;
* Add tables to multiple versions of databases: works with library&lt;br /&gt;
* No table locks: Postgres 9.6+&lt;br /&gt;
* More visibility commands via Slonik, once it&#039;s a library: Slony 2.4?&lt;br /&gt;
* Cancel subscribe set in progress&lt;br /&gt;
* Prevent DDL: Postgres 9.4, slony 2.3&lt;br /&gt;
&lt;br /&gt;
Not likely to work on Slony + Logical Decoding, because it&#039;s bigger than all of the features above.  Making it stable would take years, and it doesnt&#039; perform better.  Valintin is working on LD systems and building libaries on top of LD like a python library and replication to Kafka.  Steve&#039;s code is on Github.  Particularly, being able to switch between LD and triggers would be really complex.&lt;br /&gt;
&lt;br /&gt;
Josh mentioned the issue around WAL log volume from the slony buffers.  One user requested the ability to execute a command on a group of slaves.  So an kind of EXECUTE SCRIPT on a group of nodes.&lt;br /&gt;
&lt;br /&gt;
=== Bi Directional Replication &amp;amp; Logical Decoding ===&lt;br /&gt;
&lt;br /&gt;
Including DDL replication, Online Upgrade, Logical Replication, Bi Directional Replication etc&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Simon Riggs, Andres Freund&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
BDR and UDR etc.&lt;br /&gt;
&lt;br /&gt;
Leader: Simon&lt;br /&gt;
&lt;br /&gt;
Note-taker: Josh Berkus&lt;br /&gt;
&lt;br /&gt;
This will be about development of BDR, not using BDR.  Will be only 10 minutes about BDR.&lt;br /&gt;
&lt;br /&gt;
BDR stands for Bi-Directional Replication, has been put together across a couple years.  Has been released a couple months ago.  Is being used in production at some sites.  Have released 0.9.1 bugfixing 0.9. But it&#039;s not 1.0 yet.  We want to get it into Postgres.&lt;br /&gt;
&lt;br /&gt;
BDR allows replication to flow in two directions.  It&#039;s logical replication which permits making changes to the data as it&#039;s replicated.  Translating the WAL stream (transaction log stream) and uses Logical Decoding to take action and stream changes.  Works on a commit-by-commit basis.&lt;br /&gt;
&lt;br /&gt;
Each server has a sender process which talks to an apply process on another server.  These are implemented as background workers, a 9.3 feature.  9.4 with the BDR plugin supports one-way replication.&lt;br /&gt;
&lt;br /&gt;
Two-way replication requires handling conflicts.  This requests patches on postgres, so they have a &amp;quot;spoon&amp;quot; of Postgres (not quite a fork).  Most of this is in 9.5, but there&#039;s a couple things still waiting for 9.6.  Sequence AM was not included in 9.5, also WAL messaging, to send non-transactional WAL messages.  Implemented logical replication, then built upon that to make bi-directional replication possible.  Now building a system to handle DDL so that it can be replicated.  The DDL is hard because we need it in &amp;quot;absolute form&amp;quot;.  The DDL deparse code is still in a module.&lt;br /&gt;
&lt;br /&gt;
The other part of the system is zero-downtime upgrade.  This uses UDR.  It works with version 9.4.&lt;br /&gt;
&lt;br /&gt;
Discussion of logical vs. binary replication.  Grant asked what about parallelism on the apply side of the replication. Andres tested this, and it wasn&#039;t really a problem; the applier is much faster than the writes on the origin nodes.  &lt;br /&gt;
&lt;br /&gt;
Kevin took issue with the assertion that commit order of application doesn&#039;t allow seeing anoninalies.  He brought up an example case where that&#039;s not true with batch processing.  &lt;br /&gt;
&lt;br /&gt;
Discussion of features required in core started.&lt;br /&gt;
&lt;br /&gt;
Open items for including features in core are:&lt;br /&gt;
&lt;br /&gt;
* SEQAM - ready for commit&lt;br /&gt;
* WAL messages - need to discuss and have a flamewar but otherwise there.&lt;br /&gt;
* Metadata - where do we store metadata for the replication system?  Connection information?&lt;br /&gt;
* Control - still use functions, or implement special-case DDL?&lt;br /&gt;
* DDL Replication Code&lt;br /&gt;
&lt;br /&gt;
Metadata is currently stored in a mix of security labels and metadata tables.  Is this a conflict with RLS?  Shouldn&#039;t be, but it&#039;s a bit of a hack; it&#039;s done because it&#039;s extra data which is created and deleted with a table.&lt;br /&gt;
&lt;br /&gt;
UDR Functions:&lt;br /&gt;
* subscribue&lt;br /&gt;
&lt;br /&gt;
BDR:&lt;br /&gt;
* create group&lt;br /&gt;
* join group&lt;br /&gt;
&lt;br /&gt;
Robert asked a question about synchronizing timestamps.  This motivated some of the patches to 9.5.&lt;br /&gt;
&lt;br /&gt;
Should we have full DDL for this, or should we have functions?  Simon thinks functions are fine.  Haas likes DDL because it&#039;s more self-documenting.  Simon argued that there&#039;s been a lot of changes to the functions. It&#039;s been iterating.  But once it&#039;s in core (Haas), people expect very stable APIs, so you won&#039;t be able to change them anyway.  Some discussion about dump and restore followed.  There are some things which can&#039;t be restored.  Replication slots is a good example of this, Haas feels like that&#039;s kind of unfinished.  There&#039;s a pretty good argument that you want to be able to restore your replication sets.  &lt;br /&gt;
&lt;br /&gt;
The problem of deprecating APIs (Smith) already exists.  We can add more arguments. Which model do you want?   As soon as you put it into syntax, it&#039;s  a lot harder to change parameters etc. There&#039;s also the question of to what extent we want to keep backwards compatibility of replication stuff.  &lt;br /&gt;
&lt;br /&gt;
Do we need a generic concept of a supervisor worker, because people keep reinventing this concept?  &lt;br /&gt;
&lt;br /&gt;
What about the metadata?  We want it to work even if people rename tables, etc.  Does this work reasonably well for 100,000 table cases?  Should work with relcache, should be fine.  &lt;br /&gt;
&lt;br /&gt;
Currently subscribe/group uses pgdump, which requires passing in connections string so that we can dump out the database.  That&#039;s not the only problem with the dependancy on pgdump.  Dependancies on external binaries is kind of an issue.  Abstracting out pgdump has been a TODO forever.  Slony needs self-connection information too.  You could have BDR GUCs, but that didn&#039;t work really well.  This is different for each database.&lt;br /&gt;
&lt;br /&gt;
pgdump is used to create the initial snapshot of the data and structure.  You can use pgbasebackup instead, but that copies everything.  Other database tools do it table-by-table.  Getting sufficient administration tools into core is critical.  We don&#039;t want to have 5 separate sets of tools like we do now most of which are buggy.  Grant says: make the APIs really well, it&#039;s easy to build the tools on top of the APIs.  He doesn&#039;t want tools which work on the base stuff.   We have different sets of tools because they have different use cases.&lt;br /&gt;
&lt;br /&gt;
=== pg_shard v2.0 and Lessons Learned from NoSQL Databases ===&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Ozgun Erdogan, Marco Slot&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
pg_shard 2.0&lt;br /&gt;
&lt;br /&gt;
Ozgun explained how pg_shard is put together.  There&#039;s a metadata node, which connects to a bunch of backend nodes.  Each backend node contains multiple shards in one database. The shards are tables.&lt;br /&gt;
&lt;br /&gt;
In pg_shard 2.0, the metadata will be fully distributed.&lt;br /&gt;
&lt;br /&gt;
The metatdata node tracks where shards are located.  And shards can be redistributed.&lt;br /&gt;
&lt;br /&gt;
So there are a few proposals for how to distribute metadata.  There are several use-cases they are trying to answer:&lt;br /&gt;
* NoSQL use-case on the eventual consistency model&lt;br /&gt;
** real-time analytics over log data&lt;br /&gt;
* SAP Hana-like use case.  ACID-compliant scalable RDBMS database.&lt;br /&gt;
&lt;br /&gt;
Not like OracleRAC which is shared disk.  &lt;br /&gt;
&lt;br /&gt;
The proposals for sharing metadata:&lt;br /&gt;
# replication metadata to all nodes assuming communtative writes ... that is write order doesn&#039;t matter.  So replicate change statements between all nodes.  Use BDR.&lt;br /&gt;
# Shard health is decoupled shard health from metadata.  Delegate health to replication groups. Could be enhanced by streaming replication.  Basically failover between pairs of nodes.&lt;br /&gt;
&lt;br /&gt;
They explained the first proposal.  If they get inserts onto one table, if an insert fails, that node is marked invalid. Josh questioned whether or not this would ever become consistent.  You would need to buffer the writes and replay them or resync-from the one healthy replica.  Also requires that events can never conflict.  It pretty much only supports the insert-only use case, because all writes have to be incremental.  This is the AP proposal out of CAP.&lt;br /&gt;
&lt;br /&gt;
For the 2nd proposal, then RDS could handle that for us.  The 2nd proposal relies on having small replication groups, which would fail over in the event of a node failure.  Streaming replication could be used between replicas.  You&#039;d need small groups with at least 3 nodes.&lt;br /&gt;
&lt;br /&gt;
Josh made a third proposal, using RAFT-like semantics to share metadata and make it mostly consistent.  Various issues were pointed out with this.&lt;br /&gt;
&lt;br /&gt;
Alvaro suggested requiring quorum every time you do a read.  Some discussion of Paxos etc. ensued.&lt;br /&gt;
&lt;br /&gt;
=== FDW Enhancements ===&lt;br /&gt;
&lt;br /&gt;
Session Leaders: Shigheru Hanada and Esteru Fujita&lt;br /&gt;
&lt;br /&gt;
Note-taker: Josh Berkus&lt;br /&gt;
&lt;br /&gt;
==== Attendees ====&lt;br /&gt;
&lt;br /&gt;
==== Meeting Notes ====&lt;br /&gt;
&lt;br /&gt;
Enhancements proposed for 9.5:&lt;br /&gt;
* Inheritance Support: Committed: foreign table can be parent or child of other tables&lt;br /&gt;
* Update push-down: Returned with feedback: updated against Foreign tables without fetching data from the remote node.  &lt;br /&gt;
* Join Push-down: API committed: allows joining on the remote server.&lt;br /&gt;
&lt;br /&gt;
Update pushdown requires certain conditions in the Update statement.  Also it requires a new FDW API, called from nodeModifyTable.&lt;br /&gt;
&lt;br /&gt;
Currently joins are performed on the local server, which can be very slow.  If both tables on on the external server and joins are supported we should be able to join over there.  The FDW API is committed, but pgsql_fdw changes were not committed.  The major issue was &amp;quot;how do we construct the remote query?&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Should we use a parse tree?  They would like to support in Oracle and MySQL FDWs.  A general SQL deparser would be idea for this, but we don&#039;t have one.&lt;br /&gt;
&lt;br /&gt;
We also want sort push-down.  But there is a problem selecting the key for the sort.  Josh asked why.  Shigheru explained that FDW sees only plan tree, and the plan tree generates path information for each key, which includes multiple candidates.  &lt;br /&gt;
&lt;br /&gt;
Other possible enhancements:&lt;br /&gt;
* sort push-down&lt;br /&gt;
* aggregate push-down&lt;br /&gt;
* more aggressive join push-down&lt;br /&gt;
&lt;br /&gt;
For sort push-down, we also need to mark a Foreign Scan as sorted.  But problems: limiting sort key candidates.  Do we need to introduce FOREIGN INDEX concepts?  Should we have FDW catalogs?  Also, how can we be sure that sorting on the target and the local server are identical (collations etc.)?  And what about pre-sorted join results?  He asked for ideas on how to implement this.&lt;br /&gt;
&lt;br /&gt;
Tom suggested that if you took the overhead of doing an explain, you could check and see if it&#039;s doing a merge join on the remote node.  It might be expensive to see the explain plan.&lt;br /&gt;
&lt;br /&gt;
He doesn&#039;t have a really concrete idea how to implement aggregate push-down.  Maybe they should implement a new FDW API, and replace the Aggregate node with a ForeignScan.   Issues include how to determine the semantics of the GROUP BY clause.  Also how do we map local functions to remote ones?  THere&#039;s stuff in the SQL standard for this but not very well defined.&lt;br /&gt;
&lt;br /&gt;
More aggressive join push down would support doing a foreign nestloop scan.  One way to do that is with local small tables we can push materialized data cross the FDW and join against it.  Or we could do a temporary table or VALUES statement.  If we know that the table is replicated on the remote side, we could join against it.&lt;br /&gt;
&lt;br /&gt;
Other ideas?&lt;br /&gt;
 &lt;br /&gt;
Paul asked about extended types, like for PostGIS.  Geometry operators aren&#039;t allowed to pass down through pgsql_fdw.  He had to hack pgsql_fdw in order to pass those through.  Maybe when you declare a server, you could declare which extensions are installed in the server, which would be checked in FDW.  Shigheru thinks this is a good idea.  Right now we don&#039;t push them down because the operator might be different on the target.  &lt;br /&gt;
&lt;br /&gt;
Is an extension a useful unit for this?  Tom and Paul think yes.  Also we don&#039;t actually need to check versions.  We also want to create mappings for individual functions though.&lt;br /&gt;
&lt;br /&gt;
Marco asked about CSTORE_FDW.  The FDWAPI requires us to read row-by-row, which kills some of the advantages of the column store.  Josh asked about COPY protocol; it would be good to copy into remote tables.   &lt;br /&gt;
&lt;br /&gt;
They also talked about pushing down pre-aggregates instead of finished aggregates.  That is, count/sum instead of AVG.  That way it will work with partitioned foreign tables.  Basically, we would export the transition function somehow, like a MapReduce system.  No idea how to do this.  Also, how would it work with non-postgres systems?&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=PgCon_2015_Developer_Unconference&amp;diff=25048</id>
		<title>PgCon 2015 Developer Unconference</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=PgCon_2015_Developer_Unconference&amp;diff=25048"/>
		<updated>2015-06-15T07:17:45Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Topics */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;An Unconference-style multi-track (three tracks are currently planned) event for active PostgreSQL developers will be held from the afternoon of Tuesday 16 June, 2015 through Wednesday 17 June 2015 at the University of Ottawa, as part of PGCon 2015.  This Unconference will be focused on technical PostgreSQL development discussions ranging from Clustering and replication to the infrastructure which runs postgresql.org.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Please add your name to the topics you are interested in attending!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Topics ==&lt;br /&gt;
&lt;br /&gt;
Developers are asked to propose topics which they wish to either present on or which they would like another individual to present on.  All topics should be clearly related to PostgreSQL development.  The topic should be added to the table below and any required attendees (presumably at least the presenter, and the requester if different) listed.  Other attendees of the Unconference who are interested should list themselves as Optional.  Note that non-technical topics related to PostgreSQL development will be addressed during the invite-only Developer meeting, being held in advance of the Unconference.  Further, the Developer Unconference is for developers of PostgreSQL and user-oriented topics are not appropriate for this venue.&lt;br /&gt;
&lt;br /&gt;
== Slot assignment ==&lt;br /&gt;
&lt;br /&gt;
Slots will be assigned based on the topic&#039;s interest among the attendees of the Unconference (the number of individuals who listed themselves as attendees).  Final determination on any particular topic will be made by the Unconference organizers.  Please only participate if you are confident of your attendance at the Unconference.&lt;br /&gt;
&lt;br /&gt;
== Venue ==&lt;br /&gt;
&lt;br /&gt;
These meetings will be held at the University of Ottawa.  The topics selected, the schedule and the specific room assignments will be published closer to the event and will be based on the information provided here.  Please direct any questions to Dave Page (dpage@pgadmin.org).&lt;br /&gt;
&lt;br /&gt;
== Sponsorship ==&lt;br /&gt;
&lt;br /&gt;
The Developer Unconference will be sponsored by Salesforce.com, and by NTT Open Source for the Clustering Track.&lt;br /&gt;
&lt;br /&gt;
== Attendees ==&lt;br /&gt;
&lt;br /&gt;
While the Unconference is open to all attendees of PGCon, formal invitations will be sent to specific PostgreSQL developers, including the Core team, Major Contributors, Committers, and other developers who have been involved in the 9.4 release.  These invitations are intended to encourage developers to attend the Unconference but we are unable to guarantee every invitee a speaking slot.&lt;br /&gt;
&lt;br /&gt;
== RSVPs ==&lt;br /&gt;
&lt;br /&gt;
The following people have RSVPed to the meeting (in alphabetical order, by surname):&lt;br /&gt;
&lt;br /&gt;
* Ashutosh Bapat&lt;br /&gt;
* Oleg Bartunov&lt;br /&gt;
* Josh Berkus&lt;br /&gt;
* Christopher Browne&lt;br /&gt;
* Joe Conway&lt;br /&gt;
* Jeff Davis&lt;br /&gt;
* Andrew Dunstan&lt;br /&gt;
* Ozgun Erdogan&lt;br /&gt;
* Andres Freund&lt;br /&gt;
* Stephen Frost&lt;br /&gt;
* Masao Fujii&lt;br /&gt;
* Etsuro Fujita&lt;br /&gt;
* Peter Geoghegan&lt;br /&gt;
* Kevin Grittner&lt;br /&gt;
* Robert Haas&lt;br /&gt;
* Ahsan Hadi&lt;br /&gt;
* Magnus Hagander&lt;br /&gt;
* Shigeru Hanada&lt;br /&gt;
* Álvaro Herrera&lt;br /&gt;
* Kyotaro Horiguchi&lt;br /&gt;
* Thierry Husson (Wednesday @ 11am)&lt;br /&gt;
* Ayumi Ishii&lt;br /&gt;
* Tatsuo Ishii&lt;br /&gt;
* Stefan Kaltenbrunner&lt;br /&gt;
* Amit Kapila&lt;br /&gt;
* Konstantin Knizhnik&lt;br /&gt;
* KaiGai Kohei (arrive tuesday evening)&lt;br /&gt;
* Alexander Korotkov&lt;br /&gt;
* Ilya Kosmodemiansky&lt;br /&gt;
* Tom Lane&lt;br /&gt;
* Amit Langote&lt;br /&gt;
* Grant McAlister&lt;br /&gt;
* Mack McCauley&lt;br /&gt;
* Noah Misch&lt;br /&gt;
* Bruce Momjian&lt;br /&gt;
* Yugo Nagata&lt;br /&gt;
* Satoshi Nagayasu&lt;br /&gt;
* Jim Nasby&lt;br /&gt;
* Dave Page&lt;br /&gt;
* Christophe Pettus&lt;br /&gt;
* Paul Ramsey&lt;br /&gt;
* Kumar Rajeev Rastogi&lt;br /&gt;
* Simon Riggs&lt;br /&gt;
* Tetsuo Sakata&lt;br /&gt;
* Masahiko Sawada&lt;br /&gt;
* Dilip Kumar&lt;br /&gt;
* Marco Slot (Wednesday)&lt;br /&gt;
* Greg Smith&lt;br /&gt;
* Steve Singer (arrive tuesday mid-afternoon)&lt;br /&gt;
* Jose Luis Tallon (arrives tuesday evening)&lt;br /&gt;
* Rod Taylor&lt;br /&gt;
* Tomas Vondra&lt;br /&gt;
* Jan Wieck (arrive tuesday evening)&lt;br /&gt;
* Chris Winters&lt;br /&gt;
* Nat Wyatt&lt;br /&gt;
* Naoya Anzai (arrive tuesday evening)&lt;br /&gt;
* David Steele (arrive tuesday evening)&lt;br /&gt;
* Ingmar Alting&lt;br /&gt;
* Mehmet Emin KARAKAŞ&lt;br /&gt;
* Yasin TATAR&lt;br /&gt;
* Fabrízio de Royes Mello&lt;br /&gt;
* Euler Taveira&lt;br /&gt;
* Fabio Telles&lt;br /&gt;
* Dan Shuster&lt;br /&gt;
* Arul Shaji&lt;br /&gt;
* Motoyuki Kawaba (arrive Tuesday evening)&lt;br /&gt;
* Yurie Enomoto&lt;br /&gt;
&lt;br /&gt;
=Topics=&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Please add any topics you wish covered to the table.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;For any topics you are requesting or presenting on, please add your name in the Required column.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;For any topics you would like to attend, please add your name in the Interested column.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
!Topic&lt;br /&gt;
!Policy&lt;br /&gt;
!Taker of Notes&lt;br /&gt;
!Required Attendees&lt;br /&gt;
!Interested Attendees&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Picture!&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|All!&lt;br /&gt;
|All!&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|pgAdmin4&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Dave Page, Stephen Frost&lt;br /&gt;
|Magnus Hagander, Joe Conway, David Steele, Fabrízio de Royes Mello, Satoshi Nagayasu&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Infrastructure Q&amp;amp;A&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Dave Page, Stephen Frost, Stefan Kaltenbrunner, Magnus Hagander, Joe Conway&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|WWW Team Meeting&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Dave Page, Stephen Frost, Stefan Kaltenbrunner, Magnus Hagander&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Advocacy Team Meeting&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Stephen Frost&lt;br /&gt;
|Magnus Hagander, Greg Smith, Jim Nasby, Josh Berkus, Joe Conway&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Vertical Scalability w.r.t Writes&lt;br /&gt;
|Open&lt;br /&gt;
|Amit Kapila&lt;br /&gt;
|Amit Kapila&lt;br /&gt;
|Greg Smith, Hannu Valtonen, Ilya Kosmodemiansky, Tomas Vondra, Grant McAlister, Joe Conway, Peter Geoghegan, Kyotaro Horiguchi, Simon Riggs, Amit Langote, Andres Freund, Robert Haas, David Steele, Rod Taylor, Jim Nasby, Chris Winters, Nat Wyatt, Noah Misch, Masao Fujii, Mehmet Emin KARAKAŞ, Christophe Pettus, Fabrízio de Royes Mello, Euler Taveira, Fabio Telles, Andrew Dunstan, Mack McCauley, Masahiko Sawada, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Security Team Meeting&lt;br /&gt;
|Closed&lt;br /&gt;
|&lt;br /&gt;
|Heikki Linnakangas, Stephen Frost, Magnus Hagander&lt;br /&gt;
|Noah Misch, Álvaro Herrera, Andres Freund, Robert Haas, Tom Lane, Andrew Dunstan&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Native Compilation + LLVM&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Kumar Rajeev Rastogi&lt;br /&gt;
|Jeff Davis, Ozgun Erdogan, Tomas Vondra, Peter Geoghegan, Robert Haas, Chris Browne, Josh Berkus, Ingmar Alting, Masao Fujii, Christophe Pettus, Jose Luis Tallon&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|Horizontal Scalability / Sharding in PostgreSQL]] - ground covered so far and remaining to be covered. &lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Ahsan Hadi, Ashutosh Bapat, Etsuro Fujita&lt;br /&gt;
|Hannu Valtonen, Jeff Davis, Amit Langote, Kyotaro Horiguchi, Tetsuo Sakata, Simon Riggs, Robert Haas, David Steele, Rod Taylor, Chris Browne, Jim Nasby, Josh Berkus, Chris Winters, Masao Fujii, Mehmet Emin KARAKAŞ, Fabrízio de Royes Mello, Euler Taveira, Fabio Telles, Satoshi Nagayasu, Andrew Dunstan, Mack McCauley, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PGCAC Board Meeting 2015]]&lt;br /&gt;
|Open*&lt;br /&gt;
|Josh Berkus&lt;br /&gt;
|Josh Berkus, Chris Browne, Steve Singer, Dan Langille, Dave Page&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|pgPool2 towards version 3.5]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Tatsuo Ishii&lt;br /&gt;
|Ashutosh Bapat, Ahsan Hadi, Yurie Enomoto&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Partitioning&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Amit Langote&lt;br /&gt;
|Hannu Valtonen, Ashutosh Bapat, Jeff Davis, Kyotaro Horiguchi, KaiGai Kohei, Noah Misch, Tetsuo Sakata, Peter Geoghegan, Álvaro Herrera, Thierry Husson, Joe Conway, Naoya Anzai, Robert Haas, David Steele, Chris Browne, Jim Nasby, Josh Berkus, Masao Fujii, Mehmet Emin KARAKAŞ, Fabrízio de Royes Mello, Euler Taveira, Fabio Telles, Andrew Dunstan, Jose Luis Tallon, Yurie Enomoto, Mack McCauley, Masahiko Sawada, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|Foreign Data Wrapper enhancements]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Shigeru Hanada, Etsuro Fujita&lt;br /&gt;
|KaiGai Kohei, Hannu Valtonen, Ashutosh Bapat, Jeff Davis, Amit Langote, Kyotaro Horiguchi, Noah Misch, Tetsuo Sakata, Naoya Anzai, Robert Haas, Jim Nasby, Josh Berkus, Chris Winters, Ingmar Alting, Mehmet Emin KARAKAŞ, Jose Luis Tallon&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Utilization of modern semiconductors - GPU, SSD, NVRAM, FPGA, PMEM...&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|KaiGai Kohei&lt;br /&gt;
|Matthew Wilcox, Josh Berkus, Satoshi Nagayasu, Jose Luis Tallon, Naoya Anzai, Mack McCauley, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Native Columnar Storage&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Álvaro Herrera&lt;br /&gt;
|Ozgun Erdogan, Tomas Vondra, KaiGai Kohei, Amit Kapila, Josh Berkus, Naoya Anzai, Amit Langote, Robert Haas, David Steele, Rod Taylor, Chris Browne, Jim Nasby, Chris Winters, Nat Wyatt, Masao Fujii, Fabrízio de Royes Mello, Euler Taveira, Satoshi Nagayasu, Mack McCauley, Masahiko Sawada, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Future of PostgreSQL shared-nothing cluster&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Konstantin Knizhnik, Alexander Korotkov, Oleg Bartunov&lt;br /&gt;
|Jeff Davis, Amit Langote, Kumar Rajeev Rastogi, Josh Berkus, Simon Riggs, Robert Haas, Jim Nasby, Masao Fujii, Christophe Pettus, Fabrízio de Royes Mello, Euler Taveira, Fabio Telles, Yurie Enomoto, Masahiko Sawada, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PostgreSQL and SMR Drives]] - the future of magnetic storage means very expensive random writes&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Jeff Davis&lt;br /&gt;
|Kumar Rajeev Rastogi, Noah Misch, Ilya Kosmodemiansky, Amit Kapila, Simon Riggs, Rod Taylor, Jim Nasby, Josh Berkus, Nat Wyatt, Christophe Pettus, Satoshi Nagayasu&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|Slony Development]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Steve Singer, Chris Browne, Jan Wieck&lt;br /&gt;
| Josh Berkus, Rod Taylor, Jim Nasby, Satoshi Nagayasu, Yurie Enomoto&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[DockerizingPostgres|Dockerizing Postgres]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Josh Berkus&lt;br /&gt;
| Simon Riggs, Nat Wyatt, Christophe Pettus, Fabrízio de Royes Mello&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|Bi Directional Replication &amp;amp; Logical Decoding|BDR]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Simon Riggs&lt;br /&gt;
| Andres Freund, Jim Nasby, Josh Berkus, Mehmet Emin KARAKAŞ, Christophe Pettus, Fabrízio de Royes Mello, Euler Taveira&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Autonomous Transactions&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Simon Riggs, Kumar Rajeev Rastogi&lt;br /&gt;
| David Steele, Jim Nasby, Josh Berkus, Nat Wyatt, Masao Fujii, Euler Taveira, Andrew Dunstan, Masahiko Sawada&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Audit Logging&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| David Steele&lt;br /&gt;
| Josh Berkus, Nat Wyatt, Masao Fujii, Christophe Pettus, Fabio Telles, Satoshi Nagayasu, Yurie Enomoto, Mack McCauley, Masahiko Sawada&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|pg_shard v2.0 and Lessons Learned from NoSQL Databases ]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Ozgun Erdogan, Marco Slot &lt;br /&gt;
| Josh Berkus, Jim Nasby, Josh Berkus, Chris Winters, Mehmet Emin KARAKAŞ, Fabrízio de Royes Mello, Satoshi Nagayasu, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Direction of json  and jsonb&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Andrew Dunstan&lt;br /&gt;
| Josh Berkus, Christophe Pettus, Masahiko Sawada&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Native Sparse Set Type &lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Andrew Dunstan&lt;br /&gt;
| Josh Berkus&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Testing Framework Adequacy&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Andrew Dunstan&lt;br /&gt;
| Josh Berkus, Christophe Pettus, Mack McCauley&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== pgAdmin4 ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Infrastructure Q&amp;amp;A ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== WWW Team Meeting ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Advocacy Team Meeting ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Vertical Scalability w.r.t Writes ==&lt;br /&gt;
Purpose of this discussion:&lt;br /&gt;
* Discuss about priority/importance of various performance and scalability problems&lt;br /&gt;
* Solution/Idea to solve most important problem(&#039;s)&lt;br /&gt;
* Is pgbench sufficient to capture various kind of real world workloads?&lt;br /&gt;
&lt;br /&gt;
Some of important performance problems I have in mind are:&lt;br /&gt;
* Avoid/Reduce Vacuum Freeze&lt;br /&gt;
* Bloat&lt;br /&gt;
      Heap&lt;br /&gt;
      Index&lt;br /&gt;
* Instability in TPS due to checkpointer flush&lt;br /&gt;
* Tuple size&lt;br /&gt;
      Heap Tuple Header &lt;br /&gt;
      Alignment in index can lead to bigger index size for simple datatypes&lt;br /&gt;
Scalability bottlenecks&lt;br /&gt;
* Locks&lt;br /&gt;
      ProcArrayLock&lt;br /&gt;
      WALWriteLock&lt;br /&gt;
      CLOGControlLock&lt;br /&gt;
      Lock for Relation Extension&lt;br /&gt;
&lt;br /&gt;
* Writes, especially when data doesn&#039;t fit in shared buffers.&lt;br /&gt;
      Write Performance&lt;br /&gt;
      Double Buffering&lt;br /&gt;
      In-memory table/tablespaces&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Security Team Meeting ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* This will be, ehem, secure so nothing will be written here&lt;br /&gt;
&lt;br /&gt;
== Partitioning ==&lt;br /&gt;
Proposal to enhance partitioning support in PostgreSQL was posted to -hackers last year and resulted in discussion of some ideas regarding implementation. Late in the discussion, a crude WIP patch was also posted with some experimental syntax, catalog changes, an idea for internal representation and a proof-of-concept INSERT tuple routing function demonstrating practicality of the internal representation. It would be nice to carry the discussion forward at the same time implementing a patch to be proposed, reviewed early in the 9.6 development cycle. Points to discuss could be:  &lt;br /&gt;
&lt;br /&gt;
* New features and old inheritance based implementation&lt;br /&gt;
* Planner considerations for new partitioned table&lt;br /&gt;
* Need for a new Append-like executor node for partitioned tables&lt;br /&gt;
* DML/DDL restrictions on partitioned tables and partitions&lt;br /&gt;
* Basically any considerations for partitioned tables and partitions that are explicitly defined so at a layer that&#039;s above the storage layer&lt;br /&gt;
* Other points that come up&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Utilization of modern semiconductors ==&lt;br /&gt;
Recent evolution of semiconductor devices make us re-consider the assumption we stand on, and utilization of its power is key of innovation.&lt;br /&gt;
We&#039;d like to have a discussion to get the future direction in short and middle/long term.&lt;br /&gt;
&lt;br /&gt;
* GPU, FPGA - have advantage on simple but massive amount of calculation. It allows DBMS to perform as data processing platform that works nearby data.&lt;br /&gt;
&lt;br /&gt;
* SSD, NVRAM - likely, game changer of storage layer on both of read/write workloads. DBMS also has to pay attention characteristics of these devices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Future of PostgreSQL shared-nothing cluster ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
In 2015 PostgreSQL Professional company started project of migration PostgreSQL-XL to codebase of PostgreSQL 9.4 and increasing its stability and usability. At this unconference session we&#039;d like to discuss current progress and further development. Generally we&#039;d like to find ways to reduce difference between PostgreSQL and its shared-nothing cluster fork so that burden of the maintenance become manageable. &lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL and SMR Drives ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Native Columnar Storage ==&lt;br /&gt;
&lt;br /&gt;
See Alvaro&#039;s [http://www.postgresql.org/message-id/20150611230316.GM133018@postgresql.org email to Hackers].&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Audit Logging ==&lt;br /&gt;
&lt;br /&gt;
Audit logging is an important part of a RDBMS for many users and applications.  Discuss how best to incorporate audit logging into PostgreSQL and what must be included at a minimum to make the feature viable. &lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Direction of json  and jsonb ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
What are the future needs of the JSON types? Recent suggestions have included an indexable &amp;quot;exists&amp;quot; operator, the json pointer and json patch standards, &lt;br /&gt;
recursive merge, intersection, and being able to sssign to a subdocument (json#&amp;gt;path as an lvalue). .What are people using these types for, and what are &lt;br /&gt;
the major gaps in functionality?&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Native Sparse Set Type ==&lt;br /&gt;
&lt;br /&gt;
Sets over small domains can be reasonably modeled by bitmaps, but sets over very large domains can not.&lt;br /&gt;
Is there a need for such sets? How would we implement them? Arrays? Balanced trees? Something else?&lt;br /&gt;
What types of sets would we allow? Anything with Btree operators, or more restricted? What would the notation look like?&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Testing Framework Adequacy ==&lt;br /&gt;
&lt;br /&gt;
The buildfarm is more than 10 years old, and the testing needs of Postgres and its ofware ecosystem have changed radically in that time.&lt;br /&gt;
What do we now need in the way of testing? How do we test complex arrangements such as the various sorts of replication in an automated way?&lt;br /&gt;
Do we need a new framwork, or can the existing framework be adapted to our needs?&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=PgCon_2015_Developer_Unconference&amp;diff=25047</id>
		<title>PgCon 2015 Developer Unconference</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=PgCon_2015_Developer_Unconference&amp;diff=25047"/>
		<updated>2015-06-15T07:16:59Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Topics */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;An Unconference-style multi-track (three tracks are currently planned) event for active PostgreSQL developers will be held from the afternoon of Tuesday 16 June, 2015 through Wednesday 17 June 2015 at the University of Ottawa, as part of PGCon 2015.  This Unconference will be focused on technical PostgreSQL development discussions ranging from Clustering and replication to the infrastructure which runs postgresql.org.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Please add your name to the topics you are interested in attending!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Topics ==&lt;br /&gt;
&lt;br /&gt;
Developers are asked to propose topics which they wish to either present on or which they would like another individual to present on.  All topics should be clearly related to PostgreSQL development.  The topic should be added to the table below and any required attendees (presumably at least the presenter, and the requester if different) listed.  Other attendees of the Unconference who are interested should list themselves as Optional.  Note that non-technical topics related to PostgreSQL development will be addressed during the invite-only Developer meeting, being held in advance of the Unconference.  Further, the Developer Unconference is for developers of PostgreSQL and user-oriented topics are not appropriate for this venue.&lt;br /&gt;
&lt;br /&gt;
== Slot assignment ==&lt;br /&gt;
&lt;br /&gt;
Slots will be assigned based on the topic&#039;s interest among the attendees of the Unconference (the number of individuals who listed themselves as attendees).  Final determination on any particular topic will be made by the Unconference organizers.  Please only participate if you are confident of your attendance at the Unconference.&lt;br /&gt;
&lt;br /&gt;
== Venue ==&lt;br /&gt;
&lt;br /&gt;
These meetings will be held at the University of Ottawa.  The topics selected, the schedule and the specific room assignments will be published closer to the event and will be based on the information provided here.  Please direct any questions to Dave Page (dpage@pgadmin.org).&lt;br /&gt;
&lt;br /&gt;
== Sponsorship ==&lt;br /&gt;
&lt;br /&gt;
The Developer Unconference will be sponsored by Salesforce.com, and by NTT Open Source for the Clustering Track.&lt;br /&gt;
&lt;br /&gt;
== Attendees ==&lt;br /&gt;
&lt;br /&gt;
While the Unconference is open to all attendees of PGCon, formal invitations will be sent to specific PostgreSQL developers, including the Core team, Major Contributors, Committers, and other developers who have been involved in the 9.4 release.  These invitations are intended to encourage developers to attend the Unconference but we are unable to guarantee every invitee a speaking slot.&lt;br /&gt;
&lt;br /&gt;
== RSVPs ==&lt;br /&gt;
&lt;br /&gt;
The following people have RSVPed to the meeting (in alphabetical order, by surname):&lt;br /&gt;
&lt;br /&gt;
* Ashutosh Bapat&lt;br /&gt;
* Oleg Bartunov&lt;br /&gt;
* Josh Berkus&lt;br /&gt;
* Christopher Browne&lt;br /&gt;
* Joe Conway&lt;br /&gt;
* Jeff Davis&lt;br /&gt;
* Andrew Dunstan&lt;br /&gt;
* Ozgun Erdogan&lt;br /&gt;
* Andres Freund&lt;br /&gt;
* Stephen Frost&lt;br /&gt;
* Masao Fujii&lt;br /&gt;
* Etsuro Fujita&lt;br /&gt;
* Peter Geoghegan&lt;br /&gt;
* Kevin Grittner&lt;br /&gt;
* Robert Haas&lt;br /&gt;
* Ahsan Hadi&lt;br /&gt;
* Magnus Hagander&lt;br /&gt;
* Shigeru Hanada&lt;br /&gt;
* Álvaro Herrera&lt;br /&gt;
* Kyotaro Horiguchi&lt;br /&gt;
* Thierry Husson (Wednesday @ 11am)&lt;br /&gt;
* Ayumi Ishii&lt;br /&gt;
* Tatsuo Ishii&lt;br /&gt;
* Stefan Kaltenbrunner&lt;br /&gt;
* Amit Kapila&lt;br /&gt;
* Konstantin Knizhnik&lt;br /&gt;
* KaiGai Kohei (arrive tuesday evening)&lt;br /&gt;
* Alexander Korotkov&lt;br /&gt;
* Ilya Kosmodemiansky&lt;br /&gt;
* Tom Lane&lt;br /&gt;
* Amit Langote&lt;br /&gt;
* Grant McAlister&lt;br /&gt;
* Mack McCauley&lt;br /&gt;
* Noah Misch&lt;br /&gt;
* Bruce Momjian&lt;br /&gt;
* Yugo Nagata&lt;br /&gt;
* Satoshi Nagayasu&lt;br /&gt;
* Jim Nasby&lt;br /&gt;
* Dave Page&lt;br /&gt;
* Christophe Pettus&lt;br /&gt;
* Paul Ramsey&lt;br /&gt;
* Kumar Rajeev Rastogi&lt;br /&gt;
* Simon Riggs&lt;br /&gt;
* Tetsuo Sakata&lt;br /&gt;
* Masahiko Sawada&lt;br /&gt;
* Dilip Kumar&lt;br /&gt;
* Marco Slot (Wednesday)&lt;br /&gt;
* Greg Smith&lt;br /&gt;
* Steve Singer (arrive tuesday mid-afternoon)&lt;br /&gt;
* Jose Luis Tallon (arrives tuesday evening)&lt;br /&gt;
* Rod Taylor&lt;br /&gt;
* Tomas Vondra&lt;br /&gt;
* Jan Wieck (arrive tuesday evening)&lt;br /&gt;
* Chris Winters&lt;br /&gt;
* Nat Wyatt&lt;br /&gt;
* Naoya Anzai (arrive tuesday evening)&lt;br /&gt;
* David Steele (arrive tuesday evening)&lt;br /&gt;
* Ingmar Alting&lt;br /&gt;
* Mehmet Emin KARAKAŞ&lt;br /&gt;
* Yasin TATAR&lt;br /&gt;
* Fabrízio de Royes Mello&lt;br /&gt;
* Euler Taveira&lt;br /&gt;
* Fabio Telles&lt;br /&gt;
* Dan Shuster&lt;br /&gt;
* Arul Shaji&lt;br /&gt;
* Motoyuki Kawaba (arrive Tuesday evening)&lt;br /&gt;
* Yurie Enomoto&lt;br /&gt;
&lt;br /&gt;
=Topics=&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Please add any topics you wish covered to the table.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;For any topics you are requesting or presenting on, please add your name in the Required column.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;For any topics you would like to attend, please add your name in the Interested column.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
!Topic&lt;br /&gt;
!Policy&lt;br /&gt;
!Taker of Notes&lt;br /&gt;
!Required Attendees&lt;br /&gt;
!Interested Attendees&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Picture!&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|All!&lt;br /&gt;
|All!&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|pgAdmin4&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Dave Page, Stephen Frost&lt;br /&gt;
|Magnus Hagander, Joe Conway, David Steele, Fabrízio de Royes Mello, Satoshi Nagayasu&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Infrastructure Q&amp;amp;A&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Dave Page, Stephen Frost, Stefan Kaltenbrunner, Magnus Hagander, Joe Conway&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|WWW Team Meeting&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Dave Page, Stephen Frost, Stefan Kaltenbrunner, Magnus Hagander&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Advocacy Team Meeting&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Stephen Frost&lt;br /&gt;
|Magnus Hagander, Greg Smith, Jim Nasby, Josh Berkus, Joe Conway&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Vertical Scalability w.r.t Writes&lt;br /&gt;
|Open&lt;br /&gt;
|Amit Kapila&lt;br /&gt;
|Amit Kapila&lt;br /&gt;
|Greg Smith, Hannu Valtonen, Ilya Kosmodemiansky, Tomas Vondra, Grant McAlister, Joe Conway, Peter Geoghegan, Kyotaro Horiguchi, Simon Riggs, Amit Langote, Andres Freund, Robert Haas, David Steele, Rod Taylor, Jim Nasby, Chris Winters, Nat Wyatt, Noah Misch, Masao Fujii, Mehmet Emin KARAKAŞ, Christophe Pettus, Fabrízio de Royes Mello, Euler Taveira, Fabio Telles, Andrew Dunstan, Mack McCauley, Masahiko Sawada, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Security Team Meeting&lt;br /&gt;
|Closed&lt;br /&gt;
|&lt;br /&gt;
|Heikki Linnakangas, Stephen Frost, Magnus Hagander&lt;br /&gt;
|Noah Misch, Álvaro Herrera, Andres Freund, Robert Haas, Tom Lane, Andrew Dunstan&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Native Compilation + LLVM&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Kumar Rajeev Rastogi&lt;br /&gt;
|Jeff Davis, Ozgun Erdogan, Tomas Vondra, Peter Geoghegan, Robert Haas, Chris Browne, Josh Berkus, Ingmar Alting, Masao Fujii, Christophe Pettus, Jose Luis Tallon&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|Horizontal Scalability / Sharding in PostgreSQL]] - ground covered so far and remaining to be covered. &lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Ahsan Hadi, Ashutosh Bapat, Etsuro Fujita&lt;br /&gt;
|Hannu Valtonen, Jeff Davis, Amit Langote, Kyotaro Horiguchi, Tetsuo Sakata, Simon Riggs, Robert Haas, David Steele, Rod Taylor, Chris Browne, Jim Nasby, Josh Berkus, Chris Winters, Masao Fujii, Mehmet Emin KARAKAŞ, Fabrízio de Royes Mello, Euler Taveira, Fabio Telles, Satoshi Nagayasu, Andrew Dunstan, Mack McCauley, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PGCAC Board Meeting 2015]]&lt;br /&gt;
|Open*&lt;br /&gt;
|Josh Berkus&lt;br /&gt;
|Josh Berkus, Chris Browne, Steve Singer, Dan Langille, Dave Page&lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|pgPool2 towards version 3.5]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Tatsuo Ishii&lt;br /&gt;
|Ashutosh Bapat, Ahsan Hadi, Yurie Enomoto&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Partitioning&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Amit Langote&lt;br /&gt;
|Hannu Valtonen, Ashutosh Bapat, Jeff Davis, Kyotaro Horiguchi, KaiGai Kohei, Noah Misch, Tetsuo Sakata, Peter Geoghegan, Álvaro Herrera, Thierry Husson, Joe Conway, Naoya Anzai, Robert Haas, David Steele, Chris Browne, Jim Nasby, Josh Berkus, Masao Fujii, Mehmet Emin KARAKAŞ, Fabrízio de Royes Mello, Euler Taveira, Fabio Telles, Andrew Dunstan, Jose Luis Tallon, Yurie Enomoto, Mack McCauley, Masahiko Sawada, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|Foreign Data Wrapper enhancements]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Shigeru Hanada, Etsuro Fujita&lt;br /&gt;
|KaiGai Kohei, Hannu Valtonen, Ashutosh Bapat, Jeff Davis, Amit Langote, Kyotaro Horiguchi, Noah Misch, Tetsuo Sakata, Naoya Anzai, Robert Haas, Jim Nasby, Josh Berkus, Chris Winters, Ingmar Alting, Mehmet Emin KARAKAŞ, Jose Luis Tallon&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Utilization of modern semiconductors - GPU, SSD, NVRAM, FPGA, PMEM...&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|KaiGai Kohei&lt;br /&gt;
|Matthew Wilcox, Josh Berkus, Satoshi Nagayasu, Jose Luis Tallon, Naoya Anzai, Mack McCauley, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Native Columnar Storage&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Álvaro Herrera&lt;br /&gt;
|Ozgun Erdogan, Tomas Vondra, KaiGai Kohei, Amit Kapila, Josh Berkus, Naoya Anzai, Amit Langote, Robert Haas, David Steele, Rod Taylor, Chris Browne, Jim Nasby, Chris Winters, Nat Wyatt, Masao Fujii, Fabrízio de Royes Mello, Euler Taveira, Satoshi Nagayasu, Mack McCauley, Masahiko Sawada, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Future of PostgreSQL shared-nothing cluster&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Konstantin Knizhnik, Alexander Korotkov, Oleg Bartunov&lt;br /&gt;
|Jeff Davis, Amit Langote, Kumar Rajeev Rastogi, Josh Berkus, Simon Riggs, Robert Haas, Jim Nasby, Masao Fujii, Christophe Pettus, Fabrízio de Royes Mello, Euler Taveira, Fabio Telles, Yurie Enomoto, Masahiko Sawada&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PostgreSQL and SMR Drives]] - the future of magnetic storage means very expensive random writes&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
|Jeff Davis&lt;br /&gt;
|Kumar Rajeev Rastogi, Noah Misch, Ilya Kosmodemiansky, Amit Kapila, Simon Riggs, Rod Taylor, Jim Nasby, Josh Berkus, Nat Wyatt, Christophe Pettus, Satoshi Nagayasu&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|Slony Development]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Steve Singer, Chris Browne, Jan Wieck&lt;br /&gt;
| Josh Berkus, Rod Taylor, Jim Nasby, Satoshi Nagayasu, Yurie Enomoto&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[DockerizingPostgres|Dockerizing Postgres]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Josh Berkus&lt;br /&gt;
| Simon Riggs, Nat Wyatt, Christophe Pettus, Fabrízio de Royes Mello&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|Bi Directional Replication &amp;amp; Logical Decoding|BDR]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Simon Riggs&lt;br /&gt;
| Andres Freund, Jim Nasby, Josh Berkus, Mehmet Emin KARAKAŞ, Christophe Pettus, Fabrízio de Royes Mello, Euler Taveira&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Autonomous Transactions&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Simon Riggs, Kumar Rajeev Rastogi&lt;br /&gt;
| David Steele, Jim Nasby, Josh Berkus, Nat Wyatt, Masao Fujii, Euler Taveira, Andrew Dunstan, Masahiko Sawada&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Audit Logging&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| David Steele&lt;br /&gt;
| Josh Berkus, Nat Wyatt, Masao Fujii, Christophe Pettus, Fabio Telles, Satoshi Nagayasu, Yurie Enomoto, Mack McCauley, Masahiko Sawada&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|[[PgCon2015ClusterSummit|pg_shard v2.0 and Lessons Learned from NoSQL Databases ]]&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Ozgun Erdogan, Marco Slot &lt;br /&gt;
| Josh Berkus, Jim Nasby, Josh Berkus, Chris Winters, Mehmet Emin KARAKAŞ, Fabrízio de Royes Mello, Satoshi Nagayasu, Shigeru HANADA&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Direction of json  and jsonb&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Andrew Dunstan&lt;br /&gt;
| Josh Berkus, Christophe Pettus, Masahiko Sawada&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Native Sparse Set Type &lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Andrew Dunstan&lt;br /&gt;
| Josh Berkus&lt;br /&gt;
&lt;br /&gt;
|- style=&amp;quot;background-color:lightgray;&amp;quot;&lt;br /&gt;
|Testing Framework Adequacy&lt;br /&gt;
|Open&lt;br /&gt;
|&lt;br /&gt;
| Andrew Dunstan&lt;br /&gt;
| Josh Berkus, Christophe Pettus, Mack McCauley&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== pgAdmin4 ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Infrastructure Q&amp;amp;A ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== WWW Team Meeting ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Advocacy Team Meeting ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Vertical Scalability w.r.t Writes ==&lt;br /&gt;
Purpose of this discussion:&lt;br /&gt;
* Discuss about priority/importance of various performance and scalability problems&lt;br /&gt;
* Solution/Idea to solve most important problem(&#039;s)&lt;br /&gt;
* Is pgbench sufficient to capture various kind of real world workloads?&lt;br /&gt;
&lt;br /&gt;
Some of important performance problems I have in mind are:&lt;br /&gt;
* Avoid/Reduce Vacuum Freeze&lt;br /&gt;
* Bloat&lt;br /&gt;
      Heap&lt;br /&gt;
      Index&lt;br /&gt;
* Instability in TPS due to checkpointer flush&lt;br /&gt;
* Tuple size&lt;br /&gt;
      Heap Tuple Header &lt;br /&gt;
      Alignment in index can lead to bigger index size for simple datatypes&lt;br /&gt;
Scalability bottlenecks&lt;br /&gt;
* Locks&lt;br /&gt;
      ProcArrayLock&lt;br /&gt;
      WALWriteLock&lt;br /&gt;
      CLOGControlLock&lt;br /&gt;
      Lock for Relation Extension&lt;br /&gt;
&lt;br /&gt;
* Writes, especially when data doesn&#039;t fit in shared buffers.&lt;br /&gt;
      Write Performance&lt;br /&gt;
      Double Buffering&lt;br /&gt;
      In-memory table/tablespaces&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Security Team Meeting ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* This will be, ehem, secure so nothing will be written here&lt;br /&gt;
&lt;br /&gt;
== Partitioning ==&lt;br /&gt;
Proposal to enhance partitioning support in PostgreSQL was posted to -hackers last year and resulted in discussion of some ideas regarding implementation. Late in the discussion, a crude WIP patch was also posted with some experimental syntax, catalog changes, an idea for internal representation and a proof-of-concept INSERT tuple routing function demonstrating practicality of the internal representation. It would be nice to carry the discussion forward at the same time implementing a patch to be proposed, reviewed early in the 9.6 development cycle. Points to discuss could be:  &lt;br /&gt;
&lt;br /&gt;
* New features and old inheritance based implementation&lt;br /&gt;
* Planner considerations for new partitioned table&lt;br /&gt;
* Need for a new Append-like executor node for partitioned tables&lt;br /&gt;
* DML/DDL restrictions on partitioned tables and partitions&lt;br /&gt;
* Basically any considerations for partitioned tables and partitions that are explicitly defined so at a layer that&#039;s above the storage layer&lt;br /&gt;
* Other points that come up&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Utilization of modern semiconductors ==&lt;br /&gt;
Recent evolution of semiconductor devices make us re-consider the assumption we stand on, and utilization of its power is key of innovation.&lt;br /&gt;
We&#039;d like to have a discussion to get the future direction in short and middle/long term.&lt;br /&gt;
&lt;br /&gt;
* GPU, FPGA - have advantage on simple but massive amount of calculation. It allows DBMS to perform as data processing platform that works nearby data.&lt;br /&gt;
&lt;br /&gt;
* SSD, NVRAM - likely, game changer of storage layer on both of read/write workloads. DBMS also has to pay attention characteristics of these devices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Future of PostgreSQL shared-nothing cluster ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
In 2015 PostgreSQL Professional company started project of migration PostgreSQL-XL to codebase of PostgreSQL 9.4 and increasing its stability and usability. At this unconference session we&#039;d like to discuss current progress and further development. Generally we&#039;d like to find ways to reduce difference between PostgreSQL and its shared-nothing cluster fork so that burden of the maintenance become manageable. &lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL and SMR Drives ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Native Columnar Storage ==&lt;br /&gt;
&lt;br /&gt;
See Alvaro&#039;s [http://www.postgresql.org/message-id/20150611230316.GM133018@postgresql.org email to Hackers].&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Audit Logging ==&lt;br /&gt;
&lt;br /&gt;
Audit logging is an important part of a RDBMS for many users and applications.  Discuss how best to incorporate audit logging into PostgreSQL and what must be included at a minimum to make the feature viable. &lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Direction of json  and jsonb ==&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
What are the future needs of the JSON types? Recent suggestions have included an indexable &amp;quot;exists&amp;quot; operator, the json pointer and json patch standards, &lt;br /&gt;
recursive merge, intersection, and being able to sssign to a subdocument (json#&amp;gt;path as an lvalue). .What are people using these types for, and what are &lt;br /&gt;
the major gaps in functionality?&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Native Sparse Set Type ==&lt;br /&gt;
&lt;br /&gt;
Sets over small domains can be reasonably modeled by bitmaps, but sets over very large domains can not.&lt;br /&gt;
Is there a need for such sets? How would we implement them? Arrays? Balanced trees? Something else?&lt;br /&gt;
What types of sets would we allow? Anything with Btree operators, or more restricted? What would the notation look like?&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
== Testing Framework Adequacy ==&lt;br /&gt;
&lt;br /&gt;
The buildfarm is more than 10 years old, and the testing needs of Postgres and its ofware ecosystem have changed radically in that time.&lt;br /&gt;
What do we now need in the way of testing? How do we test complex arrangements such as the various sorts of replication in an automated way?&lt;br /&gt;
Do we need a new framwork, or can the existing framework be adapted to our needs?&lt;br /&gt;
&lt;br /&gt;
=== Meeting Notes ===&lt;br /&gt;
* To be filled in&lt;br /&gt;
&lt;br /&gt;
=== Attendees ===&lt;br /&gt;
* To be filled in&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=PgCon2015ClusterSummit&amp;diff=24748</id>
		<title>PgCon2015ClusterSummit</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=PgCon2015ClusterSummit&amp;diff=24748"/>
		<updated>2015-05-27T07:26:43Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Attendee RSVPs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=pgCon 2015 Cluster Hacker Summit=&lt;br /&gt;
&lt;br /&gt;
This year&#039;s Cluster Hacker Summit will be part of the [[PgCon_2015_Developer_Unconference]].  As such, this page will be used to coordinate sessions to propose for the Unconference, and eventually to list an agenda for the Clustering Track.&lt;br /&gt;
&lt;br /&gt;
The Cluster Summit covers both general PostgreSQL clustering, as well as PostgresXC development.&lt;br /&gt;
&lt;br /&gt;
As it is part of the Developer Unconference, Clustering sessions will take place starting in the afternoon of Tuesday, June 16 through 5pm on Wednesday, June 17.  If you are participating, and will not be able to make it on Tuesday, please note that in your attendance comments.&lt;br /&gt;
&lt;br /&gt;
== Attendee RSVPs ==&lt;br /&gt;
&lt;br /&gt;
* Josh Berkus (both days)&lt;br /&gt;
* Koichi Suzuki&lt;br /&gt;
* Tatsuo Ishii&lt;br /&gt;
* Yugo Nagata&lt;br /&gt;
* Steve Singer (arrive tuesday mid-afternoon)&lt;br /&gt;
* Jan Wieck (arrive tuesday evening)&lt;br /&gt;
* Shigeru Hanada&lt;br /&gt;
&lt;br /&gt;
== Suggested Sessions ==&lt;br /&gt;
&lt;br /&gt;
For each session below please provide a title and a moderator/leader/speaker for the session. &lt;br /&gt;
&lt;br /&gt;
* PostgresXC Team Meeting:  who?&lt;br /&gt;
* BDR and Logical Decoding: Andres/Simon/?&lt;br /&gt;
* Pgpool-II toward next major version 3.5: Tatsuo&lt;br /&gt;
* FDW enhancements: Shigeru&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=PgCon2015ClusterSummit&amp;diff=24747</id>
		<title>PgCon2015ClusterSummit</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=PgCon2015ClusterSummit&amp;diff=24747"/>
		<updated>2015-05-27T07:26:25Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Suggested Sessions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=pgCon 2015 Cluster Hacker Summit=&lt;br /&gt;
&lt;br /&gt;
This year&#039;s Cluster Hacker Summit will be part of the [[PgCon_2015_Developer_Unconference]].  As such, this page will be used to coordinate sessions to propose for the Unconference, and eventually to list an agenda for the Clustering Track.&lt;br /&gt;
&lt;br /&gt;
The Cluster Summit covers both general PostgreSQL clustering, as well as PostgresXC development.&lt;br /&gt;
&lt;br /&gt;
As it is part of the Developer Unconference, Clustering sessions will take place starting in the afternoon of Tuesday, June 16 through 5pm on Wednesday, June 17.  If you are participating, and will not be able to make it on Tuesday, please note that in your attendance comments.&lt;br /&gt;
&lt;br /&gt;
== Attendee RSVPs ==&lt;br /&gt;
&lt;br /&gt;
* Josh Berkus (both days)&lt;br /&gt;
* Koichi Suzuki&lt;br /&gt;
* Tatsuo Ishii&lt;br /&gt;
* Yugo Nagata&lt;br /&gt;
* Steve Singer (arrive tuesday mid-afternoon)&lt;br /&gt;
* Jan Wieck (arrive tuesday evening)&lt;br /&gt;
&lt;br /&gt;
== Suggested Sessions ==&lt;br /&gt;
&lt;br /&gt;
For each session below please provide a title and a moderator/leader/speaker for the session. &lt;br /&gt;
&lt;br /&gt;
* PostgresXC Team Meeting:  who?&lt;br /&gt;
* BDR and Logical Decoding: Andres/Simon/?&lt;br /&gt;
* Pgpool-II toward next major version 3.5: Tatsuo&lt;br /&gt;
* FDW enhancements: Shigeru&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Developer_FAQ/ja&amp;diff=22849</id>
		<title>Developer FAQ/ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Developer_FAQ/ja&amp;diff=22849"/>
		<updated>2014-07-04T04:57:30Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* どんなスタイルが PostgreSQL ソースコードでは使われますか? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
&lt;br /&gt;
== 開発への参加 ==&lt;br /&gt;
&lt;br /&gt;
=== どのようにすれば PostgreSQL の開発に参加できますか? ===&lt;br /&gt;
&lt;br /&gt;
ソースコードをダウンロードして読んでください。 詳細は「[[#最新のソースツリーをダウンロードする方法、また最新のソースに追随する方法は？|最新のソースツリーをダウンロードする方法、また最新のソースに追随する方法は？]]」を参照して下さい。&lt;br /&gt;
&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/ pgsql-hackers メーリングリスト] (&amp;quot;hackers&amp;quot; と呼ばれます) に参加し、読んでください。ここはプロジェクトの主要開発者やコアメンバが開発について議論する場です。&lt;br /&gt;
&lt;br /&gt;
=== 最新のソースツリーをダウンロードする方法、また最新のソースに追随する方法は？ ===&lt;br /&gt;
&lt;br /&gt;
ソースツリーを取得する方法は幾つかあります。たまに開発に参加するだけの人は最新のソースツリー・スナップショットを ftp://ftp.postgresql.org/pub/snapshot/ から取得できます。&lt;br /&gt;
&lt;br /&gt;
一般的な開発者はソースコード管理システムに anonymous でアクセスして取得しています。ソースツリーは現在 git で管理されています。git からのソースコード取得について、詳細は http://developer.postgresql.org/pgdocs/postgres/git.html と [[Working with Git]] を参考にしてください。&lt;br /&gt;
&lt;br /&gt;
=== どのような開発環境が必要ですか? ===&lt;br /&gt;
&lt;br /&gt;
PostgreSQL は主にC言語で開発されています。ソースコードの対象は、主な UNIX プラットフォームと Windows (XP, 2000 以降) です。&lt;br /&gt;
&lt;br /&gt;
多くの開発者は Unix ライクなOS上で、[http://gcc.gnu.org GCC], [http://www.gnu.org/software/make/make.html GNU Make], [http://www.gnu.org/software/gdb/gdb.html GDB], [http://www.gnu.org/software/autoconf/ Autoconf] などのオープンソースのツールを利用して開発しています。もしあなたがオープンソースソフトウェアに貢献した経験があれば、これらのツールは既に良くご存知でしょう。Windows これらのツールを使う開発者は [http://www.mingw.org/ MinGW] を使用します。&lt;br /&gt;
もっとも、Windows上のほとんどの開発は、今のところマイクロソフトの Visual Studio 2005(version 8)開発環境と付属のツールで行われています。&lt;br /&gt;
&lt;br /&gt;
PostgreSQL をビルドするために必要なソフトウェアの完全な一覧は「[http://www.postgresql.jp/document/current/html/install-requirements.html 必要条件]」を参照してください。&lt;br /&gt;
&lt;br /&gt;
ソースコードを頻繁にリビルドする開発者は configure 時に --enable-depend フラグを指定することもできます。これを使うと、ヘッダファイルを修正した際に、それに依存する全てのソースファイルもリビルドされるようになります。&lt;br /&gt;
&lt;br /&gt;
src/Makefile.custom で環境変数を設定することができます (例: CUSTOM_COPT)。これはすべてのコンパイルで使用されます。&lt;br /&gt;
&lt;br /&gt;
=== どの項目の開発が望まれていますか? ===&lt;br /&gt;
未解決の機能は [[Todo]] にまとまっています。&lt;br /&gt;
&lt;br /&gt;
それぞれの項目については、ML の[http://archives.postgresql.org/ アーカイブ]、標準SQL、推奨書籍などを参考にしてください。参照: [[#開発者向きの良書はありますか?|開発者向けの書籍]])&lt;br /&gt;
&lt;br /&gt;
=== どのようにすれば PostgreSQL ウェブサイトの開発に参加できますか? ===&lt;br /&gt;
PostgreSQL ウェブサイトの開発は、[http://archives.postgresql.org/pgsql-www/ pgsql-www メーリングリスト]で議論され、インフラチームによって管理されています。postgresql.orgのウェブサイトのソースコードは Subversion のリポジトリに格納され、[http://pgweb.postgresql.org Tracプロジェクト]の一部として提供されています。&lt;br /&gt;
&lt;br /&gt;
== 開発ツールとヘルプ ==&lt;br /&gt;
&lt;br /&gt;
=== ソースコードの構成はどうなっていますか? ===&lt;br /&gt;
&lt;br /&gt;
『[http://www.postgresql.org/developer/ext.backend.html How PostgreSQL Processes a Query] (PostgreSQL のクエリ処理方式)』(これはソースコードの src/tools/backend/index.html にもあります) をブラウザで見てください。データフロー、フローチャートの中のバックエンド構成要素、共有メモリ内の構成について、簡単に記述されています。フローチャート内の矩形をクリックすると説明が表示されます。説明文の中のディレクトリ名をクリックすると、ソースディレクトリにジャンプし、実際のソースコードを読むことができます。他にも、ソースコード・ディレクトリの中に README ファイルが幾つかあり、モジュールの関数を説明しています。ブラウザからそれらのファイルを読むこともできます。&lt;br /&gt;
&lt;br /&gt;
ソースツリーに含まれる文書以外には、コードについて記述されている論文や発表資料が http://www.postgresql.org/developer/coding にあります。素晴らしい発表資料は http://neilconway.org/talks/hacking/ でも見つかります。&lt;br /&gt;
&lt;br /&gt;
=== 開発に利用できるツールには何がありますか? ===&lt;br /&gt;
&lt;br /&gt;
まず、src/tools ディレクトリ内にある全てのファイルは開発者のために用意されたものです。&lt;br /&gt;
&lt;br /&gt;
 RELEASE_CHANGES リリースのたびに変更が必要な項目&lt;br /&gt;
 backend         backend ディレクトリ内の説明と処理の流れ&lt;br /&gt;
 ccsym           使用中のコンパイラが作成する標準 define を見つける&lt;br /&gt;
 copyright       コピーライト&lt;br /&gt;
&lt;br /&gt;
 entab           スペース文字をタブ文字に変換する (pgindent で使用される)&lt;br /&gt;
 find_static     static 関数に変更できる関数を見つける&lt;br /&gt;
 find_typedef    ソースコード中の typedef を見つける&lt;br /&gt;
 find_badmacros  括弧の使い方が不適切なマクロを見つける&lt;br /&gt;
 fsync           ファイル同期を行うシステムコールのコストを比較するスクリプト&lt;br /&gt;
 make_ctags      vi 用の &#039;tags&#039; ファイルを各ディレクトリに作成する&lt;br /&gt;
 make_diff       *.orig とソースの差分を作成する&lt;br /&gt;
 make_etags      emacs 用の &#039;etags&#039; ファイルを作成する&lt;br /&gt;
 make_keywords   キーワードを SQL&#039;92 と比較する&lt;br /&gt;
 make_mkid       mkid ID ファイルを作成する&lt;br /&gt;
 pgcvslog        それぞれのリリースのための変更リストを作成する&lt;br /&gt;
 pginclude       インクルード・ファイルを追加 / 削除するスクリプト&lt;br /&gt;
 pgindent        ソースファイルのインデントを行う&lt;br /&gt;
 pgtest          半自動化されたビルドシステム&lt;br /&gt;
 thread          スレッドのテストをするスクリプト&lt;br /&gt;
&lt;br /&gt;
src/include/catalog には以下のファイルもあります。&lt;br /&gt;
&lt;br /&gt;
 unused_oids     システムカタログ内で使われていないOIDを見つけるスクリプト&lt;br /&gt;
 duplicate_oids  システムカタログ内で重複しているOIDを見つけるスクリプト&lt;br /&gt;
&lt;br /&gt;
tools/backend については既に他の Q&amp;amp;A で説明済みです。&lt;br /&gt;
&lt;br /&gt;
第2に、タグファイルを扱えるエディタが必要です。関数呼び出しから関数定義をタグ付けできます。さらに低いレベルの関数を手繰ることができ、その後元の関数へ戻ることができます。tag または etags をサポートしているエディタは数多くあります。&lt;br /&gt;
&lt;br /&gt;
第3に、id-utils を ftp://ftp.gnu.org/gnu/id-utils/ から取得してください。&lt;br /&gt;
&lt;br /&gt;
tools/make_mkid を実行し、ソースのシンボルのアーカイブを作成することで、高速に検索できます。&lt;br /&gt;
&lt;br /&gt;
cscope (http://cscope.sf.net/) を使う開発者もいます。その他には glimpse (http://webglimpse.net/) も使われます。&lt;br /&gt;
&lt;br /&gt;
tools/make_diff は差分パッチファイルを作成するツールです。パッチはコンテキスト形式になります。メーリングリストにパッチを投稿する場合はこのコンテキスト形式にしてください。&lt;br /&gt;
&lt;br /&gt;
pgindent はソースコードのスタイルを標準の書式に修正するツールです。通常は、開発サイクルの最終段階で実行されます。ソースコードのスタイルについては[[#What.27s_the_formatting_style_used_in_PostgreSQL_source_code.3F|この質問]]も参考にしてください。&lt;br /&gt;
&lt;br /&gt;
pginclude は  #include を必要ならば追加、不要ならば削除するスクリプトです。&lt;br /&gt;
&lt;br /&gt;
型や関数のようなビルトイン・オブジェクトを追加する場合、それらに対して OID を割り当てる必要があります。この際の規約は、1-9999 の範囲の OID を重複が無いように手作業で割り当てることです。(機構的にはそれぞれのシステムカタログ内で一意であれば問題ないのですが、分かりやすくするためシステム全体で一意になるようにしています。) unused_oids というスクリプトが src/include/catalog にあり、現在使用していない OID を表示します。新しい OID を割り当てる際には unused_oids を参照して未使用のものを使ってください。可能ならば、関連する機能を持つ既存のオブジェクトの近くの OID を選びます。また、OID の割り当てミスを検出する duplicate_oids スクリプトもあります。&lt;br /&gt;
&lt;br /&gt;
=== どんなスタイルが PostgreSQL ソースコードでは使われますか? ===&lt;br /&gt;
&lt;br /&gt;
私たちの標準スタイルは BSD 式です。コードのインデントにはタブを用い、タブはスペース4個分としています。使用するエディタやファイルビューアのタブ幅をスペース4個に設定しておいてください。&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;vi&#039;&#039;&#039; の場合には &amp;lt;code&amp;gt;.exrc&amp;lt;/code&amp;gt; か &amp;lt;code&amp;gt;.vimrc&amp;lt;/code&amp;gt; で以下の設定をします:&lt;br /&gt;
 set tabstop=4 shiftwidth=4 noexpandtab&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;less&#039;&#039;&#039; や &#039;&#039;&#039;more&#039;&#039;&#039; では、&amp;lt;code&amp;gt;-x4&amp;lt;/code&amp;gt; を指定すると適切にインデントされます。&lt;br /&gt;
&lt;br /&gt;
tools/editors ディレクトリには emacs, xemacs, vim 用のサンプル設定ファイルがあります。これは PostgreSQL のコーディング・スタイルを維持するのに役立ちます。&lt;br /&gt;
&lt;br /&gt;
pgindent は OS の indent ツールに適切なフラグを指定して実行し、コードを整形します。pgindent は全てのソースコード・ファイルに対して、ベータテストの時期に実行されます。全てのソースファイルは一貫性のある形式に自動で整形されます。記述したとおりに改行されることが必要なコメントは、ブロックコメント形式にする必要があります。コメントを /*------ から開始してください。ブロックコメントは勝手に整形されることはありません。&lt;br /&gt;
&lt;br /&gt;
ドキュメントの『[http://www.postgresql.jp/document/current/html/source-format.html 書式]』も参照してください。また、[http://archives.postgresql.org/message-id/1221125165.5637.12.camel@abbas-laptop この投稿]は変数や関数名の命名方針について述べています。&lt;br /&gt;
&lt;br /&gt;
なぜ私たちがソースコード・スタイルにこれほど気にするのかについては、コーディングスタイルの価値が[http://ezine.daemonnews.org/200112/single_coding_style.html この記事]で述べられています。&lt;br /&gt;
&lt;br /&gt;
=== システムカタログのダイアグラムはありますか? ===&lt;br /&gt;
&lt;br /&gt;
はい。以下を参照してください&lt;br /&gt;
* [http://dalibo.org/_media/articles/catalog.png PNG 形式]&lt;br /&gt;
* [http://svn.postgresql.fr/repos/materials/advocacy/trunk/posters/catalogs83.svg SVG 形式]&lt;br /&gt;
&lt;br /&gt;
=== 開発者向きの良書はありますか? ===&lt;br /&gt;
&lt;br /&gt;
5冊挙げておきます:&lt;br /&gt;
* An Introduction to Database Systems, by C.J. Date, Addison, Wesley&lt;br /&gt;
* A Guide to the SQL Standard, by C.J. Date, et. al, Addison, Wesley&lt;br /&gt;
* Fundamentals of Database Systems, by Elmasri and Navathe&lt;br /&gt;
* Transaction Processing, by Jim Gray and Andreas Reuter, Morgan Kaufmann&lt;br /&gt;
* Transactional Information Systems, by Gerhard Weikum and Gottfried Vossen, Morgan Kaufmann&lt;br /&gt;
&lt;br /&gt;
=== configure とは何ですか? ===&lt;br /&gt;
&lt;br /&gt;
configure と configure.in ファイルは GNU autoconf パッケージの一部です。configure を使うと、OS の様々な機能をチェックし、その結果をCプログラムと Makefile の変数に設定します。autoconf は PostgreSQL のメインサーバにインストールされています。configure にオプションを追加するには、configure.in を編集し、その後 autoconf を実行して configure ファイルを生成してください。&lt;br /&gt;
&lt;br /&gt;
configure がユーザに実行される場合、OS の様々な機能をチェックし、その結果を config.status と config.cache に記録します。そして、複数の *.in ファイルを変更します。例えば、Makefile.in がありますが、configure はその中の全ての @var@ パラメータを設定して Makefile ファイルを生成します。&lt;br /&gt;
&lt;br /&gt;
あなたがファイルを編集する必要が生じた場合、configure によって生成されるファイルを変更するのは時間の無駄になります。代わりに *.in ファイルを編集し、再度 configure を実行することでファイルを生成してください。トップディレクトリで make distclean を実行すると、configure が生成する全てのファイルが削除されます。ソースコードとして配布されるファイルだけが残ることになります。&lt;br /&gt;
&lt;br /&gt;
=== 新しい環境へ移植するためにはどうしたら良いですか? ===&lt;br /&gt;
&lt;br /&gt;
新しい環境へ移植 (port) するためには多くの箇所を変更する必要があります。まず src/template から始めましょう。移植先の OS に対応する適切なエントリを追加します。また、src/config.guess を使ってそのOSを src/template/.similar に追加します。OS のバージョンを厳密に一致させてはいけません。configure テストは、最初に正確なOSバージョンを探し、もし見つからなければ、バージョン番号を除いて探そうとします。src/configure.in を編集し、新しいOSを追加します。(上記の configure に関する質問も参照) その後、autoconf を実行するか、src/configure にもパッチを当てます。&lt;br /&gt;
&lt;br /&gt;
次に、src/include/port をチェックし、新しいOS用のファイルを適切に記述して追加します。願わくば、src/include/storage/s_lock.h に既に移植先のCPU用のロックコードがあることを祈りましょう。src/makefiles ディレクトリにも環境ごとの Makefile があります。専用のファイルが必要な場合には、backend/port ディレクトリへ追加します。&lt;br /&gt;
&lt;br /&gt;
=== なぜスレッド, RAWデバイス, 非同期I/O 等の &amp;quot;イケてる&amp;quot; 機能を使わないのですか? ===&lt;br /&gt;
&lt;br /&gt;
OS はサポートしたばかりの最新機能は非常に魅力的ですが、そういった誘惑には抵抗しています。&lt;br /&gt;
&lt;br /&gt;
1つ目に、我々は 15 以上の OS をサポートしているため、採用する前に新機能は広く採用されていいなければなりません。2つ目に、イケてる機能の多くは、実際には劇的な改善に繋がりません。3つ目に、新機能の中には悪い側面を持つものがあり、信頼性を犠牲にしたり、追加のコードを要求されることがあります。それゆえ、我々は新機能にすぐに飛びつきはせず、こなれるまで見送ります。, then ask for testing to show that a measurable improvement is possible.&lt;br /&gt;
&lt;br /&gt;
例として、現在バックエンド・コードでスレッドが使われていない理由を挙げます:&lt;br /&gt;
&lt;br /&gt;
* 歴史的に、スレッドはサポートしない環境とバグがありました。&lt;br /&gt;
* 1つのバックエンドでエラーが生じると他のバックエンドにも悪影響が及びます。&lt;br /&gt;
* バックエンドのその他の初期化時間と比較して、スレッドの速度面の利点は微々たるものです。&lt;br /&gt;
* バックエンド・コードが複雑になります。&lt;br /&gt;
* バックエンドプロセスを終了させることにより、OSが完全に素早くリソースを開放でき、メモリーリークとファイルディスクリプタリークを防止することができます。&lt;br /&gt;
* スレッド化されたプログラムをデバッグするのは、プロセスをデバッグするのよりもずっと困難です。それに、コアダンプもスレッドではあまり役に立ちません。&lt;br /&gt;
* 読み込み専用の実行形式マップと共有バッファを使用するのはプロセスをスレッドのように扱うことになり、非常にメモリ効率が良いです。&lt;br /&gt;
* 頻繁にプロセスを生成、消滅させることによりメモリの断片化を防ぐことができます。これは、長い時間動き続けるプロセスでは管理が難しい問題です。&lt;br /&gt;
&lt;br /&gt;
(一つのクエリを複数のコアで処理するために、個々のバックエンドプロセスが複数のスレッドを使うべきかどうかというのはまた別の問題で、ここでは取り扱いません)。&lt;br /&gt;
&lt;br /&gt;
つまり、私たちは新機能を無視しているわけではありません。採用に慎重なだけなのです。TODO リストには、この分野に関する私たちの見解に関する議論がリンクされている場合があります。&lt;br /&gt;
&lt;br /&gt;
=== ブランチはどのように管理されていますか? ===&lt;br /&gt;
&lt;br /&gt;
ブランチの管理とバックポートに関しては、[[Working_with_Git#Using_Back_Branches|Using Back Branches]]と[[Committing with Git]]を参照して下さい。&lt;br /&gt;
&lt;br /&gt;
=== どこでSQL標準のコピーが入手できますか? ===&lt;br /&gt;
[http://www.iso.ch/ ISO] や [http://www.ansi.org ANSI] で購入してください。ISO/ANSI 9075 を探します。ANSI のほうが安価ですが、内容は同じです。&lt;br /&gt;
&lt;br /&gt;
SQL標準の公式コピーは高価なので、開発者の多くはインターネット上にあるドラフト版を利用しています。そのいくつかを挙げます:&lt;br /&gt;
* SQL-92 http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt&lt;br /&gt;
* SQL:1999 http://www.cse.iitb.ac.in/dbms/Data/Papers-Other/SQL1999/ansi-iso-9075-2-1999.pdf&lt;br /&gt;
* SQL:2003 http://www.wiscorp.com/sql_2003_standard.zip&lt;br /&gt;
* SQL:2008 (preliminary) http://www.wiscorp.com/sql200n.zip&lt;br /&gt;
&lt;br /&gt;
PostgreSQL 文書には PostgreSQL に関する情報と [http://www.postgresql.jp/document/current/html/features.html SQL準拠] に関する記述があります。&lt;br /&gt;
&lt;br /&gt;
SQL標準に関するウェブページを挙げます:&lt;br /&gt;
* http://troels.arvin.dk/db/rdbms/links/#standards&lt;br /&gt;
* http://www.wiscorp.com/SQLStandards.html&lt;br /&gt;
* http://www.contrib.andrew.cmu.edu/~shadow/sql.html#syntax (SQL-92)&lt;br /&gt;
* http://dbs.uni-leipzig.de/en/lokal/standards.pdf (paper)&lt;br /&gt;
&lt;br /&gt;
注意として、SQL標準のコピーを読むことは、PostgreSQL の開発者になるためには必ずしも必要ではありません。SQL標準の記述を理解することは難しく、長年の経験も必要です。そして、どのみち PostgreSQL の多くの機能は、SQL標準では規定されていないのです。&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=== 技術的な質問の回答はどこで得られますか? ===&lt;br /&gt;
&lt;br /&gt;
技術的な質問の多くは pgsql-hackers メーリングリストで応えられています。過去のアーカイブは http://archives.postgresql.org/pgsql-hackers/ にあります。&lt;br /&gt;
&lt;br /&gt;
もし過去の議論や回答が見つからない場合には、気軽にメーリングリストに投稿してください。&lt;br /&gt;
&lt;br /&gt;
IRC (irc.freenode.net #postgresql チャネル) でも、新機能の開発に関する質問も含め、主要開発者 (Major contributors) が技術的な質問に答えてくれるでしょう。&lt;br /&gt;
&lt;br /&gt;
=== なぜ CVS を SVN, Git, Monotone, VSS 等に置き換えないのですか? ===&lt;br /&gt;
&lt;br /&gt;
2010年9月、PostgreSQL プロジェクトは CVS を Git に置き換えました。&lt;br /&gt;
&lt;br /&gt;
== 開発プロセス ==&lt;br /&gt;
&lt;br /&gt;
=== 開発項目を選んだ後、何をすればよいですか? ===&lt;br /&gt;
&lt;br /&gt;
あなたがやりたいことの提案書を添えて、email を pgsql-hackers に送ってください (即採用とはいかないことを覚悟してください)。あなた1人だけで考えて開発することはお勧めしません。別の人が同じ TODO 項目に取り組んでいるかもしれませんし、あなたが TODO 項目を誤解しているかもしれないからです。email では、あなたが採用するつもりの内部実装と、ユーザから見える変更 (新しい文法など) の両方を議論してください。複雑なパッチの場合には、実際に開発を始める前にコミュニティのフィードバックを受けることが重要です。そのような手順を踏まなければ、パッチは却下されてしまうでしょう。もしあなたの開発が企業にスポンサーされている場合には、より効率的に行えるよう[http://momjian.us/main/writings/pgsql/company_contributions/ この記事]を読んでください。&lt;br /&gt;
&lt;br /&gt;
レビュー待ちのパッチ・キューは wiki の [[CommitFest]] で管理されています。&lt;br /&gt;
&lt;br /&gt;
=== どのように変更箇所をテストすれば良いですか? ===&lt;br /&gt;
&lt;br /&gt;
==== 基本システムテスト ====&lt;br /&gt;
&lt;br /&gt;
あなたのコードをテストする最も簡単な方法は、最新バージョンのコードでビルドし、コンパイラの警告が出ないことを確認することです。&lt;br /&gt;
&lt;br /&gt;
configure の際に --enable-cassert オプションを指定してビルドするのも良いでしょう。これはソースコード中のアサーションを有効にし、データ破壊やアクセス違反をより多く検知できるようになります。多くの場合、デバッグが容易になります。&lt;br /&gt;
&lt;br /&gt;
その後、psql を使って性能をテストしてください。&lt;br /&gt;
&lt;br /&gt;
==== リグレッションテスト ====&lt;br /&gt;
&lt;br /&gt;
次のステップは、あなたが行った変更に対して既存のリグレッションテスト (回帰テスト) を行うことです。テストするには、ソースツリーのルート・ディレクトリで &amp;quot;make check&amp;quot; を入力してください。失敗した場合には、調査する必要があります。&lt;br /&gt;
&lt;br /&gt;
もしあなたが既存の動作を意図的に変更した場合には、リグレッションテストには失敗するでしょうが、それは実際には間違った動作ではありません。その場合、リグレッションテストを変更するパッチも作成してください。&lt;br /&gt;
&lt;br /&gt;
==== その他の実行時テスト ====&lt;br /&gt;
&lt;br /&gt;
開発には以下のようなツールもよく利用されています。&lt;br /&gt;
* valgrind (http://valgrind.kde.org) : メモリテスト&lt;br /&gt;
* gprof (GNU binutils に含まれます), oprofile (http://oprofile.sourceforge.net/) : プロファイリング&lt;br /&gt;
&lt;br /&gt;
==== ユニットテスト、統計的解析、モデルチェックなどはどうですか? ====&lt;br /&gt;
&lt;br /&gt;
テスト用フレームワークについては既に多くの議論があり、れらのアイデアを採用している開発者もいます。&lt;br /&gt;
&lt;br /&gt;
Makefile はインクルードファイルに対して依存性を持たないように注意してください。make clean の後でも make が動作する必要があります。もし GCC を使っているのであれば、--enable-depend オプションを configure 時に指定することで、コンパイラに依存性を自動計算させることができます。&lt;br /&gt;
&lt;br /&gt;
=== パッチの開発後、次に何をすれば良いですか? ===&lt;br /&gt;
&lt;br /&gt;
パッチを pgsql-hackers@postgresql.org へ投稿してください。あなたのパッチが迅速にレビューされ、採用されるようにするため、「[[Submitting a Patch|パッチの投稿]]」にあるガイドラインに従うよう努めてください。&lt;br /&gt;
&lt;br /&gt;
=== パッチの投稿後には何がありますか? ===&lt;br /&gt;
&lt;br /&gt;
パッチは他の開発者のレビューを受けることになります。採用されることもあれば、追加開発が必要だとして送り返されることもあります。このプロセスの詳しい解説は、『[[Submitting a Patch#Patch review and commit|パッチを投稿するには]]』にあります。&lt;br /&gt;
&lt;br /&gt;
=== どうすればパッチのレビューに参加できますか? ===&lt;br /&gt;
&lt;br /&gt;
あなたが [[CommitFestInProgress|CommitFest]] に登録されているパッチのレビューに参加することは大歓迎です。詳細は、「[[Reviewing a Patch|パッチのレビュー]]」を参考にしてください。&lt;br /&gt;
&lt;br /&gt;
=== 著作権の譲渡に合意する必要がありますか？ ===&lt;br /&gt;
&lt;br /&gt;
いいえ。貢献者は自分の著作権を保持します(ヨーロッパの国々ではどちらにせよそうなります)。貢献者は、PostgreSQL Global Development Groupの成員であると見なされます(PGDGに著作権を与えることはできません。なぜなら、PGDGは法的な実体がないからです)。これは、Linuxカーネルや、他の多くのオープンソースプロジェクトで採用されている方法です。&lt;br /&gt;
&lt;br /&gt;
=== 私の著作権表示を適当な場所に追加しても良いですか？ ===&lt;br /&gt;
&lt;br /&gt;
いいえ、そうしないでください。私達は法律的な事項に関する表示は、短く明快にしておきたいと考えています。また、営利企業のユーザにはこれが問題になることがあると聞いています。&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQLライセンス自身が著作権を完全な形で表示することを要求しているのではありませんか？ ===&lt;br /&gt;
&lt;br /&gt;
その通りです。また、これがPostgreSQL Global Development Groupがすべての著作権を保持している理由です。ちなみに、合衆国の法律では著作権が認められるために著作権表示をする必要はありません。ヨーロッパの国々の法律でも同様です。&lt;br /&gt;
&lt;br /&gt;
== 技術的な質問 ==&lt;br /&gt;
=== どうすればバックエンドのコードからシステムカタログへ効率的なアクセスができますか? ===&lt;br /&gt;
&lt;br /&gt;
最初にあなたが必要とするタプル (行) を見つける必要があります。それには2つの方法があります。1つは SearchSysCache() やその類似関数を呼び、既知のカタログ用インデックスを使ってシステムカタログを取得する方法です。これはシステムカタログにアクセスする方法として推奨されています。なぜなら、初回の呼び出して必要な行がキャッシュにロードされ、それ以降の呼び出しでは元の表にアクセスする必要が無くなるためです。利用可能なキャッシュの一覧は、src/backend/utils/cache/syscache.c に記載されています。src/backend/utils/cache/lsyscache.c は数多くの特定の列を取得するためのキャッシュ検索関数が定義されています。&lt;br /&gt;
&lt;br /&gt;
返却される行はキャッシュで管理されています。そのため、SearchSysCache() から返された行を変更や削除してはいけません。使用後には ReleaseSysCache() で行を解放する必要があります。解放されたキャッシュは必要に応じて破棄されます。もし ReleaseSysCache() を呼ばなかった場合、キャッシュのエントリはトランザクションの終了までロックされます。開発時には良いかもしれませんが、実際にリリースされるコードでは許されません。&lt;br /&gt;
&lt;br /&gt;
もしシステムキャッシュが利用できない場合には、全てのバックエンドで共有されるバッファキャッシュを介して、表から直接データを取得する必要があります。バックエンドは行を自動的にバッファキャッシュに読み込みます。これを行うには、heap_open() で表を開いた後に、その表のスキャンを heap_beginscan() で開始し、heap_getnext() を HeapTupleIsValid() が true を返す限り繰り返し呼び出します。最後に heap_endscan() を呼びます。スキャンの際にはキーも指定できますが、インデックスは使われません。全ての行がキーと比較され、適合する行のみが返却されます。&lt;br /&gt;
&lt;br /&gt;
ブロック番号とオフセット番号が分かっている場合には heap_fetch() で行を取得することもできます。heap_fetch() では、バッファキャッシュ上の行のロック / アンロックは自動的に行われますが、利用後には Buffer ポインタを渡して ReleaseBuffer() を呼び出す必要があります。&lt;br /&gt;
&lt;br /&gt;
行が得られた後、全ての行タイプで共通のデータを取得することができます。t_self と t_oid は、単に HeapTuple 構造体のエントリにアクセスするだけで読み取れます。表ごとに異なる列を取得する場合には、HeapTuple ポインタ を GETSTRUCT() マクロに渡します。返却されるポインタは構造体のポインタにキャストして使います。例えば pg_proc ならば Form_pg_proc ポインタ、pg_type ならば Form_pg_type ポインタです。その後は構造体ポインタを介してフィールドにアクセスできます:&lt;br /&gt;
&lt;br /&gt;
 ((Form_pg_class) GETSTRUCT(tuple))-&amp;gt;relnatts&lt;br /&gt;
&lt;br /&gt;
注意としては、この方法は、固定長かつ非NULLであり、そのフィールドよりも前方の列も固定長かつ非NULLの列でのみ利用可能なことです。さもなければ列の位置は不定になるため、heap_getattr() やその類似関数を使って行から値を取り出す必要があります。&lt;br /&gt;
&lt;br /&gt;
また、有効な行に対して構造体のフィールドを直接書き換えることは避けてください。最も良い方法は、heap_modifytuple() に変更前の行と変更内容を渡すことです。palloc された新しい行が返却され、heap_update() に渡すことができます。削除の場合は、行の t_self を heap_delete() に渡します。t_self は heap_update() でも使うことができます。覚えておく必要があるのは、行は、ReleaseSysCache() の呼び出しで解放されるシステムキャッシュにあるコピーでも、eap_getnext(), heap_endscan(), heap_fetch() の場合は ReleaseBuffer() で解放されるディスクバッファから直接読み取った行でも、構わないということです。もしくは、palloc された行であれば、使用後には pfree() で解放する必要があります。&lt;br /&gt;
&lt;br /&gt;
=== なぜ表, 列, 型, 関数, ビューの名前は Name,  NameData, char * といった異なる型として参照されるのですか? ===&lt;br /&gt;
&lt;br /&gt;
表, 列, 型, 関数, ビューの名前はシステムテーブルに Name 型の列として保持されています。Name は固定長でヌル終端の文字列です。サイズは NAMEDATALEN バイトです (デフォルト64バイト)。&lt;br /&gt;
&lt;br /&gt;
 typedef struct nameData&lt;br /&gt;
 {&lt;br /&gt;
     char        data[NAMEDATALEN];&lt;br /&gt;
 } NameData;&lt;br /&gt;
 typedef NameData *Name;&lt;br /&gt;
&lt;br /&gt;
表, 列, 型, 関数, ビューの名前はユーザクエリを経由して、可変長のヌル終端された文字列としてバックエンドに渡されます。&lt;br /&gt;
&lt;br /&gt;
heap_open() などの多くの関数は、両方の名前型で呼び出れます。Name 型は NULL 終端されているため、char * 型を引数に取る関数に渡しても大丈夫です。ディスク上の名前 (Name) がユーザから渡された名前 (char *) と比較される機会は多く、Name と char * を入れ替えて使える場合も頻繁にあります。&lt;br /&gt;
&lt;br /&gt;
=== なぜデータ構造体を作成するために Node や List を使うのですか? ===&lt;br /&gt;
バックエンドの中で柔軟にデータをやり取りする一貫性のある方法だからです。全ての Node はその型を表す NodeTag フィールド持っています。List は複数の Node を保持する単方向リンクリストです。List 内に要素の順序が意味を持つか否かは用途によります。&lt;br /&gt;
&lt;br /&gt;
以下に List 操作コマンドの一部を示します:&lt;br /&gt;
&lt;br /&gt;
;lfirst(i)&lt;br /&gt;
;lfirst_int(i)&lt;br /&gt;
;lfirst_oid(i)&lt;br /&gt;
:データを返します。(それぞれセル i を ポインタ, 整数, OID として)&lt;br /&gt;
&lt;br /&gt;
;lnext(i)&lt;br /&gt;
:i の次のセルを返します。&lt;br /&gt;
&lt;br /&gt;
;foreach(i, list)&lt;br /&gt;
:list をループし、それぞれのセルを i に格納します。&lt;br /&gt;
&lt;br /&gt;
重要なのは、i が ListCell * 型であることです。セルに格納されたデータではありません。lfirst 関数のいずれかを使ってセルのデータを取得する必要があります。&lt;br /&gt;
&lt;br /&gt;
以下はループ処理を行う典型的なコードです。List 型は Var * 型のデータを格納しており、要素それぞれを処理したい場合です:&lt;br /&gt;
&lt;br /&gt;
 List        *list;&lt;br /&gt;
 ListCell    *i;&lt;br /&gt;
 ...&lt;br /&gt;
 foreach(i, list)&lt;br /&gt;
 {&lt;br /&gt;
     Var *var = (Var *) lfirst(i);&lt;br /&gt;
     ...&lt;br /&gt;
     /* ここで var を使う */&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
;lcons(node, list)&lt;br /&gt;
:node を list の先頭に追加します。list が NIL ならばリストを新規作成します。&lt;br /&gt;
&lt;br /&gt;
;lappend(list, node)&lt;br /&gt;
:node を list の末尾に追加します。&lt;br /&gt;
&lt;br /&gt;
;list_concat(list1, list2)&lt;br /&gt;
:list1 の末尾に list2 を追加します。&lt;br /&gt;
&lt;br /&gt;
;list_length(list)&lt;br /&gt;
:list の長さを返します。&lt;br /&gt;
&lt;br /&gt;
;list_nth(list, i)&lt;br /&gt;
:list の i 番目の要素を返します。番号は 0 から数えます。&lt;br /&gt;
&lt;br /&gt;
;lcons_int, ...&lt;br /&gt;
:整数版の lcons_int, lappend_int や、OID 版の lcons_oid, lappend_oid もあります。&lt;br /&gt;
&lt;br /&gt;
gdb を使って、ノードを簡単に表示することができます。最初に gdb の表示切り詰めを無効化してください。&lt;br /&gt;
&lt;br /&gt;
 (gdb) set print elements 0&lt;br /&gt;
&lt;br /&gt;
List, Node, 構造体の内容を表示するには、gdb 形式で値を表示する代わりに次の2つのコマンドを使うと、詳しい情報を得ることができます。List の中の Node は展開され、Node はその詳細が出力されます。1番目の関数は短い形式、2番目の関数は長い形式で表示します:&lt;br /&gt;
&lt;br /&gt;
 (gdb) call print(any_pointer)&lt;br /&gt;
 (gdb) call pprint(any_pointer)&lt;br /&gt;
&lt;br /&gt;
出力はサーバログに行われますが、postmaster を使わずバックエンドを直接起動していた場合には画面に表示されます。&lt;br /&gt;
&lt;br /&gt;
=== 構造体にフィールドを追加する際、他に何をする必要がありますか? ===&lt;br /&gt;
&lt;br /&gt;
パーサ、リライタ、オプティマイザ、エグゼキュータ (parser, rewriter, optimizer, executor) に渡す構造体の場合には、処理の追加が必要です。構造体の多くは src/backend/nodes で定義されるルーチンをサポートしており、構造体の作成、コピー、読み取り、書き出しを行うことができます。特に、ほとんどのノード型は copyfuncs.c と equalfuncs.c への対応が必須であり、一部は outfuncs.c や readfuncs.c もサポートする必要があります。新しいフィールドをこれらのファイルでもサポートするよう変更してください。そのほかにも追加したフィールドに対応するコードが無いかを探してください。これには既存のフィールドがどのように扱われているかを参考にするのが良いでしょう。mkid が役に立ちます。([[#What_tools_are_available_for_developers.3F|利用可能なツール]] 参照)&lt;br /&gt;
&lt;br /&gt;
=== なぜメモリ確保に palloc() と pfree() を使うのですか? ===&lt;br /&gt;
&lt;br /&gt;
palloc() と pfree() は malloc() と free() の代わりに使われます。その理由は、クエリの完了時に確保した全てのメモリを容易に解放するためです。たとえどこでメモリを確保したのかが分らなくなっても、全てのメモリを解放することが可能になります。クエリ単位ではないメモリ領域もありますが、バックエンドが定義解放します。&lt;br /&gt;
&lt;br /&gt;
=== ereport() とは何ですか? ===&lt;br /&gt;
&lt;br /&gt;
ereport() はフロントエンドにメッセージを送信します。また、実行中のクエリを終了することもできます。使い方の詳細は「[http://www.postgresql.jp/document/current/html/error-message-reporting.html サーバ内部からのエラーの報告]」を参照してください。&lt;br /&gt;
&lt;br /&gt;
=== CommandCounterIncrement() とは何ですか? ===&lt;br /&gt;
&lt;br /&gt;
通常は、コマンド文は自身が変更した行を見ることはできません。これは「UPDATE foo SET x = x + 1」が正常に動作するために必要です。&lt;br /&gt;
&lt;br /&gt;
しかしながら、トランザクションの中で、そのトランザクションが直前に行った変更結果が必要になる場合もあります。これはコマンド・カウンタ (Command Counter) を利用することで実現できます。カウンタを増加させることでトランザクションを断片に分割し、それぞれの断片はそれ以前に実行した断片の結果を読み取ることができるようになります。CommandCounterIncrement() はコマンド・カウンタを増加させ、トランザクションに新しい断片を追加する処理です。&lt;br /&gt;
&lt;br /&gt;
=== 問い合わせ処理に変更を加える必要が出てきました。パーサ関係のファイルについて手短に説明して下さい。 ===&lt;br /&gt;
&lt;br /&gt;
パーサ関係のファイルは 「src/backend/parser」ディレクトリにあります。&lt;br /&gt;
&lt;br /&gt;
scan.lは、字句解析器(lexer)を定義します。字句解析機は、SQL文を含む文字列を一連のトークンに分解します。トークンは通常は一個の単語(空白を含まず、空白によって区切られているもの)ですが、単一引用符、二重引用符で囲まれている場合は、文字列全体になり得ます。字句解析機は基本的に正規表現を使って定義されており、様々なトークンのタイプが記述できます。&lt;br /&gt;
&lt;br /&gt;
gram.yは、字句解析器が生成したトークンを基本構成要素として使ってSQL文の文法(構文構造)を定義します。文法は、BNF記法で定義されています。BNFは正規表現に似ていますが、文字ではなく、トークン上で動きます。また、パターン(ルール、あるいはBNFにおける生成規則)には名前が付けられており、再帰的に定義できます。よって、自分自身をパターンとして呼び出すことができます。&lt;br /&gt;
&lt;br /&gt;
実際の字句解析器は、flexというツールを使ってscan.lから生成されます。flexのマニュアルは http://flex.sourceforge.net/manual/ で参照できます。&lt;br /&gt;
&lt;br /&gt;
実際のパーサは、bisonというツールを使ってgram.yから生成されます。bisonのマニュアルは http://www.gnu.org/s/bison/ で参照できます。&lt;br /&gt;
&lt;br /&gt;
一つ注意しておくと、もし以前にflexやbisonを使ったことがない場合、学習曲線はかなり急なものになるでしょう。&lt;br /&gt;
&lt;br /&gt;
=== どのようなデバッグ機能を利用できますか? ===&lt;br /&gt;
&lt;br /&gt;
まず、もしあなたがC言語で開発しているならば、&#039;&#039;&#039;必ず&#039;&#039;&#039; --enable-cassert と --enable-debug オプションを有効にして configure を行った状態で動作することを確認してください。アサーションを有効にすると多くの正常性確認処理が有効になります。デバッグシンボルはデバッガ (例えば gdb) を使って期待通りに動作しないコードを追うのに役立ちます。&lt;br /&gt;
&lt;br /&gt;
PostgreSQL サーバには -d オプションがあり、これは詳細メッセージをログに記録します (elog または ereport で DEBUGn の情報を出力します)。-d オプションはデバッグレベルの数値を1つ引数に取ります。高いデバッグレベルを指定するとログファイルのサイズが大きくなるので注意してください。&lt;br /&gt;
&lt;br /&gt;
postmaster が実行中ならば、ウィンドウ (コンソール) を1つ開いて psql を開始します。その後、その psql が接続している postgres プロセスの PID を、SELECT pg_backend_pid() を使って取得します。デバッガをその postgres の PID にアタッチします。デバッガからブレークポイントを設定し、その後 psql セッションからクエリを発行します。もしエラーやログメッセージを出力している場所を探しているのであれば、errfinish にブレークポイントを設定するのが良いでしょう。もしセッションの開始処理をデバッグしたいのであれば、環境変数 PGOPTIONS=&amp;quot;-W n&amp;quot; を指定してから psql を開始してください。開始処理に n 秒の遅延を行うため、その間に postgres プロセスにデバッガをアタッチすることができます。ブレークポイントを適切に設定した後に開始処理を継続することになります。&lt;br /&gt;
&lt;br /&gt;
もし postmaster が実行されていないならば、postgres バックエンドをコマンドラインから開始し、SQL 文を直接入力することもできます。しかしながら、これはあまり良い方法ではありません。psql ほど使いやすい環境ではなく (例えばコマンド履歴がありません)、並行処理をテストすることもできないためです。initdb が正常に動作しなくなってしまった場合には役立つかもしれませんが、それ以外の状況ではお勧めしません。&lt;br /&gt;
&lt;br /&gt;
どの関数の実行に時間がかかっているかを知るためにプロファイリングを有効にしてコンパイルすることもできます。configure の際に --enable-profiling を指定してください (この時、性能を測定したいのであれば --enable-casserts は使わないでください。アサーションのチェックは無視できるほど軽量ではないためです)。&lt;br /&gt;
サーバプロセスからのプロファイル・ファイルは pgsql/data ディレクトリに出力されます。psql 等のクライアントからのプロファイル・ファイルは、クライアントのカレントディレクトリに置かれます。&lt;br /&gt;
&lt;br /&gt;
[[Category:FAQ]]&lt;br /&gt;
[[Category:Japanese]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=20120924updaterelease/ja&amp;diff=18511</id>
		<title>20120924updaterelease/ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=20120924updaterelease/ja&amp;diff=18511"/>
		<updated>2012-11-02T01:05:32Z</updated>

		<summary type="html">&lt;p&gt;Hanada: 原文の変更に追従（The 9.2 upgrade docs say to also set vacuum_freeze_table_age to 0）&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
&lt;br /&gt;
= 2012-09-24 更新リリースのデータ破損問題に関する詳細 =&lt;br /&gt;
&lt;br /&gt;
== 問題の説明 ==&lt;br /&gt;
&lt;br /&gt;
PostgreSQLのバージョン9.1と9.2には、ダーティブロックのメモリからのフラッシュ(または&amp;quot;[http://www.postgresql.jp/document/current/html/wal-configuration.html チェックポイント]&amp;quot;)に関して性能改善と新機能の追加(主に[[What%27s_new_in_PostgreSQL_9.1#Unlogged_Tables|ログを取らないテーブル]])の副作用として偶然混入したバグがあります。このバグは、以下の理由によりデータベースがシャットダウンまたは再起動した場合にある種のデータがディスクに書き込まれないことの原因となります。&lt;br /&gt;
&lt;br /&gt;
* PostgreSQLのクラッシュ&lt;br /&gt;
* サーバクラッシュまたは電源喪失&lt;br /&gt;
* &amp;quot;immediate&amp;quot; シャットダウン (pg_ctl -m immediate)&lt;br /&gt;
* postmasterサービスに対する&amp;quot;kill -9&amp;quot; または Out-Of-Memory-Kill&lt;br /&gt;
* データベースがスタンバイからマスターに昇格した&lt;br /&gt;
&lt;br /&gt;
これらの状況下では、データベースはリカバリ可能なデータ破損に陥る可能性があります。この破損の特徴は、一見正しいが実際には間違っている問い合わせ結果を返す場合があることです。このため、このデータ破損の影響を受けたかもしれないユーザはただちに復旧手順を実施することが重要です。&lt;br /&gt;
&lt;br /&gt;
第一に、BTREEとGINインデックスの破損の可能性は低いです。正常にシャットダウンすればこの問題の拡散を防ぐことが出来ます。もしデータ破損が起きていた場合、おそらくインデックスが使用された時にエラーメッセージの形で現れるでしょう。&lt;br /&gt;
&lt;br /&gt;
次に、リレーションの可視性マップ(訳注:visibility map)の破損が起こる有意な可能性(スタンバイではほぼ100%)があります。&lt;br /&gt;
&lt;br /&gt;
PostgreSQL Global Development Groupはこの問題による不便についてお詫びします。&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL 9.1 ユーザのための手順 ==&lt;br /&gt;
&lt;br /&gt;
もし9.1を利用しており、かつ過去数ヶ月の間にあなたのデータベースが予期せぬシャットダウンやフェイルオーバーをしていてデータベース破損の影響を受けている疑いがある場合は、以下の手順を実施してください:&lt;br /&gt;
&lt;br /&gt;
# 新しい 9.1.6 のパッケージ群をダウンロードする&lt;br /&gt;
# 以下のいずれかの手段でPostgreSQLをクリーンシャットダウンする&lt;br /&gt;
#* 起動スクリプトまたはサービスマネージャ&lt;br /&gt;
#* pg_ctl -m start stop&lt;br /&gt;
#* pg_ctl -m fast stop&lt;br /&gt;
# 9.1.6をインストールする&lt;br /&gt;
# 9.2 アップグレードのドキュメントに従い、データベースサーバを再起動する前のこの時点でpostgresql.confの[http://www.postgresql.jp/document/current/html/runtime-config-client.html#GUC-VACUUM-FREEZE-TABLE-AGE vacuum_freeze_table_age]を0に設定して、この手順が完了してからそのエントリを削除するのがよいでしょう; vacuum_cost_delayをグローバルに設定できるのはこの時点です。&lt;br /&gt;
# データベースシステムを再起動する&lt;br /&gt;
# BTreeおよびGINのインデックスを順次再構築する(下記参照)&lt;br /&gt;
# データベース全体に対する手動vacuumを都合のよい負荷の低い時間帯にスケジュールする(下記参照)&lt;br /&gt;
&lt;br /&gt;
もしあなたがPostgreSQL 9.2へのアップグレードを計画している場合は、最初にデータベース全体に対するVACUUMを実行することが重要です。&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL 9.2 ユーザのための手順 ==&lt;br /&gt;
&lt;br /&gt;
もし9.2.0を利用しており、かつ過去数ヶ月の間にあなたのデータベースが予期せぬシャットダウンやフェイルオーバーをしていてデータベース破損の影響を受けている疑いがある場合は、以下の手順を実施してください:&lt;br /&gt;
&lt;br /&gt;
# 新しい 9.2.1 のパッケージ群をダウンロードする&lt;br /&gt;
# 以下のいずれかの手段でPostgreSQLをクリーンシャットダウンする&lt;br /&gt;
#* 起動スクリプトまたはサービスマネージャ&lt;br /&gt;
#* pg_ctl -m start stop&lt;br /&gt;
#* pg_ctl -m fast stop&lt;br /&gt;
# 9.2.1をインストールする&lt;br /&gt;
# 9.2 アップグレードのドキュメントに従い、データベースサーバを再起動する前のこの時点でpostgresql.confの[http://www.postgresql.jp/document/current/html/runtime-config-client.html#GUC-VACUUM-FREEZE-TABLE-AGE vacuum_freeze_table_age]を0に設定して、この手順が完了してからそのエントリを削除するのがよいでしょう; vacuum_cost_delayをグローバルに設定できるのはこの時点です。&lt;br /&gt;
# データベースシステムを再起動する&lt;br /&gt;
# すぐにあなたのデータベース内の全てのテーブルをVACUUMする。&lt;br /&gt;
# BTreeおよびGINのインデックスを順次再構築する(下記参照)&lt;br /&gt;
&lt;br /&gt;
== 全てのテーブルをVACUUMする方法 ==&lt;br /&gt;
&lt;br /&gt;
可視性マップの破損を修復するために、ユーザはvacuumを実行してマップ全体をリセットするために全データベースブロックのスキャンを強制しなければなりません。これは結果的にデータベース全体のスキャンを意味するので、相当量のIOを発生させ、大きなデータベースではかなり時間がかかるでしょう。並列で実行されるデータベースの影響を改善する方法、vacuumを拡散させるためにcost delayを使用することです:&lt;br /&gt;
&lt;br /&gt;
    SET [http://www.postgresql.jp/document/current/html/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-VACUUM-COST vacuum_cost_delay] = 50;&lt;br /&gt;
&lt;br /&gt;
=== 対話的VACUUM ===&lt;br /&gt;
&lt;br /&gt;
データベースそれぞれについて、以下の手順を実施する必要があります:&lt;br /&gt;
&lt;br /&gt;
# psqlにPostgresのスーパーユーザでログインする&lt;br /&gt;
# もしそうするならば、vacuum_cost_delayを設定する&lt;br /&gt;
# &amp;quot;[http://www.postgresql.jp/document/current/html/sql-vacuum.html VACUUM ( FREEZE, VERBOSE, ANALYZE );]&amp;quot;を実行する(ANALYZEは省略可能)&lt;br /&gt;
&lt;br /&gt;
このコマンドはデータベース全体のvacuumの進捗を確認できるように大量の出力を生成します。&lt;br /&gt;
&lt;br /&gt;
vacuumの終わったものと終わっていないものを追跡するために、あなたは全部を順番に実行する代わりに一度に一つずつテーブルをVACUUMすることもできます。&lt;br /&gt;
&lt;br /&gt;
=== vacuumdb ===&lt;br /&gt;
&lt;br /&gt;
もしvacuumするデータベースが複数ある場合は、代わりに[http://www.postgresql.jp/document/current/html/app-vacuumdb.html vacuumdb]を使うほうが便利だと判断するかもしれません。この場合はこのように実行します:&lt;br /&gt;
&lt;br /&gt;
# もしそうするならば、postgresql.confでvacuum_cost_delayを設定する(そしてデータベースをリロードする)&lt;br /&gt;
# postgresスーパーユーザで&amp;quot;vacuumdb -F -v -z -a&amp;quot;を実行する&lt;br /&gt;
&lt;br /&gt;
データベースサーバに接続するために追加のパラメータをvacuumdbに指定する必要があるかもしれない点に注意して下さい。-z(analyze)や-v(verbose)オプションは省略可能です。&lt;br /&gt;
&lt;br /&gt;
== BTree/GINインデックスの再構築 ==&lt;br /&gt;
&lt;br /&gt;
更新リリースにより修正された問題によって破損したインデックスはアクセスされるとエラーメッセージを表示するので、容易に識別できそうです。しかし、いくつかのインデックスは(あまりなさそうですが)エラーなしで誤った応答を返すように破損しているかもしれません。&lt;br /&gt;
&lt;br /&gt;
上で推奨されているVACUUM FREEZEは何種類かのインデックス破損を修復します。しかし、データの完全性に関する強い懸念を持つユーザや、サーバで過去に複数回のクラッシュやフェイルオーバーが発生していて特にリスクを感じているユーザは、考えうるあらゆる破損を除去するためにインデックスの再構築を追加手順として実施すべきです。&lt;br /&gt;
&lt;br /&gt;
=== 各インデックスの再構築 ===&lt;br /&gt;
&lt;br /&gt;
予防であってもインデックス破損を発見したためであっても、一度に一つずつインデックスを再構築できます。最も単純な方法は[http://www.postgresql.jp/document/current/html/sql-reindex.html REINDEX]を使うことです。&lt;br /&gt;
&lt;br /&gt;
    REINDEX TABLE &amp;lt;tablename&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
または、単一インデックスに対しては:&lt;br /&gt;
&lt;br /&gt;
    REINDEX INDEX &amp;lt;indexname&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
利用可能なRAMの1/8(最大で2GB)までmaintainance_work_memを増やして、REINDEXで使えるRAMを増やすこともできます。REINDEXはテーブル全体の書き込みロックを取得し、テーブルのサイズに依存しますが実行にかなりの時間がかかることがあります。同時に存在するデータベース負荷の下でインデックスを再構築するために、CREATE INDEX CONCURRENTLYが利用できます:&lt;br /&gt;
&lt;br /&gt;
    CREATE INDEX CONCURRENTLY &amp;lt;indexname&amp;gt;_tmp &amp;lt;index_definition&amp;gt;;&lt;br /&gt;
    BEGIN;&lt;br /&gt;
    DROP INDEX &amp;lt;indexname&amp;gt;;&lt;br /&gt;
    ALTER INDEX &amp;lt;indexname&amp;gt;_tmp RENAME TO &amp;lt;indexname&amp;gt;;&lt;br /&gt;
    END;&lt;br /&gt;
&lt;br /&gt;
これは最後の削除とリネームの段階でのみテーブルをロックします。ただし、より複雑です。&lt;br /&gt;
&lt;br /&gt;
どちらのアプローチも、大きなテーブルに実行している間は相当量のIOを発生させます。&lt;br /&gt;
&lt;br /&gt;
=== BtreeおよびGINインデックスの一覧の取得 ===&lt;br /&gt;
&lt;br /&gt;
インデックス再構築のアプローチに関わらず、データベース内のBTreeおよびGINインデックスの一覧を取得できます。BTreeは最も一般的なインデックス種別であるため、あなたのデータベース内のほとんどのインデックスがこれに含まれるでしょう。GiSTインデックスはとても大きくなりうることを考慮して、それらを再構築の対象から外すことができます。&lt;br /&gt;
&lt;br /&gt;
このクエリを使ってください:&lt;br /&gt;
&lt;br /&gt;
    SELECT tablename, indexname, indexdef&lt;br /&gt;
    FROM pg_indexes&lt;br /&gt;
    WHERE ( indexdef ILIKE &#039;%USING btree%&#039;&lt;br /&gt;
      OR indexdef ILIKE &#039;%USING GIN%&#039; )&lt;br /&gt;
      AND schemaname &amp;lt;&amp;gt; &#039;pg_catalog&#039;&lt;br /&gt;
    ORDER BY tablename, indexname;&lt;br /&gt;
&lt;br /&gt;
=== 全インデックスの再構築 ===&lt;br /&gt;
&lt;br /&gt;
要求されるダウンタイムを許容でき、全ての破損の予防を絶対的に確信したいのであれば、[http://www.postgresql.jp/document/current/html/app-reindexdb.html reindexdb ユーティリティ]を使ってデータベース内の全てのインデックスを再構築することができます。このコマンドは、破損の危険性がないにも関わらずGiSTインデックスも再構築してしまう点に注意してください。&lt;br /&gt;
&lt;br /&gt;
一つのデータベースをインデックス再構築するにはpostgresスーパーユーザで以下を実行してください:&lt;br /&gt;
&lt;br /&gt;
    reindexdb &amp;lt;databasename&amp;gt;&lt;br /&gt;
&lt;br /&gt;
または、全てのデータベースをインデックス再構築するには:&lt;br /&gt;
&lt;br /&gt;
    reindexdb -a&lt;br /&gt;
&lt;br /&gt;
データベースサーバに接続するために、reindexdbの追加のオプションが必要になるかもしれません。reindexdbは全てのテーブルのロックを一度に一つずつ取得するので、ダウンタイム中に行うのが最適です。&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Running_%26_Installing_PostgreSQL_On_Native_Windows/ja&amp;diff=18316</id>
		<title>Running &amp; Installing PostgreSQL On Native Windows/ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Running_%26_Installing_PostgreSQL_On_Native_Windows/ja&amp;diff=18316"/>
		<updated>2012-09-28T07:58:45Z</updated>

		<summary type="html">&lt;p&gt;Hanada: 原文の変更に追従＋typo修正&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
== サポートされるプラットフォーム ==&lt;br /&gt;
&lt;br /&gt;
=== どのバージョンのWindowsでPostgreSQLは動作しますか？===&lt;br /&gt;
&lt;br /&gt;
少なくともバージョン9.0の時点では、PostgreSQLはWindows XP以上でサポートされます。32ビットおよび64ビットシステムで動作します。&lt;br /&gt;
&lt;br /&gt;
より新しいメジャーバージョンのサーバがリリースされた後にリリースされた新しいバージョンのオペレーティングシステムについては、そのバージョンのサーバはテストされません。たとえばWindows 7はPostgreSQL 8.4の後にリリースされましたので、PostgreSQL 8.3ではWindows 7をサポートしません。同様に近い将来のRHEL 6がリリースされた時、PostgreSQL 9.0.xのみがそこでサポートされます。&lt;br /&gt;
私たちは少なくとも、Windowsの新しいバージョンを、そのリリースの後のPostgreSQLのメジャーバージョンでサポートすることを目標としています。&lt;br /&gt;
&lt;br /&gt;
ワンクリックインストーラでサポートされるプラットフォームについては、メインダウンロードページではなく、インストーラのダウンロードページ[http://www.postgresql.org/download/windows download page for windows]を参照してください。&lt;br /&gt;
&lt;br /&gt;
Windows以外のプラットフォームについては、[[FAQ|main FAQ]] and the [http://www.postgresql.org/download/ main download page]を参照してください。&lt;br /&gt;
&lt;br /&gt;
=== どのWindowsプラットフォームはサポート*されない*のでしょうか？ ===&lt;br /&gt;
&lt;br /&gt;
PostgreSQLインストーラは以下ではテストまたはサポート&amp;lt;i&amp;gt;されません&amp;lt;/i&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
* Windows XP Embedded&lt;br /&gt;
* Windows 2000&lt;br /&gt;
* Windows NT 4&lt;br /&gt;
* Windows NT 3.5.x&lt;br /&gt;
* Windows 95/98/ME/3.x&lt;br /&gt;
* Windows CE&lt;br /&gt;
* Windows Mobile&lt;br /&gt;
&lt;br /&gt;
これらのプラットフォームはサポートされません。こうしたプラットフォームでの援助をメーリングリストで頼まないでください。&lt;br /&gt;
&lt;br /&gt;
組込みWindowsに関しては多少の情報があります。問題解消のために[[Troubleshooting Installation#Installation fails on windows embedded|installation on embedded versions of windows]]を参照してください。&lt;br /&gt;
&lt;br /&gt;
=== NT4もサポートされていると聞いたのだけれども本当ですか？ ===&lt;br /&gt;
公式にはサポートされておらず、また、以下のような若干の問題がありますが、PostgreSQLはWindows NT4でも動作する可能性があります。。&lt;br /&gt;
* インストーラは正しく動作しません。そのため、バイナリの.zipリリース、または、コードをコンパイルして、手作業でインストールしなければなりません。&lt;br /&gt;
* PostgreSQLはテーブル空間を実装するためにNTFSファイルシステムの&amp;quot;リパースポイント&amp;quot;機能を使用しています。リパースポイントはNT4では使用できませんので、テーブル空間を使用することはできません。&lt;br /&gt;
* 標準ではWindows NT4には&#039;runas.exe&#039;コマンドがありません。このため、管理者アカウントからPostgreSQLを起動することが難しくなっています。&lt;br /&gt;
また、NT4での動作確認はほとんど行われていないことにも注意してください。&lt;br /&gt;
* Windows NT 4またはWindows 2000では試験は行われません。これらのプラットフォームではより新しいバージョンは動作しない可能性があります。&lt;br /&gt;
&lt;br /&gt;
これらの古いプラットフォームについての問い合わせをメーリングリストで行わないでください。&lt;br /&gt;
けれども、[http://www.postgresql.org/support/professional_support professional support]の一部の企業が支援してくれるかもしれません。&lt;br /&gt;
&lt;br /&gt;
=== Winsows95や98、MEはどうなっていますか？ ===&lt;br /&gt;
&lt;br /&gt;
PostgreSQLはこれらのプラットフォームでは使用できない機能を必要としていますので、これらのプラットフォームでは動作しません。&lt;br /&gt;
こうしたプラットフォームでPostgreSQLを実行する場合は[http://www.postgresql.org/files/documentation/faqs/text/FAQ_CYGWIN Cygwin]の方を確認してください。こちらは9xプラットフォームをサポートしています。&lt;br /&gt;
&lt;br /&gt;
=== Windows用に64ビットで構築されたPostgreSQLはありますか？ ===&lt;br /&gt;
&lt;br /&gt;
[[64bit Windows port]]は[[PostgreSQL 9.0]]でリリースされました。&lt;br /&gt;
&lt;br /&gt;
一般的に、32ビットで構築されたこれまでのバージョンのPostgreSQLは、64ビット版のWindowsでもうまく動作します。これらはおよそ１GB以上のshared_buffersを実質的に使用することができませんが、Windowsカーネルがディスク読み取りをキャッシュするためにメモリを使用しますので、4GB以上のメモリがあることの利点はまだあります。&lt;br /&gt;
&lt;br /&gt;
=== 64ビット版のODBCドライバについては？ ===&lt;br /&gt;
&lt;br /&gt;
執筆時点では、[http://psqlodbc.projects.postgresql.org/ psqlODBC]のソースコード版には64ビットサポートが存在しますが、64ビットODBCドライバの公式バイナリリリースはありません。詳しくはpsqlODBCのwebサイトを確認してください。&lt;br /&gt;
&lt;br /&gt;
== インストール ==&lt;br /&gt;
&lt;br /&gt;
=== WindowsでPostgreSQLをインストールするためには何が必要ですか？ ===&lt;br /&gt;
&lt;br /&gt;
Windowsにおける各種ダウンロード方法、インストール方法については[http://www.postgresql.org/download/windows the PostgreSQL for Windows download page]を参照してください。&lt;br /&gt;
&lt;br /&gt;
WindowsにPostgreSQLをインストールする一番簡単な方法は、EnterPriseDBにより保守されているOne Click installer package]を使用することです。これは上でリンクされたページから入手することができます。&lt;br /&gt;
これは、コンパイル済みのバージョンのPostgreSQLをpgAdmin(管理・保守用のグラフィカルインタフェース)と一緒にインストールする他、特別な機能を追加する&#039;contrib&#039;モジュールや手続き言語を選択してインストールします。&lt;br /&gt;
必要になるかもしれないODBCやJDBCドライバなどの追加コンポーネントのダウンロードとインストールを補助する、StackBuilderと呼ばれるプログラムがインストールされます。&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQLをソースコードからコンパイルするためには何が必要ですか？ ===&lt;br /&gt;
&lt;br /&gt;
WindowsにおけるPostgreSQLのコンパイル方法、サポートされるコンパイラやツールについては[http://www.postgresql.org/docs/current/static/install-windows.html 文書]を参照してください。&lt;br /&gt;
&lt;br /&gt;
=== なぜPostgreSQLを実行するために管理者以外のアカウントが必要なのですか？ ===&lt;br /&gt;
&lt;br /&gt;
ハッカーがパッケージ内のソフトウェアの不具合を使用してコンピュータへの取っ掛かりを持った場合、ハッカーはそのサービスを稼動しているユーザアカウントの権限を持つことになります。&lt;br /&gt;
PostgreSQLではこうした不具合はまだありませんが、ハッカーがPostgreSQLの不具合を見つけ、それを悪用してシステムをハックしたとしても、損害が最小となるように管理者以外のサービスアカウントの使用を強制しています。&lt;br /&gt;
&lt;br /&gt;
これはUnixの世界ではかなり前から常識的な方法でした。&lt;br /&gt;
Windowsの世界でも、Microsoftやほかのベンダーがそのシステムのセキュリティを高めるにつれて、標準的な方法になりつつあります。&lt;br /&gt;
&lt;br /&gt;
PostgreSQL リリース8.2では管理者アカウントで実行することが可能であるという点に注意してください。&lt;br /&gt;
PostgreSQL 8.2以降では、取り消せない方法で起動時に管理者権限を放棄することができるので、PostgreSQLが乗っ取られるという極めて起こりそうにない出来事があっても、その後のシステムの安全性を保証します。&lt;br /&gt;
&lt;br /&gt;
=== FATパーティションにPostgreSQLをインストールできますか？ ===&lt;br /&gt;
&lt;br /&gt;
FAT32は何らかのデータベースを稼働させるためのファイルシステムとしてはひどいものですので、FAT32ファイルシステム上のPostgreSQLはサポートも試験もされていません。&lt;br /&gt;
&lt;br /&gt;
PostgreSQLの最優先すべきことはデータの整合性を保つことです。FATおよびFAT32ファイルシステムは単純で、必要とする信頼性やクラッシュに対する安全性を提供していません。さらにFATではセキュリティ機能が提供されませんので、データファイルそのものが承認なしに変更されてしまうのを防ぐことはできません。最後に、PostgreSQLは&#039;リパースポイント&#039;という機能を使用してテーブル空間を実装しています。&lt;br /&gt;
この機能はFATパーティションでは使用できません。&lt;br /&gt;
&lt;br /&gt;
NTFSファイルシステムはジャーナリングファイルシステムであり、より優れた信頼性とクラッシュ時の復旧機能を持っています。更に、判りやすいアクセス制御システムを持ち、PostgreSQLで使用するリパースポイントも提供します。&lt;br /&gt;
&lt;br /&gt;
こうした理由により、PostgreSQLインストーラパッケージでは、NTFSパーティション以外にデータベースクラスタを初期化しません。&lt;br /&gt;
サーバとユーティリティはパーティションの種類は関係なくインストールすることができます。&lt;br /&gt;
&lt;br /&gt;
しかし、FATパーティションしか選べない、まれな場合もあることを把握しています。こうした場合、データベースクラスタを初期化させずに、通常通りにPostgreSQLをインストールすることもできます。インストールが完了した時に、手作業でFATパーティションに対して&#039;initdb.exe&#039;プログラムを実行してください。&lt;br /&gt;
しかしセキュリティと信頼性については妥協することになりますし、また、テーブル空間の作成は失敗します。&lt;br /&gt;
&amp;lt;b&amp;gt;運用段階ではFAT32でPostgreSQLを使用しないでください&amp;lt;/b&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
人々がこの件について質問する最もよくある理由は、彼らがUSBキーや外部ハードドライブを持っていて、PostgreSQLデータベースをそこに置きたいからです。そのようなことはしないでください。USBキーや外部ハードドライブをNTFSでフォーマットすることができますので、もしデータベースをそこで実行したいのであればそう&amp;lt;i&amp;gt;すべき&amp;lt;/i&amp;gt;です。FATはクラッシュセーフでなく、Windowsで「安全に取り外す」を用いずにハードドライブを取り外すことはハードドライブに関する限りクラッシュとしてカウントされます。かなりの確率で破損が起こるでしょう。PostgreSQLと共に使用してあなたが気にかけるなんらかのデータを保存するのであれば、リムーバブルドライブをNTFSで再フォーマットすることは&amp;lt;i&amp;gt;大変重要&amp;lt;/i&amp;gt;です。&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQLが必要とするファイルシステムの権限は何ですか？ ===&lt;br /&gt;
PostgreSQLサービスアカウントには、サービスディレクトリまでの階層のディレクトリ全てに対する&#039;&#039;読み取り&#039;&#039;権限が必要です。&lt;br /&gt;
データディレクトリについては&#039;&#039;書き込み&#039;&#039;権限&#039;&#039;のみ&#039;&#039;が必要です。&lt;br /&gt;
特に、バイナリファイルを格納するディレクトリに対しては、&#039;&#039;読み取り&#039;&#039;以外を許可しては&#039;&#039;なりません&#039;&#039;。&lt;br /&gt;
（インストール先のディレクトリ以下にある全てのディレクトリについてはインストーラが設定しますので、何も変更していなければ問題にならないはずです。）&lt;br /&gt;
&lt;br /&gt;
また、PostgreSQLにはkernel32.dllやuser32.dllなどのシステムDLLへの&#039;&#039;読み取り&#039;&#039;権限が必要です。&lt;br /&gt;
これは通常デフォルトで許可されています。&lt;br /&gt;
CMD.EXEバイナリも同様ですが、こちらはロックされているかもしれませんのでその場合は解除しなければなりません。&lt;br /&gt;
&lt;br /&gt;
マルチユーザシステムでPostgreSQLを稼動させる場合、PostgreSQLディレクトリから管理者以外の全てのユーザの権限を取り除かなければなりません。&lt;br /&gt;
PostgreSQLのファイルに対して権限が必要なユーザは&#039;&#039;決して&#039;&#039;存在しません。&lt;br /&gt;
全ての通信はlibpq接続を介して行われます。&lt;br /&gt;
データファイルに直接アクセスすると、情報の漏洩をもたらしたり、システムが不安定になったりします。&lt;br /&gt;
&lt;br /&gt;
=== なぜエンコーディングにUnicodeを選択できないのですか？ ===&lt;br /&gt;
PostgreSQL 8.1からWindows上でUTF-8 UNICODE符号化方式を完全にサポートしました。&lt;br /&gt;
Unicode ODBCドライバはUTF-16をサポートし、また、JDBCドライバは完全にunicodeをサポートします。&lt;br /&gt;
&lt;br /&gt;
PostgreSQLサーバは２バイトのUTF-16、４バイトのUTF-32 Unicode符号化方式を、内部データ格納やネットワーク通信においてサポートしません。&lt;br /&gt;
WindowsにおいてUTF-16がデフォルトの符号化方式であり、Windowsユーザはたいてい「Unicode」といえばこの符号化方式と考えますので、これが問題になるかと想像するかもしれませんが、ODBCおよびJDBCドライバが面倒を見てくれますので、実際のところは問題ありません。&lt;br /&gt;
libpqを直接使用するプログラムはこれに注意しなければなりません。が大した作業ではありません。&lt;br /&gt;
&lt;br /&gt;
=== 英語以外の言語でインストールしたのだけれども、表示されるメッセージが全て英語になってます！ ===&lt;br /&gt;
インストール処理時の言語の選択はインストール時のみにインストーラが使用する言語を何にするかを決めるものです。&lt;br /&gt;
インストール後の製品のメッセージの言語を変更するためには、&#039;&#039;Natural language support&#039;&#039;機能付きでインストールしなければなりません。&lt;br /&gt;
その後、postgresql.confファイルを編集し、&#039;&#039;lc_messages&#039;&#039;パラメータの値を好みの言語に変更してください。&lt;br /&gt;
&lt;br /&gt;
== インストール時によくあるエラー ==&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQLやインストーラが起動時にクラッシュしたり、起動できなかったり、起動が固まったりします。 ===&lt;br /&gt;
&lt;br /&gt;
WindowsにおけるPostgreSQLのインストールと実行時の問題のよくある原因は、Windows Scripting&lt;br /&gt;
Hostの問題、アンチウィルスソフトウェアの問題、（Microsoft以外の）サードパーティ製のソフトウェアファイアウォールです。&lt;br /&gt;
またpostgresサービスアカウントのパスワードで問題が発生することもあります。&lt;br /&gt;
&lt;br /&gt;
以下の節でこれらの問題を説明します。インストーラの問題を問い合わせる前にこれらを読み、手順に従ってみてください。&lt;br /&gt;
&lt;br /&gt;
==== アンチウィルスソフトウェア ====&lt;br /&gt;
&lt;br /&gt;
何らかのアンチウィルスソフトをインストールしているのであれば、PostgreSQLで使用されるはずのデータディレクトリを対象から外す&#039;&#039;&#039;必要があります&#039;&#039;&#039;。&lt;br /&gt;
これでうまくいかなければ、アンチウィルスソフトを完全にマシンからアンインストールする必要があるのかもしれません。&lt;br /&gt;
&lt;br /&gt;
PostgreSQLはMicrosoftによる文書に完全にしたがって動作するようにWindows内のファイルアクセスコマンドを要求しますので、アンチウィルスソフトウェアはPostgreSQLの操作に干渉することがあり得ます。&lt;br /&gt;
このため多くのアンチウィルスプログラムは、エラーまたは事故のような動作により、これらのコマンドを少し誤作動させてしまうように変更します。&lt;br /&gt;
かなり単純な方法でファイルにアクセスしますので、ほとんどのプログラムで気になることはありません。&lt;br /&gt;
PostgreSQLは継続的に複数のプロセスから同じファイル群を読み書きしますので、アンチウィルスソフトウェアのプログラムミスや設計ミスをもたらしがちです。&lt;br /&gt;
こうした問題のため、不規則かつ予期できないエラー、最悪データ破損を引き起こすことがあり得ます。&lt;br /&gt;
&lt;br /&gt;
またアンチウィルスソフトウェアがPostgreSQLの動作を劇的に遅くすることがよくあります。&lt;br /&gt;
このためスキャナが無視するように少なくともpostgres.exeとデータディレクトリを対象から外さなければなりません&lt;br /&gt;
&lt;br /&gt;
===== 問題がないアンチウィルスソフトウエアには何がありますか？ =====&lt;br /&gt;
&lt;br /&gt;
Windowsインストーラを構築する際に使用しているシステムはいずれもSophos AVかAVGの無料版を使用しています。&lt;br /&gt;
またこれらのシステムでは、これらのプログラムを実行中であってもPostgreSQLのリグレッション試験を完全に通過しています。&lt;br /&gt;
Microsoft Security Essentialsも動作することを把握しています。&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;nod32&#039;&#039;アンチウィルス製品については問題がすでに報告されています。&lt;br /&gt;
この製品を使用している場合は、排除プロセスリストに&amp;quot;postmaster.exe&amp;quot;を追加してください。&lt;br /&gt;
(アドバンスオプションから設定可能です。)&lt;br /&gt;
この問題については解決のための報告を行っています。&lt;br /&gt;
&lt;br /&gt;
McAfeeやPandaアンチウィルスソフトウェア、および、NetLimiterネットワーク監視ソフトウェアについてもすでに問題が報告されています。&lt;br /&gt;
このソフトウェアパッケージと一緒にPostgreSQLが稼動している場合もありますが、一部で動作しないことがあり、これに対するまだ具体的、あるいは推奨する方法はありません。&lt;br /&gt;
インストール時に特化した問題かもしれません。&lt;br /&gt;
アンインストールが必要な場合もありました。&lt;br /&gt;
&lt;br /&gt;
==== ソフトウェアファイアウォール ====&lt;br /&gt;
&lt;br /&gt;
マシンにサードパーティ製のファイアウォールソフトウェアがインストールされている場合、無効またはアンインストールを試してください。&lt;br /&gt;
実際のところ、Microsoftにより提供される組み込みのファイアウォールが優れた処理を行いますので、Windows XP以降ではサードパーティ製のファイアウォールの必要性はありません。&lt;br /&gt;
一部のできがよくない、サードパーティ製のファイアウォールは正しくアンインストールすることができません。&lt;br /&gt;
このためアンインストールの後、[http://support.microsoft.com/kb/299357 tell Windows to repair its network settings]を行わなければならないかもしれません。&lt;br /&gt;
&lt;br /&gt;
インストールの際に無効にし、アンインストールの時に元に戻すことに失敗する製品が多くあるため、過去サードパーティ製ファイアウォールを使用していて、アンインストールした場合、Windows Firewallが有効に戻っていることを確認してください。&lt;br /&gt;
&lt;br /&gt;
==== インストーラがインストール時に実行エラーで終了してしまいます？ ====&lt;br /&gt;
&lt;br /&gt;
インストーラが&#039;&#039;An error occured executing the Microsoft VC++ runtime installer&#039;&#039;などのエラーで終了する可能性があります。&lt;br /&gt;
これはWindowsでのみ起こり得ます。&lt;br /&gt;
&lt;br /&gt;
これが発生する原因には大きく２つあります。&lt;br /&gt;
&lt;br /&gt;
1) Windows Scripting HostがVBscriptsを実行することができませんでした。&lt;br /&gt;
これは、スクリプトホストが無効な場合（あまりありません）、またはインストーレーションが破損していた場合に発生します。&lt;br /&gt;
この問題の兆候は、&#039;&#039;CScript Error: Can&#039;t find script engine &amp;quot;VBScript&amp;quot; for script &amp;quot;C:\...&#039;&#039;のようなメッセージです。&lt;br /&gt;
これはVBscriptインタプリタを再登録することで解消することがよくあります。&lt;br /&gt;
&#039;&#039;Start&#039;&#039; -&amp;gt; &#039;&#039;Run&#039;&#039;をクリックし、以下を入力、そして&#039;&#039;OK&#039;&#039;をクリックしてください。&lt;br /&gt;
&lt;br /&gt;
 regsvr32 %systemroot%\system32\vbscript.dll&lt;br /&gt;
&lt;br /&gt;
これが失敗する場合、古めのバージョンのWindowsであれば[http://www.microsoft.com/downloads/en/results.aspx?freetext=windows+script+host&amp;amp;displaylang=en&amp;amp;stype=s_basic updating the scripting host]を試してください。&lt;br /&gt;
&lt;br /&gt;
2) インストーラがシステムの&#039;&#039;TEMP&#039;&#039;ディレクトリで適切にファイルを読み書きすることができませんでした。&lt;br /&gt;
これは、&#039;&#039;TEMP&#039;&#039;または&#039;&#039;TMP&#039;&#039;環境変数が標準以外の値に設定されている場合に起こります。&lt;br /&gt;
これは、ログファイル内の、スクリプトが実行できなかった、または見つからなかったことを示すメッセージによって確認することができます。&lt;br /&gt;
この問題を解消するためには、&#039;&#039;TEMP&#039;&#039;または&#039;&#039;TMP&#039;&#039;変数が正しい値に設定されていることを確認してください。&lt;br /&gt;
&lt;br /&gt;
==== postgresユーザのパスワードに関する障害 ====&lt;br /&gt;
&lt;br /&gt;
使用されるパスワードの違いと、パスワードリセットなど一般的な問題を解決させる方法について、Dave Pageが[http://pgsnake.blogspot.com/2010/07/postgresql-passwords-and-installers.html ブログ記事]を記述しています。&lt;br /&gt;
&lt;br /&gt;
==== PATH環境変数 ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;cygwin&#039;&#039;をインストールし、かつ、cygwin\binディレクトリがシステムのPATH変数にある場合も問題があります。&lt;br /&gt;
このcygwinディレクトリにはインタプリタ言語(TCL、perl、python)に関連したDLLファイルが存在します。&lt;br /&gt;
が、これらにはインストーラやインストールされたPostgreSQLをハングさせたりクラッシュさせるような不具合があります。&lt;br /&gt;
インストーラを実行する前にパスからcygwin\binディレクトリを消去してください！&lt;br /&gt;
&lt;br /&gt;
libssl、libintl、またはその両方のバージョンを含むディレクトリがPATH環境変数に含まれている場合にも、問題が報告されています。&lt;br /&gt;
&lt;br /&gt;
==== initdbのインストールと実行の時、権限に関するエラーが起こります ====&lt;br /&gt;
&lt;br /&gt;
PostgreSQLサービスアカウントが、インストール先のディレクトリまでの階層全てに権限を持っているか確認してください。&lt;br /&gt;
インストーラはインストール先ディレクトリの権限を設定しますが、その親ディレクトリの権限は設定しません。&lt;br /&gt;
&lt;br /&gt;
==== インストーラが指定したアカウントが管理者だと言い張ります。実際は管理者ではありません！ ====&lt;br /&gt;
&lt;br /&gt;
よくあるのは、そのつもりがなかったとしても、指定したアカウントがadministratorまたはpowerユーザであることです。&lt;br /&gt;
インストーラで使用している検査は具体的にいうとAdministratorsグループやPower Usersグループのメンバを検査しています。&lt;br /&gt;
作業を戻して、「Local Users and Groups」からAdministratorsグループを開き、メンバを確認してください。&lt;br /&gt;
更に、どのグループ(ドメインまたはローカル)がAdministratorsグループのメンバになっているか、そしてそのグループのグループメンバなどなどと確認してください。&lt;br /&gt;
PostgreSQLは入れ子のグループに対して全てのレベルを検査します。&lt;br /&gt;
&lt;br /&gt;
==== ターミナルサービスセッションからはPostgreSQLをインストールできないというエラーメッセージが現れます ====&lt;br /&gt;
&lt;br /&gt;
残念ながらその通りです。&lt;br /&gt;
PostgreSQLのバックエンドはTSセッションからは実行しません。&lt;br /&gt;
また、initdbを行うために、インストーラはスタンドアロンのバックエンドを起動しなければなりません。&lt;br /&gt;
そのため、インストールはコンソールから行わなければなりません。&lt;br /&gt;
Windows Server 2003を使用している場合は、単なる管理用セッションではなく、実際のコンソールにリモートアクセスすることができることに注意してください。&lt;br /&gt;
このためには、&amp;lt;I&amp;gt;mstsc /console&amp;lt;/I&amp;gt;を実行してリモートデスクトップ接続を開始し、その後は通常通りに接続してください。&lt;br /&gt;
これはサーバローカルのコンソールをロックし、そのセッション経由のコントロールを提供します。&lt;br /&gt;
この状況であれば、PostgreSQLをうまくインストールできるはずです。&lt;br /&gt;
&lt;br /&gt;
==== &amp;quot;the user has not been granted the requested logon type at this computer&amp;quot;などといったエラーになります ====&lt;br /&gt;
&lt;br /&gt;
指定したPostgreSQLアカウントが『サービスとしてログオン』権限と『ローカルにログオン』権限を持っていることを確認してください。&lt;br /&gt;
『ローカルにログオン』権限はインストール段階でのみ必要で、セキュリティポリシーが要求している場合インストール後に取り除くことができます。&lt;br /&gt;
(権限は『ローカルセキュリティポリシー』MMC スナップインを使用して付与したり削除したりできます。&lt;br /&gt;
『ローカルにログオン』権限はデフォルトです。『サービスとしてログオン』権限は通常、インストーラによって自動的に付与されます。)&lt;br /&gt;
&lt;br /&gt;
まだ問題があるのであれば、監査を(『ローカルセキュリティポリシー』スナップインを使用して)有効にし、他にどんな権限がセットアップに必要かを知らせてください。&lt;br /&gt;
&lt;br /&gt;
コンピュータがドメインのメンバである場合、グループポリシーを使用してドメインレベルでセキュリティポリシーが制御されているかもしれません。&lt;br /&gt;
&lt;br /&gt;
==== サービスアカウントの削除方法は？これはユーザリストに出てきません ====&lt;br /&gt;
&lt;br /&gt;
WindowsのGUIツールは時々一部のアカウントを隠しますので、そこから削除することはできません。&lt;br /&gt;
これには自動的に作成（過去のインストレーションから引き継がれたのかもしれません）されたPostgreSQLサービスアカウントが含まれます。このアカウントを削除するためには、以下のようにコマンドラインからNETコマンドを使用してください。&lt;br /&gt;
 NET USER &amp;lt;username&amp;gt; /DELETE&lt;br /&gt;
ここで&amp;lt;username&amp;gt;はユーザのWindowsログイン名、たとえば&#039;&#039;postgres&#039;&#039;です。&lt;br /&gt;
&lt;br /&gt;
== 実行時によるある問題 ==&lt;br /&gt;
&lt;br /&gt;
=== 手続き言語をインストールすると&amp;quot;dynamic load error&amp;quot;というエラーになります。 ===&lt;br /&gt;
&lt;br /&gt;
その手続き言語用の実際の言語DLLが存在しないことを意味する場合がほとんどです。&lt;br /&gt;
PostgreSQLのDLLには言語バインディングのみしか含まれてません。&lt;br /&gt;
言語の分散DLLはシステムPATHに存在しなければなりません。&lt;br /&gt;
現時点の異なる手続き言語で必要なDLLの一覧に関しては、[http://pginstaller.projects.postgresql.org インストール手順]を参照してください。&lt;br /&gt;
&lt;br /&gt;
どのDLLが存在しないかを正確に調べるために、Microsoftが提供する&#039;&#039;depends&#039;&#039;ツールを使用することができます。&lt;br /&gt;
これは、インストール用とは別のWindows CDにあるWindows Support Toolsから利用可能です。&lt;br /&gt;
&#039;&#039;depends plpython.dll&#039;&#039; (PL/pythonの場合)を実行することで、どのインポートが存在しないかを表示します。&lt;br /&gt;
&lt;br /&gt;
=== サーバを一回だけ起動したのですが、多くのpostgres.exeプロセスが存在します。 ===&lt;br /&gt;
&lt;br /&gt;
これは正常です。&lt;br /&gt;
PostgreSQLは複数プロセスアーキテクチャを使用しています。&lt;br /&gt;
空のシステムでは、2個から5個のプロセスが存在するかと思います。&lt;br /&gt;
クライアントが接続し始めると、プロセス数は増加します。&lt;br /&gt;
&lt;br /&gt;
=== 環境変数はどう設定すればいいのですか。 ===&lt;br /&gt;
PostgreSQLは複数の設定のために環境変数を使用します。&lt;br /&gt;
ほとんどのバージョンのWindowsでは、環境変数を変更するためにマイコンピュータのプロパティを開き、「詳細設定」を選択します。&lt;br /&gt;
2種類の環境変数が存在することに注意してください。&lt;br /&gt;
ひとつは全ユーザに適用されるシステム環境変数、もうひとつは現在のユーザ向けの環境変数です。&lt;br /&gt;
PostgreSQLサービス向けの設定を行うための環境変数では、システム環境変数を変更しなければなりません。&lt;br /&gt;
システム環境変数を変更した後、サービスを再起動しなければなりません。&lt;br /&gt;
&lt;br /&gt;
=== ハードウェアは十分ありますが、一度に125程度以上の接続で動作させることができません。 ===&lt;br /&gt;
サービスとして使用すると、おおよそ125以上の同時接続で失敗することを経験するかもしれません。&lt;br /&gt;
PostgreSQLが依存するライブラリの一部がuser32.dllに依存することが原因で発生する可能性があります。&lt;br /&gt;
user32.dllはデスクトップヒープとして知られる領域からメモリを割り当てます。&lt;br /&gt;
デスクトップヒープはログインセッションごとに割り当てられ、通常、非対話型セッションでは512キロバイトが割り当てられます。&lt;br /&gt;
通常稼動する各postgresプロセスはおおよそ3.2キロバイトのデスクトップヒープを消費します。&lt;br /&gt;
これとその他のオーバーヘッドにより、おおよそ125接続近辺で割り当て可能なヒープがなくなります。&lt;br /&gt;
これはコマンドラインから起動した場合には発生しません（より正確には、もっと多くの接続で発生するようになります）。&lt;br /&gt;
対話型のログインセッションで通常3メガバイトのデスクトップヒープが割り当てられるからです。&lt;br /&gt;
&lt;br /&gt;
[http://support.microsoft.com/kb/184802 Microsoft ナレッジベースの記事]で紹介されているようにレジストリの第三SharedSection値を変更することで、非対話型デスクトップヒープを増やすことができます。&lt;br /&gt;
あまりに大きな値を指定するとシステムが起動できなくなる可能性がありますので、これには十分な注意が必要です。&lt;br /&gt;
&lt;br /&gt;
[[Category:FAQ]]&lt;br /&gt;
[[Category:Japanese]]&lt;br /&gt;
[[Category:Windows]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Windowsのバージョン固有の問題 ==&lt;br /&gt;
&lt;br /&gt;
==== 64ビット版Windowsに32ビット版のPostgreSQLをインストールすることはできますか ==== &lt;br /&gt;
&lt;br /&gt;
最近の32ビット版のPostgreSQL（8.3以降）は64ビット版のWindows XP以降にインストールし、使用することができます。しかし最大プロセスアドレス空間（とこれに伴う共有メモリ）に関して32ビットの制限が残っています。&lt;br /&gt;
&lt;br /&gt;
32ビット版のPostgreSQLサーバに、サーバが稼動中のコンピュータ、またはプログラムの実行環境に64ビット版のlibpqもしくはpsqlODBCドライバがインストールされている場合はそのコンピュータ上の64ビット版のプログラムから接続することができます。&lt;br /&gt;
&lt;br /&gt;
32ビット版のPostgreSQLサーバは32ビット版のlibpqとpsqlODBCしかインストールしませんので、追加で64ビット版のODBCドライバかlibpqをインストールしていない限り、サーバをインストールしたコンピュータ上では32ビット版のプログラムのみがそのデータベースを使用することができます。&lt;br /&gt;
&lt;br /&gt;
==== PostgreSQL ODBCドライバはどこにありますか？64ビット版のWindowsで32ビット版のPostgreSQLを使用しています。 ====&lt;br /&gt;
&lt;br /&gt;
32ビット版のドライバを使用して32ビット版のアプリケーション用のデータソースを設定するためには32ビット版のODBC管理を使用しなければなりません。&lt;br /&gt;
&lt;br /&gt;
[http://psqlodbc.projects.postgresql.org psqlODBC]の[[#What about 64-bit ODBC drivers?|64-bit version]]を同時にインストールしていない限り、PostgreSQLの32ビット版のインストールでは32ビット版のODBCドライバしかありません。この32ビットODBCドライバは32ビットプログラムのみで使用することができ、「64ビット版ODBC管理では現れません」。&lt;br /&gt;
&lt;br /&gt;
64ビット版のWindowsの&amp;lt;code&amp;gt;c:\windows\system32\odbcad32&amp;lt;/code&amp;gt;は、この名前にも関わらず「64ビット」ODBCドライバ管理ですので、これは混乱を招きます。これはWindows開発の歴史による産物です。多くのアプリケーションとインストーラがこの名前とパスにあるodbcad32.exeに依存していることは明らかです。このためMicrosoftはばかげた名前になったにも関わらず面倒な状態に陥りました。「system32」ディレクトリが64ビット版Windowsでもこの名前であることも同じ理由です。PostgreSQLでこれをどうにかすることはできません。&lt;br /&gt;
&lt;br /&gt;
参考文献: [http://support.microsoft.com/kb/942976 http://support.microsoft.com/kb/942976]&lt;br /&gt;
&lt;br /&gt;
この記事を読めば64ビット版Windowsにおける32ビット版のODBC管理が以下にあることが分かるでしょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%systemdrive%\Windows\SysWoW64\odbcad32.exe&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
上記パスを&amp;quot;Start-&amp;gt;Run&amp;quot;に入力することで、これを起動することができます。32ビット版のODBC管理上にPostgreSQL ODBCドライバが現れます。&lt;br /&gt;
&lt;br /&gt;
64ビット版のアプリケーションでは32ビット版のODBCドライバを使用することは「できません」。つまり、64ビット版のODBCドライバをインストールしていない限り32ビット版のアプリケーションでのみPostgreSQL ODBCドライバを使用することができます。&lt;br /&gt;
&lt;br /&gt;
==== 32ビット版のPostgreSQLサーバで64ビット版のODBCプログラムを使用することはできますか？ ====&lt;br /&gt;
&lt;br /&gt;
64ビット版の[http://psqlodbc.projects.postgresql.org|psqlODBC]ドライバをインストールしている場合のみです。インストール節を参照してください。&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=20120924updaterelease&amp;diff=18305</id>
		<title>20120924updaterelease</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=20120924updaterelease&amp;diff=18305"/>
		<updated>2012-09-26T02:58:11Z</updated>

		<summary type="html">&lt;p&gt;Hanada: add Japanese page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
&lt;br /&gt;
= Details of 2012-09-24 Update Release Data Corruption Issue =&lt;br /&gt;
&lt;br /&gt;
== Description of the Problem ==&lt;br /&gt;
&lt;br /&gt;
Versions 9.1 and 9.2 of PostgreSQL have a bug with flushing dirty blocks from memory, or &amp;quot;[http://www.postgresql.org/docs/current/static/wal-configuration.html checkpointing]&amp;quot;, introduced accidentally as a side effect of performance optimizations and new features, mainly [[What%27s_new_in_PostgreSQL_9.1#Unlogged_Tables|Unlogged Tables]].  This bug can cause data of certain types to not be written to disk if the database shuts down or restarts for any of the following reasons:&lt;br /&gt;
&lt;br /&gt;
* PostgreSQL crash&lt;br /&gt;
* Server crash or power loss&lt;br /&gt;
* &amp;quot;immediate&amp;quot; shutdown (pg_ctl -m immediate)&lt;br /&gt;
* &amp;quot;kill -9&amp;quot; or Out-Of-Memory-Kill of the postmaster service&lt;br /&gt;
* database is a standby which was promoted to master&lt;br /&gt;
&lt;br /&gt;
Under these circumstances, the database can suffer from recoverable data corruption.  The nature of this corruption is such that it can produce wrong, but seemingly valid, answers to queries, so it is critical that users who may have been affected by this corruption take steps to clean it up very soon.&lt;br /&gt;
&lt;br /&gt;
First, there is a low probability of corruption of BTREE and GIN indexes. Shutting&lt;br /&gt;
down cleanly will limit the further spread of this issue. It&#039;s very likely that if corruption has occurred that it would be visible in the form of error messages when the index is used.&lt;br /&gt;
&lt;br /&gt;
Second, there is a significant probability of corruption of relation visibility maps (approaching 100% on standbys).   This affects 9.1 very differently from 9.2, however. On PostgreSQL 9.1 the worst consequence is some transient inefficiency and/or failure to recover free space during VACUUM. On PostgreSQL 9.2, we use the visibility map during index only scans and so these are likely to produce wrong answers.&lt;br /&gt;
&lt;br /&gt;
The PostgreSQL Global Development Group apologizes for the inconvenience caused by these issues.&lt;br /&gt;
&lt;br /&gt;
== Steps for Users of PostgreSQL 9.1 ==&lt;br /&gt;
&lt;br /&gt;
If you are running 9.1, and suspect that you may be vulnerable to database corruption because your database has shut down unexpectedly or failed over during the last few months:&lt;br /&gt;
&lt;br /&gt;
# Download new 9.1.6 packages&lt;br /&gt;
# Do a clean shutdown of PostgreSQL, using one of the following mechanisms:&lt;br /&gt;
#* init script or service manager&lt;br /&gt;
#* pg_ctl -m smart stop&lt;br /&gt;
#* pg_ctl -m fast stop&lt;br /&gt;
# Install 9.1.6&lt;br /&gt;
# Restart the database system&lt;br /&gt;
# Gradually rebuild all of your BTree and GIN indexes (see below)&lt;br /&gt;
# Schedule a manual vacuum of the whole database during a convenient slow period (see below)&lt;br /&gt;
&lt;br /&gt;
If you are planning to upgrade to PostgreSQL 9.2 using pg_upgrade, it is critical for you to run the full database VACUUM first.&lt;br /&gt;
&lt;br /&gt;
== Steps for Users of PostgreSQL 9.2 ==&lt;br /&gt;
&lt;br /&gt;
If you are running 9.2.0, and suspect that you may be vulnerable to database corruption because your database has shut down unexpectedly or failed over during the last two weeks:&lt;br /&gt;
&lt;br /&gt;
# Download new 9.2.1 packages&lt;br /&gt;
# Do a clean shutdown of PostgreSQL, using one of the following mechanisms:&lt;br /&gt;
#* init script or service manager&lt;br /&gt;
#* pg_ctl -m smart stop&lt;br /&gt;
#* pg_ctl -m fast stop&lt;br /&gt;
# Install 9.2.1&lt;br /&gt;
# Restart the database system&lt;br /&gt;
# VACUUM all tables in your database immediately&lt;br /&gt;
# Gradually rebuild all of your BTree and GIN indexes (see below)&lt;br /&gt;
&lt;br /&gt;
== How to VACUUM All Tables ==&lt;br /&gt;
&lt;br /&gt;
To correct corruption of the visibility map, users should run a vacuum and force a scan of all database blocks in order to reset the entire map.  Since this means effectively scanning the entire database, it will generate considerable IO and take significant time to  execute for large databases.  One way to ameliorate the impact on concurrently running database load is to use cost delay to spread out the vacuum:&lt;br /&gt;
&lt;br /&gt;
    SET [http://www.postgresql.org/docs/9.2/static/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-VACUUM-COST vacuum_cost_delay] = 50;&lt;br /&gt;
&lt;br /&gt;
=== Interactive VACUUM ===&lt;br /&gt;
&lt;br /&gt;
For each database, you should:&lt;br /&gt;
&lt;br /&gt;
# log in to psql as the Postgres superuser&lt;br /&gt;
# set vacuum_cost_delay, if doing so&lt;br /&gt;
# run &amp;quot;[http://www.postgresql.org/docs/9.2/static/sql-vacuum.html VACUUM ( FREEZE, VERBOSE, ANALYZE );]&amp;quot;  (ANALYZE is optional)&lt;br /&gt;
&lt;br /&gt;
This will produce a lot of output, allowing you to track progress of the full-database vacuum.&lt;br /&gt;
&lt;br /&gt;
You can also VACUUM one table at a time instead of doing them all one after the other, provided that you have some way to track which tables have and have not been vacuumed.&lt;br /&gt;
&lt;br /&gt;
=== vacuumdb ===&lt;br /&gt;
&lt;br /&gt;
If you have multiple databases to vacuum, you may find it convenient to use the [http://www.postgresql.org/docs/9.2/static/app-vacuumdb.html vacuumdb utility] instead.  This would work by:&lt;br /&gt;
&lt;br /&gt;
# set vacuum_cost_delay in postgresql.conf, if doing so (and reload database)&lt;br /&gt;
# run &amp;quot;vacuumdb -F -v -z -a&amp;quot; as the postgres superuser&lt;br /&gt;
&lt;br /&gt;
Note that you may need to give vacuumdb additional parameters in order to connect with the database server.  The -z (analyze) and -v (verbose) options are optional.&lt;br /&gt;
&lt;br /&gt;
== Rebuild BTree/GIN Indexes ==&lt;br /&gt;
&lt;br /&gt;
It is likely that any indexes which are corrupted because of the issues fixed in this update release will display error messages when accessed, and can be easily identified.  However, it is possible (though unlikely) that a few indexes may be corrupted so that they return incorrect answers without errors. &lt;br /&gt;
&lt;br /&gt;
The VACUUM FREEZE recommended above will correct some types of index corruption.  However, users who have strong data integrity concerns, or feel they are especially at risk due to multiple crashes or failovers in their server history, should take the extra step of rebuilding indexes in order to eliminate any possible corruption.&lt;br /&gt;
&lt;br /&gt;
=== Rebuilding an Individual Index ===&lt;br /&gt;
&lt;br /&gt;
Whether you are being precautionary, or because you have found an index corruption error, you can rebuild indexes one at a time.  The simplest way is via [http://www.postgresql.org/docs/9.2/static/sql-reindex.html REINDEX].&lt;br /&gt;
&lt;br /&gt;
    REINDEX TABLE &amp;lt;tablename&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
or for a single index:&lt;br /&gt;
&lt;br /&gt;
    REINDEX INDEX &amp;lt;indexname&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
You may want to increase the RAM available to REINDEX, by increasing maintenance_work_mem, up to 1/8 of your available RAM (up to a maximum of 2GB).  REINDEX takes a full table write lock, however, and depending on the size of the table, can take a considerable time to run.   In order to rebuild indexes while under concurrent database load, use CREATE INDEX CONCURRENTLY:&lt;br /&gt;
&lt;br /&gt;
    CREATE INDEX CONCURRENTLY &amp;lt;indexname&amp;gt;_tmp &amp;lt;index_definition&amp;gt;;&lt;br /&gt;
    BEGIN;&lt;br /&gt;
    DROP INDEX &amp;lt;indexname&amp;gt;;&lt;br /&gt;
    ALTER INDEX &amp;lt;indexname&amp;gt;_tmp RENAME TO &amp;lt;indexname&amp;gt;;&lt;br /&gt;
    END;&lt;br /&gt;
&lt;br /&gt;
This locks the table only during the final drop and rename stage.  It is, however, more complex.&lt;br /&gt;
&lt;br /&gt;
Either approach will generate considerable IO while running on large tables.&lt;br /&gt;
&lt;br /&gt;
=== Getting a List of Btree and GIN Indexes ===&lt;br /&gt;
&lt;br /&gt;
Regardless of your approach towards rebuilding your indexes, you may want to get a list of all BTree and GIN indexes in the database.  BTree is the most common type of index, so this will include most of the indexes in your database.  Given that GiST indexes can be quite large, though, you may want to omit them from rebuilding.&lt;br /&gt;
&lt;br /&gt;
Use this query:&lt;br /&gt;
&lt;br /&gt;
    SELECT tablename, indexname, indexdef&lt;br /&gt;
    FROM pg_indexes&lt;br /&gt;
    WHERE ( indexdef ILIKE &#039;%USING btree%&#039;&lt;br /&gt;
      OR indexdef ILIKE &#039;%USING GIN%&#039; )&lt;br /&gt;
      AND schemaname &amp;lt;&amp;gt; &#039;pg_catalog&#039;&lt;br /&gt;
    ORDER BY tablename, indexname;&lt;br /&gt;
&lt;br /&gt;
=== Reindexing Everything ===&lt;br /&gt;
&lt;br /&gt;
If you can afford the required downtime, and want to be absolutely certain that you&#039;ve prevented all corruption, you can reindex every index in your database using [http://www.postgresql.org/docs/9.2/static/app-reindexdb.html the reindexdb utility].   Note that this will cause GiST indexes to be rebuilt as well, even though they are not in danger of corruption.&lt;br /&gt;
&lt;br /&gt;
Run the following as the postgres superuser to reindex one database:&lt;br /&gt;
&lt;br /&gt;
    reindexdb &amp;lt;databasename&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or to reindex all databases:&lt;br /&gt;
&lt;br /&gt;
    reindexdb -a&lt;br /&gt;
&lt;br /&gt;
Additional options may be required for reindexdb to connect to your database.  Since reindexdb will take a lock on entire tables in your installation, one at a time, this is best done during a downtime.&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=20120924updaterelease/ja&amp;diff=18304</id>
		<title>20120924updaterelease/ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=20120924updaterelease/ja&amp;diff=18304"/>
		<updated>2012-09-26T02:57:11Z</updated>

		<summary type="html">&lt;p&gt;Hanada: translate into Japanese&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
&lt;br /&gt;
= 2012-09-24 更新リリースのデータ破損問題に関する詳細 =&lt;br /&gt;
&lt;br /&gt;
== 問題の説明 ==&lt;br /&gt;
&lt;br /&gt;
PostgreSQLのバージョン9.1と9.2には、ダーティブロックのメモリからのフラッシュ(または&amp;quot;[http://www.postgresql.jp/document/current/html/wal-configuration.html チェックポイント]&amp;quot;)に関して性能改善と新機能の追加(主に[[What%27s_new_in_PostgreSQL_9.1#Unlogged_Tables|ログを取らないテーブル]])の副作用として偶然混入したバグがあります。このバグは、以下の理由によりデータベースがシャットダウンまたは再起動した場合にある種のデータがディスクに書き込まれないことの原因となります。&lt;br /&gt;
&lt;br /&gt;
* PostgreSQLのクラッシュ&lt;br /&gt;
* サーバクラッシュまたは電源喪失&lt;br /&gt;
* &amp;quot;immediate&amp;quot; シャットダウン (pg_ctl -m immediate)&lt;br /&gt;
* postmasterサービスに対する&amp;quot;kill -9&amp;quot; または Out-Of-Memory-Kill&lt;br /&gt;
* データベースがスタンバイからマスターに昇格した&lt;br /&gt;
&lt;br /&gt;
これらの状況下では、データベースはリカバリ可能なデータ破損に陥る可能性があります。この破損の特徴は、一見正しいが実際には間違っている問い合わせ結果を返す場合があることです。このため、このデータ破損の影響を受けたかもしれないユーザはただちに復旧手順を実施することが重要です。&lt;br /&gt;
&lt;br /&gt;
第一に、BTREEとGINインデックスの破損の可能性は低いです。正常にシャットダウンすればこの問題の拡散を防ぐことが出来ます。もしデータ破損が起きていた場合、おそらくインデックスが使用された時にエラーメッセージの形で現れるでしょう。&lt;br /&gt;
&lt;br /&gt;
次に、リレーションの可視性マップ(訳注:visibility map)の破損が起こる有意な可能性(スタンバイではほぼ100%)があります。&lt;br /&gt;
&lt;br /&gt;
PostgreSQL Global Development Groupはこの問題による不便についてお詫びします。&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL 9.1 ユーザのための手順 ==&lt;br /&gt;
&lt;br /&gt;
もし9.1を利用しており、かつ過去数ヶ月の間にあなたのデータベースが予期せぬシャットダウンやフェイルオーバーをしていてデータベース破損の影響を受けている疑いがある場合は、以下の手順を実施してください:&lt;br /&gt;
&lt;br /&gt;
# 新しい 9.1.6 のパッケージ群をダウンロードする&lt;br /&gt;
# 以下のいずれかの手段でPostgreSQLをクリーンシャットダウンする&lt;br /&gt;
#* 起動スクリプトまたはサービスマネージャ&lt;br /&gt;
#* pg_ctl -m start stop&lt;br /&gt;
#* pg_ctl -m fast stop&lt;br /&gt;
# 9.1.6をインストールする&lt;br /&gt;
# データベースシステムを再起動する&lt;br /&gt;
# BTreeおよびGINのインデックスを順次再構築する(下記参照)&lt;br /&gt;
# データベース全体に対する手動vacuumを都合のよい負荷の低い時間帯にスケジュールする(下記参照)&lt;br /&gt;
&lt;br /&gt;
もしあなたがPostgreSQL 9.2へのアップグレードを計画している場合は、最初にデータベース全体に対するVACUUMを実行することが重要です。&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL 9.2 ユーザのための手順 ==&lt;br /&gt;
&lt;br /&gt;
もし9.2.0を利用しており、かつ過去数ヶ月の間にあなたのデータベースが予期せぬシャットダウンやフェイルオーバーをしていてデータベース破損の影響を受けている疑いがある場合は、以下の手順を実施してください:&lt;br /&gt;
&lt;br /&gt;
# 新しい 9.2.1 のパッケージ群をダウンロードする&lt;br /&gt;
# 以下のいずれかの手段でPostgreSQLをクリーンシャットダウンする&lt;br /&gt;
#* 起動スクリプトまたはサービスマネージャ&lt;br /&gt;
#* pg_ctl -m start stop&lt;br /&gt;
#* pg_ctl -m fast stop&lt;br /&gt;
# 9.2.1をインストールする&lt;br /&gt;
# データベースシステムを再起動する&lt;br /&gt;
# すぐにあなたのデータベース内の全てのテーブルをVACUUMする。&lt;br /&gt;
# BTreeおよびGINのインデックスを順次再構築する(下記参照)&lt;br /&gt;
&lt;br /&gt;
== 全てのテーブルをVACUUMする方法 ==&lt;br /&gt;
&lt;br /&gt;
可視性マップの破損を修復するために、ユーザはvacuumを実行してマップ全体をリセットするために全データベースブロックのスキャンを強制しなければなりません。これは結果的にデータベース全体のスキャンを意味するので、相当量のIOを発生させ、大きなデータベースではかなり時間がかかるでしょう。並列で実行されるデータベースの影響を改善する方法、vacuumを拡散させるためにcost delayを使用することです:&lt;br /&gt;
&lt;br /&gt;
    SET [http://www.postgresql.jp/document/current/html/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-VACUUM-COST vacuum_cost_delay] = 50;&lt;br /&gt;
&lt;br /&gt;
=== 対話的VACUUM ===&lt;br /&gt;
&lt;br /&gt;
データベースそれぞれについて、以下の手順を実施する必要があります:&lt;br /&gt;
&lt;br /&gt;
# psqlにPostgresのスーパーユーザでログインする&lt;br /&gt;
# もしそうするならば、vacuum_cost_delayを設定する&lt;br /&gt;
# &amp;quot;[http://www.postgresql.jp/document/current/html/sql-vacuum.html VACUUM ( FREEZE, VERBOSE, ANALYZE );]&amp;quot;を実行する(ANALYZEは省略可能)&lt;br /&gt;
&lt;br /&gt;
このコマンドはデータベース全体のvacuumの進捗を確認できるように大量の出力を生成します。&lt;br /&gt;
&lt;br /&gt;
vacuumの終わったものと終わっていないものを追跡するために、あなたは全部を順番に実行する代わりに一度に一つずつテーブルをVACUUMすることもできます。&lt;br /&gt;
&lt;br /&gt;
=== vacuumdb ===&lt;br /&gt;
&lt;br /&gt;
もしvacuumするデータベースが複数ある場合は、代わりに[http://www.postgresql.jp/document/current/html/app-vacuumdb.html vacuumdb]を使うほうが便利だと判断するかもしれません。この場合はこのように実行します:&lt;br /&gt;
&lt;br /&gt;
# もしそうするならば、postgresql.confでvacuum_cost_delayを設定する(そしてデータベースをリロードする)&lt;br /&gt;
# postgresスーパーユーザで&amp;quot;vacuumdb -F -v -z -a&amp;quot;を実行する&lt;br /&gt;
&lt;br /&gt;
データベースサーバに接続するために追加のパラメータをvacuumdbに指定する必要があるかもしれない点に注意して下さい。-z(analyze)や-v(verbose)オプションは省略可能です。&lt;br /&gt;
&lt;br /&gt;
== BTree/GINインデックスの再構築 ==&lt;br /&gt;
&lt;br /&gt;
更新リリースにより修正された問題によって破損したインデックスはアクセスされるとエラーメッセージを表示するので、容易に識別できそうです。しかし、いくつかのインデックスは(あまりなさそうですが)エラーなしで誤った応答を返すように破損しているかもしれません。&lt;br /&gt;
&lt;br /&gt;
上で推奨されているVACUUM FREEZEは何種類かのインデックス破損を修復します。しかし、データの完全性に関する強い懸念を持つユーザや、サーバで過去に複数回のクラッシュやフェイルオーバーが発生していて特にリスクを感じているユーザは、考えうるあらゆる破損を除去するためにインデックスの再構築を追加手順として実施すべきです。&lt;br /&gt;
&lt;br /&gt;
=== 各インデックスの再構築 ===&lt;br /&gt;
&lt;br /&gt;
予防であってもインデックス破損を発見したためであっても、一度に一つずつインデックスを再構築できます。最も単純な方法は[http://www.postgresql.jp/document/current/html/sql-reindex.html REINDEX]を使うことです。&lt;br /&gt;
&lt;br /&gt;
    REINDEX TABLE &amp;lt;tablename&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
または、単一インデックスに対しては:&lt;br /&gt;
&lt;br /&gt;
    REINDEX INDEX &amp;lt;indexname&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
利用可能なRAMの1/8(最大で2GB)までmaintainance_work_memを増やして、REINDEXで使えるRAMを増やすこともできます。REINDEXはテーブル全体の書き込みロックを取得し、テーブルのサイズに依存しますが実行にかなりの時間がかかることがあります。同時に存在するデータベース負荷の下でインデックスを再構築するために、CREATE INDEX CONCURRENTLYが利用できます:&lt;br /&gt;
&lt;br /&gt;
    CREATE INDEX CONCURRENTLY &amp;lt;indexname&amp;gt;_tmp &amp;lt;index_definition&amp;gt;;&lt;br /&gt;
    BEGIN;&lt;br /&gt;
    DROP INDEX &amp;lt;indexname&amp;gt;;&lt;br /&gt;
    ALTER INDEX &amp;lt;indexname&amp;gt;_tmp RENAME TO &amp;lt;indexname&amp;gt;;&lt;br /&gt;
    END;&lt;br /&gt;
&lt;br /&gt;
これは最後の削除とリネームの段階でのみテーブルをロックします。ただし、より複雑です。&lt;br /&gt;
&lt;br /&gt;
どちらのアプローチも、大きなテーブルに実行している間は相当量のIOを発生させます。&lt;br /&gt;
&lt;br /&gt;
=== BtreeおよびGINインデックスの一覧の取得 ===&lt;br /&gt;
&lt;br /&gt;
インデックス再構築のアプローチに関わらず、データベース内のBTreeおよびGINインデックスの一覧を取得できます。BTreeは最も一般的なインデックス種別であるため、あなたのデータベース内のほとんどのインデックスがこれに含まれるでしょう。GiSTインデックスはとても大きくなりうることを考慮して、それらを再構築の対象から外すことができます。&lt;br /&gt;
&lt;br /&gt;
このクエリを使ってください:&lt;br /&gt;
&lt;br /&gt;
    SELECT tablename, indexname, indexdef&lt;br /&gt;
    FROM pg_indexes&lt;br /&gt;
    WHERE ( indexdef ILIKE &#039;%USING btree%&#039;&lt;br /&gt;
      OR indexdef ILIKE &#039;%USING GIN%&#039; )&lt;br /&gt;
      AND schemaname &amp;lt;&amp;gt; &#039;pg_catalog&#039;&lt;br /&gt;
    ORDER BY tablename, indexname;&lt;br /&gt;
&lt;br /&gt;
=== 全インデックスの再構築 ===&lt;br /&gt;
&lt;br /&gt;
要求されるダウンタイムを許容でき、全ての破損の予防を絶対的に確信したいのであれば、[http://www.postgresql.jp/document/current/html/app-reindexdb.html reindexdb ユーティリティ]を使ってデータベース内の全てのインデックスを再構築することができます。このコマンドは、破損の危険性がないにも関わらずGiSTインデックスも再構築してしまう点に注意してください。&lt;br /&gt;
&lt;br /&gt;
一つのデータベースをインデックス再構築するにはpostgresスーパーユーザで以下を実行してください:&lt;br /&gt;
&lt;br /&gt;
    reindexdb &amp;lt;databasename&amp;gt;&lt;br /&gt;
&lt;br /&gt;
または、全てのデータベースをインデックス再構築するには:&lt;br /&gt;
&lt;br /&gt;
    reindexdb -a&lt;br /&gt;
&lt;br /&gt;
データベースサーバに接続するために、reindexdbの追加のオプションが必要になるかもしれません。reindexdbは全てのテーブルのロックを一度に一つずつ取得するので、ダウンタイム中に行うのが最適です。&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=Slow_Counting/ja&amp;diff=18238</id>
		<title>Slow Counting/ja</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=Slow_Counting/ja&amp;diff=18238"/>
		<updated>2012-09-19T01:16:27Z</updated>

		<summary type="html">&lt;p&gt;Hanada: Translate note about index-only scans in 9.2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
&#039;&#039;&#039;以下の記事は9.2より前のPostgreSQLバージョンにのみ適用されることに注意してください。今はインデックスオンリースキャンが実装されています。&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
以下の例のようなテーブル内の全行数を数えることは、PostgreSQLの性能が遅いことが分かっている操作の１つです。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM table&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
これが低速となる理由はPostgreSQLの[[MVCC]]実装に関連します。&lt;br /&gt;
複数のトランザクションが異なるデータ状態を参照することができることは、&amp;quot;COUNT(*)&amp;quot;のためにテーブル全体に渡るデータをまとめる簡単な方法があり得ないことを意味します。&lt;br /&gt;
別の見方をすると、PostgreSQLは&#039;&#039;&#039;必ず&#039;&#039;&#039;すべての行をたどります。&lt;br /&gt;
これは通常、テーブル内の全行に関する情報をシーケンシャルスキャンを使用して読み取ることになります。&lt;br /&gt;
問い合わせがどのように進んでいるかを確認する優れた方法はEXPLAIN ANALYZEを使用することです。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
postgres=# EXPLAIN ANALYZE SELECT COUNT(*) FROM accounts;&lt;br /&gt;
                                                      QUERY PLAN                                                       &lt;br /&gt;
-----------------------------------------------------------------------------------------------------------------------&lt;br /&gt;
 Aggregate  (cost=4499.00..4499.01 rows=1 width=0) (actual time=465.588..465.591 rows=1 loops=1)&lt;br /&gt;
   -&amp;gt;  Seq Scan on accounts  (cost=0.00..4249.00 rows=100000 width=0) (actual time=0.011..239.212 rows=100000 loops=1)&lt;br /&gt;
 Total runtime: 465.642 ms&lt;br /&gt;
(3 rows)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
悲観的にならざるを得ないのがこの厳密な集約構文だけであることがわかることには価値があります。もし次のように&amp;quot;WHERE&amp;quot;句があったとすると、PostgreSQLは限定されたフィールドに対して利用可能なインデックスを利用して、数えなければならないレコードの行数を制限します。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM table WHERE status = &#039;something&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
これによりこうした問い合わせは大きく高速化されます。PostgreSQLはまだ、行が存在するかどうかを検証するために結果行を読み取る必要があります。他のデータベースシステムでは、こうした状況ではインデックスを参照する必要があるだけかもしれません。&lt;br /&gt;
&lt;br /&gt;
== 行数の推定 ==&lt;br /&gt;
&lt;br /&gt;
おおよその行数だけが必要である場合、PostgreSQLには1つの代替方法があります。&lt;br /&gt;
これは以下のようにpg_classカタログのreltuplesフィールドを使用することです。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
pgbench=# select reltuples from pg_class where relname=&#039;tellers&#039;;&lt;br /&gt;
 reltuples &lt;br /&gt;
-----------&lt;br /&gt;
       250&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
この前提となるのは、統計情報が最新情報を維持できるほど十分にテーブルに対してANALYZEを実行していることです。&lt;br /&gt;
&lt;br /&gt;
他にもトリガを基にした機構を使用してテーブル内の行数を数える方法がよく使われます。&lt;br /&gt;
これらの技法の片方、または両方の説明は以下にあります。&lt;br /&gt;
* [http://www.varlena.com/GeneralBits/120.php Counting Rows]&lt;br /&gt;
* [http://www.varlena.com/GeneralBits/49.php Tracking the Row Count]&lt;br /&gt;
&amp;lt;p&amp;gt;&lt;br /&gt;
* 元原稿:  [[Why PostgreSQL Instead of MySQL: Comparing Reliability and Speed in 2007|Why PostgreSQL Instead of MySQL]] (これにはMySQLとどのように異なるかについても議論されています)&lt;br /&gt;
&lt;br /&gt;
[[Category:FAQ]]&lt;br /&gt;
[[Category:Performance]]&lt;br /&gt;
[[Category:Japanese]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=16364</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=16364"/>
		<updated>2012-03-06T11:11:44Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* FDW routines */ PlanForeignScan can return multiple paths, from 9.2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification began in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
Check out the list of all the [[foreign data wrappers]]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Add pgsql_fdw as a contrib module ==&lt;br /&gt;
[http://commitfest.postgresql.org/action/patch_view?id=667 &amp;quot;pgsql_fdw contrib module&amp;quot;] is under proposal at CF 2011-11.  The goal of this proposal is to add pgsql_fdw as a contrib module.&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook to delegate row sampling to each FDW.  For this purpose, [http://commitfest.postgresql.org/action/patch_view?id=661 &amp;quot;Collecting statistics on foreign tables&amp;quot;] is under proposal at CF 2011-11. This proposal provides a handler function which allows FDWs to handle ANALYZE commands which are executed for foreign tables. In addition, contrib/file_fdw is enhanced to get sample rows from actual data file and calculate statistics by using existing routines in core.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a JOIN (or JOINs) on the remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching has not been implemented in order to focus on the FDW API.  Ideas below once had been implemented but have since been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scan of a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If the reusable connection is not in cache, then call FdwRoutine.ConnectServer() to create a new connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is the same as the name of the server which the connection uses.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map the foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; has a &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In the first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In the SQL standard, FDW routines are designed to have a portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, a PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOINs on several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hooks may be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
=== Version 4 ===&lt;br /&gt;
In 9.2, PlanForeignScan is changed so that FDW can return multiple scan paths per a foreign table, and this change get rid of FdwPlan.  Planner chooses appropriate path from paths provided by FDW, and creates only one ForeignScan node which has copy of fdw_private of chosen path.  Now PlanForeignScan is responsible to create ForeignScan path node and add it to RelOptInfo (baserel).  You can use create_foreignscan_path, which is also changed in 9.2, to create a finished ForeignScan path node.&lt;br /&gt;
&lt;br /&gt;
 typedef void (*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                           PlannerInfo *root,&lt;br /&gt;
                                           RelOptInfo *baserel);&lt;br /&gt;
&lt;br /&gt;
PlanForeignScan of FDW which doesn&#039;t support any pushing down feature would be like this.&lt;br /&gt;
&lt;br /&gt;
 void&lt;br /&gt;
 fooPlanForeignScan(Oid foreigntableid,&lt;br /&gt;
                    PlannerInfo *root,&lt;br /&gt;
                    RelOptInfo *baserel)&lt;br /&gt;
 {&lt;br /&gt;
     double rows;&lt;br /&gt;
     Cost startup_cost, total_cost;&lt;br /&gt;
     List *fdw_private;&lt;br /&gt;
 &lt;br /&gt;
     /* Estimate # of rows returned by this scan */&lt;br /&gt;
     rows = ...;&lt;br /&gt;
 &lt;br /&gt;
     /* Estimate costs of this scan */&lt;br /&gt;
     startup_cost = ...;&lt;br /&gt;
     total_cost = ...;&lt;br /&gt;
 &lt;br /&gt;
     /* Store FDW-private information as copy-able objects */&lt;br /&gt;
     fdw_private = NIL;&lt;br /&gt;
     fdw_private = lappend(fdw_private, makeNode(...));&lt;br /&gt;
     ...&lt;br /&gt;
 &lt;br /&gt;
     /* Create path node and add it to baserel */&lt;br /&gt;
     add_path(baserel, (Path *)&lt;br /&gt;
              create_foreignscan_path(root, baserel,&lt;br /&gt;
                                      rows,          /* # of tuples in the table */&lt;br /&gt;
                                      startup_cost,  /* costs are required */&lt;br /&gt;
                                      total_costs,&lt;br /&gt;
                                      NIL,           /* no pathkeys */&lt;br /&gt;
                                      NULL,          /* no outer rel eigher */&lt;br /&gt;
                                      NIL,           /* no param clause */&lt;br /&gt;
                                      fdw_private));&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
In other FDW functions, fdw_private is available via ForeignScanState.&lt;br /&gt;
&lt;br /&gt;
     List *fdw_private;&lt;br /&gt;
 &lt;br /&gt;
     fdw_private = ((ForeignScan *) node-&amp;gt;ss.ps.plan)-&amp;gt;fdw_private;&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
An FDW handler function returns an FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as the container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in which we store the foreign server ID and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for this purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In the planning phase, create_foreignscan_path() calls PlanRelScan() of the related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide a common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such a function, FDWs can update their statistics in their own respective ways.&lt;br /&gt;
&lt;br /&gt;
In version 1, the planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause for a column, and key/value pairs are stored in attfdwoptions of pg_attribute.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It might be able to be integrated with [http://www.postgresql.org/docs/9.1/static/dblink.html contrib/dblink] to share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from FDW options of foreign-data wrapper, foreign server and user mapping, with choosing only connection options because FDW option might include non-connection options such as relname and nspname.&lt;br /&gt;
Note that non-superuser MUST specify password in FDW options and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, FDW options of user mappings are visible to users who has SUPERUSER privilege or USAGE privilege on relevant SERVER, because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Cost estimation ===&lt;br /&gt;
ANALYZE for foreign tables is not supported in 9.0, so we can&#039;t store statistics in local PG.  One work around is getting EXPLAIN result from remote server, and use its cost values for local planning.&lt;br /&gt;
&lt;br /&gt;
=== SELECT-clause optimization ===&lt;br /&gt;
Currently SELECT clause is constructed as &amp;quot;SELECT col1, col2, col3, ...&amp;quot;. If some of columns are not used at all in the original query, they will be replaced with NULL for optimization.  For example, if col2 was unused, SELECT clause will be &amp;quot;SELECT col1, NULL, col3, ...&amp;quot;.  Main purpose of this optimization is to reduce amount of data transferred from remote server.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
&lt;br /&gt;
To push-down a condition, it must consist of only the following node types.  For this purpose, we check each element in RelOptInfo.baserestrictinfo list. If there are conditions which can&#039;t be pushed down, the remote server will send rows without the conditions, and the local server will evaluate the rows and ignore rows which don&#039;t satisfy the conditions.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, are configurable via FDW option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
We must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy and some overhead. Another solution is registering cleanup function to resource owner, and release PGresult in that cleanup function. This method has already been used to close libpq connection.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15988</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15988"/>
		<updated>2011-12-19T02:02:27Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Active Work In Progress */ update active works&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
Check out the list of all the [[foreign data wrappers]]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Add pgsql_fdw as a contrib module ==&lt;br /&gt;
[http://commitfest.postgresql.org/action/patch_view?id=667 &amp;quot;pgsql_fdw contrib module&amp;quot;] is under proposal at CF 2011-11.  The goal of this proposal is to add pgsql_fdw as a contrib module.&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.  For this purpose, [http://commitfest.postgresql.org/action/patch_view?id=661 &amp;quot;Collecting statistics on foreign tables&amp;quot;] is under proposal at CF 2011-11. This proposal provides handler function which allows FDWs to handle ANALYZE commands which is executed for foreign tables. In addition, contrib/file_fdw is enhanced to get sample rows from actual data file and calculate statistics by using existing routines in core.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause for a column, and key/value pairs are stored in attfdwoptions of pg_attribute.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It might be able to be integrated with [http://www.postgresql.org/docs/9.1/static/dblink.html contrib/dblink] to share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from FDW options of foreign-data wrapper, foreign server and user mapping, with choosing only connection options because FDW option might include non-connection options such as relname and nspname.&lt;br /&gt;
Note that non-superuser MUST specify password in FDW options and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, FDW options of user mappings are visible to users who has SUPERUSER privilege or USAGE privilege on relevant SERVER, because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Cost estimation ===&lt;br /&gt;
ANALYZE for foreign tables is not supported in 9.0, so we can&#039;t store statistics in local PG.  One work around is getting EXPLAIN result from remote server, and use its cost values for local planning.&lt;br /&gt;
&lt;br /&gt;
=== SELECT-clause optimization ===&lt;br /&gt;
Currently SELECT clause is constructed as &amp;quot;SELECT col1, col2, col3, ...&amp;quot;. If some of columns are not used at all in the original query, they will be replaced with NULL for optimization.  For example, if col2 was unused, SELECT clause will be &amp;quot;SELECT col1, NULL, col3, ...&amp;quot;.  Main purpose of this optimization is to reduce amount of data transferred from remote server.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
&lt;br /&gt;
To push-down a condition, it must consist of only the following node types.  For this purpose, we check each element in RelOptInfo.baserestrictinfo list. If there are conditions which can&#039;t be pushed down, the remote server will send rows without the conditions, and the local server will evaluate the rows and ignore rows which don&#039;t satisfy the conditions.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, are configurable via FDW option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
We must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy and some overhead. Another solution is registering cleanup function to resource owner, and release PGresult in that cleanup function. This method has already been used to close libpq connection.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15857</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15857"/>
		<updated>2011-11-24T07:06:21Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Active Work In Progress */ 9.2 supports per-column FDW options&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
Check out the list of all the [[foreign data wrappers]]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause for a column, and key/value pairs are stored in attfdwoptions of pg_attribute.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It might be able to be integrated with [http://www.postgresql.org/docs/9.1/static/dblink.html contrib/dblink] to share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from FDW options of foreign-data wrapper, foreign server and user mapping, with choosing only connection options because FDW option might include non-connection options such as relname and nspname.&lt;br /&gt;
Note that non-superuser MUST specify password in FDW options and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, FDW options of user mappings are visible to users who has SUPERUSER privilege or USAGE privilege on relevant SERVER, because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Cost estimation ===&lt;br /&gt;
ANALYZE for foreign tables is not supported in 9.0, so we can&#039;t store statistics in local PG.  One work around is getting EXPLAIN result from remote server, and use its cost values for local planning.&lt;br /&gt;
&lt;br /&gt;
=== SELECT-clause optimization ===&lt;br /&gt;
Currently SELECT clause is constructed as &amp;quot;SELECT col1, col2, col3, ...&amp;quot;. If some of columns are not used at all in the original query, they will be replaced with NULL for optimization.  For example, if col2 was unused, SELECT clause will be &amp;quot;SELECT col1, NULL, col3, ...&amp;quot;.  Main purpose of this optimization is to reduce amount of data transferred from remote server.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
&lt;br /&gt;
To push-down a condition, it must consist of only the following node types.  For this purpose, we check each element in RelOptInfo.baserestrictinfo list. If there are conditions which can&#039;t be pushed down, the remote server will send rows without the conditions, and the local server will evaluate the rows and ignore rows which don&#039;t satisfy the conditions.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, are configurable via FDW option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
We must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy and some overhead. Another solution is registering cleanup function to resource owner, and release PGresult in that cleanup function. This method has already been used to close libpq connection.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15856</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15856"/>
		<updated>2011-11-24T07:03:45Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Per-column FDW option */ move description about pg_attribute from &amp;quot;Active work&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
Check out the list of all the [[foreign data wrappers]]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause for a column, and key/value pairs are stored in attfdwoptions of pg_attribute.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It might be able to be integrated with [http://www.postgresql.org/docs/9.1/static/dblink.html contrib/dblink] to share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from FDW options of foreign-data wrapper, foreign server and user mapping, with choosing only connection options because FDW option might include non-connection options such as relname and nspname.&lt;br /&gt;
Note that non-superuser MUST specify password in FDW options and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, FDW options of user mappings are visible to users who has SUPERUSER privilege or USAGE privilege on relevant SERVER, because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Cost estimation ===&lt;br /&gt;
ANALYZE for foreign tables is not supported in 9.0, so we can&#039;t store statistics in local PG.  One work around is getting EXPLAIN result from remote server, and use its cost values for local planning.&lt;br /&gt;
&lt;br /&gt;
=== SELECT-clause optimization ===&lt;br /&gt;
Currently SELECT clause is constructed as &amp;quot;SELECT col1, col2, col3, ...&amp;quot;. If some of columns are not used at all in the original query, they will be replaced with NULL for optimization.  For example, if col2 was unused, SELECT clause will be &amp;quot;SELECT col1, NULL, col3, ...&amp;quot;.  Main purpose of this optimization is to reduce amount of data transferred from remote server.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
&lt;br /&gt;
To push-down a condition, it must consist of only the following node types.  For this purpose, we check each element in RelOptInfo.baserestrictinfo list. If there are conditions which can&#039;t be pushed down, the remote server will send rows without the conditions, and the local server will evaluate the rows and ignore rows which don&#039;t satisfy the conditions.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, are configurable via FDW option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
We must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy and some overhead. Another solution is registering cleanup function to resource owner, and release PGresult in that cleanup function. This method has already been used to close libpq connection.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15182</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15182"/>
		<updated>2011-08-22T07:46:42Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* PostgreSQL */ use remote costs for local planning&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It might be able to be integrated with [http://www.postgresql.org/docs/9.1/static/dblink.html contrib/dblink] to share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from FDW options of foreign-data wrapper, foreign server and user mapping, with choosing only connection options because FDW option might include non-connection options such as relname and nspname.&lt;br /&gt;
Note that non-superuser MUST specify password in FDW options and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, FDW options of user mappings are visible to users who has SUPERUSER privilege or USAGE privilege on relevant SERVER, because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Cost estimation ===&lt;br /&gt;
ANALYZE for foreign tables is not supported in 9.0, so we can&#039;t store statistics in local PG.  One work around is getting EXPLAIN result from remote server, and use its cost values for local planning.&lt;br /&gt;
&lt;br /&gt;
=== SELECT-clause optimization ===&lt;br /&gt;
Currently SELECT clause is constructed as &amp;quot;SELECT col1, col2, col3, ...&amp;quot;. If some of columns are not used at all in the original query, they will be replaced with NULL for optimization.  For example, if col2 was unused, SELECT clause will be &amp;quot;SELECT col1, NULL, col3, ...&amp;quot;.  Main purpose of this optimization is to reduce amount of data transferred from remote server.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
&lt;br /&gt;
To push-down a condition, it must consist of only the following node types.  For this purpose, we check each element in RelOptInfo.baserestrictinfo list. If there are conditions which can&#039;t be pushed down, the remote server will send rows without the conditions, and the local server will evaluate the rows and ignore rows which don&#039;t satisfy the conditions.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, are configurable via FDW option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
We must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy and some overhead. Another solution is registering cleanup function to resource owner, and release PGresult in that cleanup function. This method has already been used to close libpq connection.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15127</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15127"/>
		<updated>2011-08-12T02:17:13Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* WHERE-clause push-down */ use baserestrictinfo for push-down&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It might be able to be integrated with [http://www.postgresql.org/docs/9.1/static/dblink.html contrib/dblink] to share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from FDW options of foreign-data wrapper, foreign server and user mapping, with choosing only connection options because FDW option might include non-connection options such as relname and nspname.&lt;br /&gt;
Note that non-superuser MUST specify password in FDW options and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, FDW options of user mappings are visible to users who has SUPERUSER privilege or USAGE privilege on relevant SERVER, because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== SELECT-clause optimization ===&lt;br /&gt;
Currently SELECT clause is constructed as &amp;quot;SELECT col1, col2, col3, ...&amp;quot;. If some of columns are not used at all in the original query, they will be replaced with NULL for optimization.  For example, if col2 was unused, SELECT clause will be &amp;quot;SELECT col1, NULL, col3, ...&amp;quot;.  Main purpose of this optimization is to reduce amount of data transferred from remote server.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
&lt;br /&gt;
To push-down a condition, it must consist of only the following node types.  For this purpose, we check each element in RelOptInfo.baserestrictinfo list. If there are conditions which can&#039;t be pushed down, the remote server will send rows without the conditions, and the local server will evaluate the rows and ignore rows which don&#039;t satisfy the conditions.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, are configurable via FDW option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
We must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy and some overhead. Another solution is registering cleanup function to resource owner, and release PGresult in that cleanup function. This method has already been used to close libpq connection.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15126</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15126"/>
		<updated>2011-08-12T02:04:15Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* WHERE-clause push-down */ separate SELECT-clause optimization&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It might be able to be integrated with [http://www.postgresql.org/docs/9.1/static/dblink.html contrib/dblink] to share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from FDW options of foreign-data wrapper, foreign server and user mapping, with choosing only connection options because FDW option might include non-connection options such as relname and nspname.&lt;br /&gt;
Note that non-superuser MUST specify password in FDW options and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, FDW options of user mappings are visible to users who has SUPERUSER privilege or USAGE privilege on relevant SERVER, because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== SELECT-clause optimization ===&lt;br /&gt;
Currently SELECT clause is constructed as &amp;quot;SELECT col1, col2, col3, ...&amp;quot;. If some of columns are not used at all in the original query, they will be replaced with NULL for optimization.  For example, if col2 was unused, SELECT clause will be &amp;quot;SELECT col1, NULL, col3, ...&amp;quot;.  Main purpose of this optimization is to reduce amount of data transferred from remote server.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, are configurable via FDW option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
We must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy and some overhead. Another solution is registering cleanup function to resource owner, and release PGresult in that cleanup function. This method has already been used to close libpq connection.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15125</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15125"/>
		<updated>2011-08-12T01:45:59Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* PostgreSQL */ follow recent updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It might be able to be integrated with [http://www.postgresql.org/docs/9.1/static/dblink.html contrib/dblink] to share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from FDW options of foreign-data wrapper, foreign server and user mapping, with choosing only connection options because FDW option might include non-connection options such as relname and nspname.&lt;br /&gt;
Note that non-superuser MUST specify password in FDW options and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, FDW options of user mappings are visible to users who has SUPERUSER privilege or USAGE privilege on relevant SERVER, because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, are configurable via FDW option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
We must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy and some overhead. Another solution is registering cleanup function to resource owner, and release PGresult in that cleanup function. This method has already been used to close libpq connection.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15124</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15124"/>
		<updated>2011-08-12T01:33:05Z</updated>

		<summary type="html">&lt;p&gt;Hanada: per-column FDW options has been committed.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, can be specified as generic option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
Anyway, we must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy. Another solution is registering cleanup function to resource owner, and release PGresult in the function. This method has already been used to close libpq connection.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15078</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15078"/>
		<updated>2011-08-05T06:17:58Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Retrieving result tuples */ resource owner can be used to cleanup PGresult&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, can be specified as generic option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
Anyway, we must ensure that PGresult is released explicitly in any case because libpq uses malloc rather than palloc. Copying results into a Tuplestorestate is a solution, which is used in contrib/dblink, but it needs extra memory during the copy. Another solution is registering cleanup function to resource owner, and release PGresult in the function. This method has already been used to close libpq connection.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15077</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15077"/>
		<updated>2011-08-05T04:59:26Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* for SQL-based FDWs */ pushing internal parameter down seems difficult&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, can be specified as generic option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
Anyway, received tuples have to be copied into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory.  Further research might show us an another solution.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
: This seems difficult in some cases, because value of internal parameter is determined &#039;&#039;&#039;after&#039;&#039;&#039; fetching tuple from a relation.&lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15076</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15076"/>
		<updated>2011-08-05T04:55:42Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* General */ now file_fdw shares exported COPY FROM routines&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, can be specified as generic option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
Anyway, received tuples have to be copied into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory.  Further research might show us an another solution.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15075</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15075"/>
		<updated>2011-08-05T04:54:40Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* DML */ execute-time constraint has benn removed from proposal&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, can be specified as generic option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
Anyway, received tuples have to be copied into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory.  Further research might show us an another solution.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15074</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15074"/>
		<updated>2011-08-05T04:52:41Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Open questions */ mark some questions closed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, can be specified as generic option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
Anyway, received tuples have to be copied into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory.  Further research might show us an another solution.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
== Resolved questions ==&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
: &#039;&#039;&#039;In 9.1, locking foreign table is not supported.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint(not implemented)&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns can be evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15073</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15073"/>
		<updated>2011-08-05T04:44:28Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Retrieving all tuples at once */ pgsql_fdw uses cursor for huge result&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving result tuples ===&lt;br /&gt;
This FDW switches method for retrieving result tuples according to estimated # of result rows.&lt;br /&gt;
&lt;br /&gt;
If the estimated rows is less than the threshold, simple SELECT is used to retrieve all result at once in first call of Iterate() after Begin() or ReScan().  Otherwise, SQL-level cursor is created in that place, and result rows are retrieved when they were necessary.&lt;br /&gt;
&lt;br /&gt;
Two numbers, minimum # of rows to use cursor and # of rows fetched in one FETCH call, can be specified as generic option of SERVER and/or FOREIGN TABLE.  If a option was specified on both object, latter overrides former.&lt;br /&gt;
&lt;br /&gt;
Anyway, received tuples have to be copied into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory.  Further research might show us an another solution.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint(not implemented)&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns can be evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15072</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15072"/>
		<updated>2011-08-05T04:18:05Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* file_fdw */ describe what has been done for file_fdw&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
The file_fdw is a foreign-data wrapper implementation, and included in the distribution of PostgreSQL 9.1 as a contrib module.  This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw can recognize the file formats which are recognized by COPY command, by using exported COPY FROM routines.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving all tuples at once ===&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint(not implemented)&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns can be evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15071</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15071"/>
		<updated>2011-08-05T03:16:30Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Active Work In Progress */ clarify that each work item is done or undone&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
== Per-column FDW option ==&lt;br /&gt;
Similar to other kind of FDW objects, column of a foreign table can have FDW options.  This means that CREATE/ALTER FOREIGN TABLE syntax accept OPTIONS clause, and key/value pairs are stored in catalog.&lt;br /&gt;
&lt;br /&gt;
Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute need to have new column attfdwoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Table partioning ==&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
== Smart planning ==&lt;br /&gt;
* We might have statistics of external data.  ANALYZE command would need to have hook  to delegate row sampling to each FDW.&lt;br /&gt;
* set_foreign_size_estimates() have to be enhanced to reflect actual statistics.&lt;br /&gt;
== JOIN push down ==&lt;br /&gt;
Doing a (or more) JOIN on remote side would reduce amount of data transferred from external server.&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Finished works =&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ NOT NULL ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables can have generic options with OPTIONS syntax.&lt;br /&gt;
&lt;br /&gt;
In first version, column DEFAULT value and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
=== Version 3 ===&lt;br /&gt;
Finally FDW API has been defined in PostgreSQL 9.1 as below:&lt;br /&gt;
 typedef FdwPlan *(*PlanForeignScan_function) (Oid foreigntableid,&lt;br /&gt;
                                                           PlannerInfo *root,&lt;br /&gt;
                                                         RelOptInfo *baserel);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ExplainForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                     struct ExplainState *es);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*BeginForeignScan_function) (ForeignScanState *node,&lt;br /&gt;
                                                        int eflags);&lt;br /&gt;
 &lt;br /&gt;
 typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*ReScanForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef void (*EndForeignScan_function) (ForeignScanState *node);&lt;br /&gt;
 &lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     NodeTag     type;&lt;br /&gt;
 &lt;br /&gt;
     PlanForeignScan_function PlanForeignScan;&lt;br /&gt;
     ExplainForeignScan_function ExplainForeignScan;&lt;br /&gt;
     BeginForeignScan_function BeginForeignScan;&lt;br /&gt;
     IterateForeignScan_function IterateForeignScan;&lt;br /&gt;
     ReScanForeignScan_function ReScanForeignScan;&lt;br /&gt;
     EndForeignScan_function EndForeignScan;&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     bool        fsSystemCol;&lt;br /&gt;
     struct FdwPlan *fdwplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     struct FdwRoutine     *fdwroutine;&lt;br /&gt;
     void *fdw_state;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fdw_state-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw uses the file formats which are recognized by COPY command, so exporting COPY FROM routines would help implementing file_fdw.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving all tuples at once ===&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint(not implemented)&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns can be evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15070</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15070"/>
		<updated>2011-08-05T02:45:29Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Built-in foreign data wrappers */ move to upper level&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
 In first version, syntax for defining column level generic option would be omitted.&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     FdwPlan    *fplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     FdwExecutionState *fstate;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fstate-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Foreign data wrappers =&lt;br /&gt;
== file_fdw ==&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
=== using COPY FROM routines ===&lt;br /&gt;
File_fdw uses the file formats which are recognized by COPY command, so exporting COPY FROM routines would help implementing file_fdw.&lt;br /&gt;
&lt;br /&gt;
=== generic options ===&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
=== Connection options ===&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
=== No transaction management ===&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
=== WHERE-clause push-down ===&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
=== Retrieving all tuples at once ===&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint(not implemented)&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns can be evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15069</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15069"/>
		<updated>2011-08-05T02:41:48Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Active Work In Progress */ remove WIP code disclosure&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
 In first version, syntax for defining column level generic option would be omitted.&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     FdwPlan    *fplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     FdwExecutionState *fstate;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fstate-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== using COPY FROM routines ====&lt;br /&gt;
File_fdw uses the file formats which are recognized by COPY command, so exporting COPY FROM routines would help implementing file_fdw.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint(not implemented)&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns can be evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15068</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=15068"/>
		<updated>2011-08-05T02:33:57Z</updated>

		<summary type="html">&lt;p&gt;Hanada: add to category PostgreSQL 9.2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
 In first version, syntax for defining column level generic option would be omitted.&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     FdwPlan    *fplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     FdwExecutionState *fstate;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fstate-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== using COPY FROM routines ====&lt;br /&gt;
File_fdw uses the file formats which are recognized by COPY command, so exporting COPY FROM routines would help implementing file_fdw.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint(not implemented)&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns can be evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;br /&gt;
[[Category:PostgreSQL 9.2]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=13333</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=13333"/>
		<updated>2011-03-15T04:16:25Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Current Status */ some features have been merged into core&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
Basic features have been merged in PostgreSQL 9.1Alpha4.&lt;br /&gt;
*Make foreign data wrapper functional&lt;br /&gt;
*Support FOREIGN TABLEs&lt;br /&gt;
contrib/file_fdw is available to retrieve external data from server-side files.&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
 In first version, syntax for defining column level generic option would be omitted.&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     FdwPlan    *fplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     FdwExecutionState *fstate;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fstate-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== using COPY FROM routines ====&lt;br /&gt;
File_fdw uses the file formats which are recognized by COPY command, so exporting COPY FROM routines would help implementing file_fdw.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint(not implemented)&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns can be evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;br /&gt;
[[Category:PostgreSQL 9.1]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12860</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12860"/>
		<updated>2010-12-24T07:49:33Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* file_fdw */ mention about exporting COPY FROM routines&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
 In first version, syntax for defining column level generic option would be omitted.&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     FdwPlan    *fplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     FdwExecutionState *fstate;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fstate-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create or alter foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== using COPY FROM routines ====&lt;br /&gt;
File_fdw uses the file formats which are recognized by COPY command, so exporting COPY FROM routines would help implementing file_fdw.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
Different from COPY, the &#039;&#039;force_not_null&#039;&#039; can be described in per-column generic option with boolean values, not a list of column names.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint(not implemented)&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns can be evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12859</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12859"/>
		<updated>2010-12-24T07:43:50Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* DML */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
 In first version, syntax for defining column level generic option would be omitted.&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     FdwPlan    *fplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     FdwExecutionState *fstate;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fstate-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which is read from per-column generic option.  It should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint(not implemented)&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns can be evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12858</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12858"/>
		<updated>2010-12-24T07:36:20Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Planner */ move ForeignScan from Executor section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
 In first version, syntax for defining column level generic option would be omitted.&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
In version 1, planner generates a ForeignScan node for each foreign table in the query, and store FdwPlan in it which is returned by PlanRelScan().&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
     FdwPlan    *fplan;&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     FdwExecutionState *fstate;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fstate-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which is read from per-column generic option.  It should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12857</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12857"/>
		<updated>2010-12-24T07:33:37Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Executor */ use new FdwRoutine&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
 In first version, syntax for defining column level generic option would be omitted.&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Create ForeignScanState for the given ForeignScan plan node.&lt;br /&gt;
:Call FdwRoutine.BeginScan() with FdwPlan which was stored in ForeignScan to initiate foreign query if the execution was not for EXPLAIN, and receive FdwExecutionState.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table via TupleTableSlot.&lt;br /&gt;
:If the scan reaches the end, the slot will be empty after Iterate() call.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReScan() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.EndScan() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     FdwExecutionState *fstate;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwExecutionState has private area which can be used to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.fstate-&amp;gt;private.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which is read from per-column generic option.  It should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12856</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12856"/>
		<updated>2010-12-24T07:15:28Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Planner */ PlanRelScan() is called from create_foreignscan_path()&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
 In first version, syntax for defining column level generic option would be omitted.&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, create_foreignscan_path() calls PlanRelScan() of related FDW&#039;s FdwRoutine for each ForeignScan node.  PlanRelScan() should provide proper costs for the scan which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
In future, additional planner hooks might be added for:&lt;br /&gt;
&lt;br /&gt;
# Pass-through mode (one ForeignScan node executes whole query)&lt;br /&gt;
# Query optimization such as merging multiple foreign tables into one remote query&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which is read from per-column generic option.  It should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12841</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12841"/>
		<updated>2010-12-21T08:04:32Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* pg_catalog.pg_attribute */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
 In first version, syntax for defining column level generic option would be omitted.&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, cost_foreignscan() calls EstimateCosts() of related FDW&#039;s FdwRoutine for each ForeignScan node.&lt;br /&gt;
&lt;br /&gt;
EstimateCosts() should provide proper costs which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which is read from per-column generic option.  It should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12840</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12840"/>
		<updated>2010-12-21T07:58:14Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* FDW routines */ new FdwRoutine was proposed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
=== Version 1 ===&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
=== Version 2 ===&lt;br /&gt;
Per discussion and [http://archives.postgresql.org/pgsql-hackers/2010-11/msg01713.php Heikki Linnakangas&#039;s proposal], FdwRoutine was changed in some points:&lt;br /&gt;
&lt;br /&gt;
* Add FdwPlan as container of FDW-specific planning information.&lt;br /&gt;
* Add FdwExecutionState as container of FD-specific execution information.&lt;br /&gt;
* Connection management is left to each FDW, because simple FDW, such as file wrapper, would not need connection&lt;br /&gt;
* Add planner hook which allow FDWs to generate FDW-specific plan from RelOptInfo and other information.  That plan will be passed to BeginScan() to execute the scan.&lt;br /&gt;
&lt;br /&gt;
 struct FdwPlan {&lt;br /&gt;
     NodeTag type;           /* FdwPlan need copyObject() support for plan&lt;br /&gt;
                                caching */&lt;br /&gt;
     char *explainInfo;      /* FDW-specific info shown in EXPLAIN VERBOSE */&lt;br /&gt;
     double startup_cost;    /* Optimizer needs costs for each path */&lt;br /&gt;
     double total_cost;&lt;br /&gt;
     List *private;          /* FDW can store private data as copy-able objects */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwExecutionState&lt;br /&gt;
 {&lt;br /&gt;
     void *private;          /* FDW-private data */&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
 #ifdef IN_THE_FUTURE&lt;br /&gt;
     FdwPlan *(*PlanNative)(Oid serverid, char *query);&lt;br /&gt;
     FdwPlan *(*PlanQuery)(PlannerInfo *root, Query query);&lt;br /&gt;
 #endif&lt;br /&gt;
     FdwPlan *(*PlanRelScan)(Oid foreigntableid, PlannerInfo *root,&lt;br /&gt;
                             RelOptInfo *baserel);&lt;br /&gt;
     FdwExecutionState *(*BeginScan)(FdwPlan *plan, ParamListInfo params);&lt;br /&gt;
     void (*Iterate)(FdwExecutionState *state, TupleTableSlot *slot);&lt;br /&gt;
     void (*ReScan)(FdwExecutionState *state);&lt;br /&gt;
     void (*EndScan)(FdwExecutionState *state);&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
In future, more planner hook might be added to allow FDWs to optimize the query.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, cost_foreignscan() calls EstimateCosts() of related FDW&#039;s FdwRoutine for each ForeignScan node.&lt;br /&gt;
&lt;br /&gt;
EstimateCosts() should provide proper costs which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which is read from per-column generic option.  It should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12839</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12839"/>
		<updated>2010-12-21T07:18:22Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Syntax */ simplified syntax for version 1&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW handler function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with FDW handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
In first version, NOT NULL constraint, column DEFAULT value,  and column level options are omitted to simplify the patch and make review easy.&lt;br /&gt;
[http://archives.postgresql.org/pgsql-hackers/2010-12/msg01168.php hackers-ML archive]&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, cost_foreignscan() calls EstimateCosts() of related FDW&#039;s FdwRoutine for each ForeignScan node.&lt;br /&gt;
&lt;br /&gt;
EstimateCosts() should provide proper costs which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which is read from per-column generic option.  It should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12838</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12838"/>
		<updated>2010-12-21T06:56:43Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Active Work In Progress */ separate fdw_core into two&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_syntax&#039;&#039;&#039; branch contains syntax of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;fdw_scan&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW connector function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with connection handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, cost_foreignscan() calls EstimateCosts() of related FDW&#039;s FdwRoutine for each ForeignScan node.&lt;br /&gt;
&lt;br /&gt;
EstimateCosts() should provide proper costs which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which is read from per-column generic option.  It should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12543</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12543"/>
		<updated>2010-11-25T09:00:26Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* file_fdw */ file_fdw is a contrib module now, and doesn&amp;#039;t support oids&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_core&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW connector function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with connection handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, cost_foreignscan() calls EstimateCosts() of related FDW&#039;s FdwRoutine for each ForeignScan node.&lt;br /&gt;
&lt;br /&gt;
EstimateCosts() should provide proper costs which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented as a contrib module.&lt;br /&gt;
Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable, but &#039;&#039;oids&#039;&#039; is not supported by file_fdw because it&#039;s a legacy feature.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which is read from per-column generic option.  It should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12542</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12542"/>
		<updated>2010-11-25T08:18:56Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Active Work In Progress */ fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_core&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;pgsql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW connector function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with connection handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, cost_foreignscan() calls EstimateCosts() of related FDW&#039;s FdwRoutine for each ForeignScan node.&lt;br /&gt;
&lt;br /&gt;
EstimateCosts() should provide proper costs which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented in the core, initially installed on initdb.  Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable except &#039;&#039;oids&#039;&#039;.  The first column of the file is treated as oid automatically if the foreign table has been defined with &amp;quot;WITH OIDS&amp;quot; option.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which has been changed from COPY FROM option.  &#039;&#039;force_not_null&#039;&#039; should be specified in per-column generic option and should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12541</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12541"/>
		<updated>2010-11-25T08:17:50Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Active Work In Progress */ chage names of git branch for development&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_core&#039;&#039;&#039; branch contains core funcionality of SQL/MED&lt;br /&gt;
* &#039;&#039;&#039;postgresql_fdw&#039;&#039;&#039; branch contains FDW for external PostgreSQL servers&lt;br /&gt;
* &#039;&#039;&#039;file_fdw&#039;&#039;&#039; branch contains FDW for flat files&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW connector function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with connection handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, cost_foreignscan() calls EstimateCosts() of related FDW&#039;s FdwRoutine for each ForeignScan node.&lt;br /&gt;
&lt;br /&gt;
EstimateCosts() should provide proper costs which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented in the core, initially installed on initdb.  Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable except &#039;&#039;oids&#039;&#039;.  The first column of the file is treated as oid automatically if the foreign table has been defined with &amp;quot;WITH OIDS&amp;quot; option.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which has been changed from COPY FROM option.  &#039;&#039;force_not_null&#039;&#039; should be specified in per-column generic option and should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12496</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12496"/>
		<updated>2010-11-18T12:41:39Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* file_fdw */ oids option has gone&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_select_simple&#039;&#039;&#039; branch contains minimal implementation of SQL/MED query support.&lt;br /&gt;
* &#039;&#039;&#039;fdw_table&#039;&#039;&#039; branch contains all features proposed.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW connector function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with connection handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, cost_foreignscan() calls EstimateCosts() of related FDW&#039;s FdwRoutine for each ForeignScan node.&lt;br /&gt;
&lt;br /&gt;
EstimateCosts() should provide proper costs which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented in the core, initially installed on initdb.  Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
Information of the source file such as filename are passed via generic options.  Options of COPY FROM statement are acceptable except &#039;&#039;oids&#039;&#039;.  The first column of the file is treated as oid automatically if the foreign table has been defined with &amp;quot;WITH OIDS&amp;quot; option.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;force_not_null&#039;&#039; is the only option which has been changed from COPY FROM option.  &#039;&#039;force_not_null&#039;&#039; should be specified in per-column generic option and should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12481</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12481"/>
		<updated>2010-11-17T06:39:13Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* FDW routines */ add BeginScan() for initiation of scan&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_select_simple&#039;&#039;&#039; branch contains minimal implementation of SQL/MED query support.&lt;br /&gt;
* &#039;&#039;&#039;fdw_table&#039;&#039;&#039; branch contains all features proposed.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW connector function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with connection handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*BeginScan)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, cost_foreignscan() calls EstimateCosts() of related FDW&#039;s FdwRoutine for each ForeignScan node.&lt;br /&gt;
&lt;br /&gt;
EstimateCosts() should provide proper costs which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented in the core, initially installed on initdb.  Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
The file name is passed with &#039;&#039;filename&#039;&#039; generic option, and options which are valid in COPY FROM statement are also acceptable.  The &#039;&#039;force_not_null&#039;&#039; is the only option which has been changed from COPY option; it should be specified in per-column generic option and should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
	<entry>
		<id>https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12480</id>
		<title>SQL/MED</title>
		<link rel="alternate" type="text/html" href="https://wiki.postgresql.org/index.php?title=SQL/MED&amp;diff=12480"/>
		<updated>2010-11-17T06:37:53Z</updated>

		<summary type="html">&lt;p&gt;Hanada: /* Active Work In Progress */ removed wrong link to git branch&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;SQL/MED&#039;&#039;&#039; is Management of External Data, a part of the SQL standard that deals with how a database management system can integrate data stored outside the database. There are two components in SQL/MED:&lt;br /&gt;
&lt;br /&gt;
; Foreign Table&lt;br /&gt;
: a transparent access method for external data&lt;br /&gt;
; [[DATALINK]]&lt;br /&gt;
: a special SQL type intended to store URLs in database&lt;br /&gt;
&lt;br /&gt;
= Current Status =&lt;br /&gt;
The implementation of this specification has begun in PostgreSQL 8.4 and will over time introduce powerful new features into PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
* [http://www.pgcon.org/2009/schedule/events/142.en.html SQL/MED:  Doping for PostgreSQL]&lt;br /&gt;
* [http://developer.postgresql.org/pgdocs/postgres/sql-createforeigndatawrapper.html CREATE FOREIGN DATA WRAPPER]&lt;br /&gt;
&lt;br /&gt;
= Active Work In Progress =&lt;br /&gt;
This is a project for PostgreSQL 9.1 to add FDW routines into foreign data wrappers so that we can retrieve data from foreign servers through foreign tables. The syntax for them should be same as for normal local tables.&lt;br /&gt;
&lt;br /&gt;
WIP codes are available at: http://git.postgresql.org/gitweb?p=users/hanada/postgres.git;a=summary&lt;br /&gt;
* &#039;&#039;&#039;master&#039;&#039;&#039; branch is a copy of postgres&#039; HEAD.&lt;br /&gt;
* &#039;&#039;&#039;fdw_select_simple&#039;&#039;&#039; branch contains minimal implementation of SQL/MED query support.&lt;br /&gt;
* &#039;&#039;&#039;fdw_table&#039;&#039;&#039; branch contains all features proposed.&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
In SQL standard, &#039;CREATE FOREIGN DATA WRAPPER&#039; have &#039;LIBRARY&#039; option and FDW routines are exported directly from the library, but another approach like &#039;[http://developer.postgresql.org/pgdocs/postgres/sql-createlanguage.html CREATE LANGUAGE]&#039; would be better because we already have pg_proc, an existing function manager.&lt;br /&gt;
&lt;br /&gt;
 -- Register a function that returns FDW connector function set.&lt;br /&gt;
 CREATE FUNCTION postgresql_fdw_handler() RETURNS fdw_handler&lt;br /&gt;
   AS &#039;MODULE_PATHNAME&#039;&lt;br /&gt;
   LANGUAGE C;&lt;br /&gt;
 &lt;br /&gt;
 -- Create a foreign data wrapper with connection handler.&lt;br /&gt;
 CREATE FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   HANDLER postgresql_fdw_handler&lt;br /&gt;
   VALIDATOR postgresql_fdw_validator;&lt;br /&gt;
CREATE FOREIGN DATA WRAPPER has now HANDLER clause, which is used to specify the handler function to be used to access external data.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign server.&lt;br /&gt;
 CREATE SERVER remote_postgresql_server&lt;br /&gt;
   FOREIGN DATA WRAPPER postgresql&lt;br /&gt;
   OPTIONS ( host &#039;somehost&#039;, port 5432, dbname &#039;remotedb&#039; );&lt;br /&gt;
 &lt;br /&gt;
 -- Create a user mapping.&lt;br /&gt;
 CREATE USER MAPPING FOR postgres&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( user &#039;someuser&#039;, password &#039;secret&#039; );&lt;br /&gt;
These two statements are not changed.&lt;br /&gt;
&lt;br /&gt;
 -- Create a foreign table.&lt;br /&gt;
 CREATE FOREIGN TABLE schemaname.tablename (&lt;br /&gt;
     column_name &#039;&#039;type_name&#039;&#039; [ OPTIONS ( ... ) ] [ &#039;&#039;constraints&#039;&#039; | DEFAULT &#039;&#039;default value&#039;&#039; [...] ],&lt;br /&gt;
     ...&lt;br /&gt;
   )&lt;br /&gt;
   INHERTIS ( parent )&lt;br /&gt;
   SERVER remote_postgresql_server&lt;br /&gt;
   OPTIONS ( ... );&lt;br /&gt;
&lt;br /&gt;
Foreign tables should support inheritance and [[table partitioning]] for scale-out [[clustering]]. The main parent table is partitioned into multiple foreign tables, and each foreign table is connected to different foreign servers. It can be used like as [[PL/Proxy#Partitioned remote function call|partitioned remote function call]] in [[PL/Proxy]].&lt;br /&gt;
&lt;br /&gt;
Foreign tables and columns of foreign tables can have generic options with OPTIONS syntax.  Because of syntax vagueness between &amp;quot;DEFAULT b_expr&amp;quot; and &amp;quot;OPTIONS ( ... )&amp;quot;, OPTIONS clause for a column must be specified before any constraints or default value.&lt;br /&gt;
&lt;br /&gt;
== FDW routines ==&lt;br /&gt;
In SQL standard, FDW routines are designed to have portable application binary interface. FDW libraries could be used by several DBMSes without recompiling there, but it doesn&#039;t seem realistic. Instead, PostgreSQL-specific and C language-specific routine set would be feasible:&lt;br /&gt;
&lt;br /&gt;
 /* FDW interface routines */&lt;br /&gt;
 typedef struct FdwRoutine&lt;br /&gt;
 {&lt;br /&gt;
     FSConnection * (*ConnectServer)(ForeignServer *server, UserMapping *user);&lt;br /&gt;
     void           (*FreeFSConnection)(FSConnection *conn);&lt;br /&gt;
     void           (*EstimateCosts(ForeignPath *path, PlannerInfo *root, RelOptInfo *baserel);&lt;br /&gt;
     void           (*Open)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Iterate)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*Close)(ForeignScanState *scanstate);&lt;br /&gt;
     void           (*ReOpen)(ForeignScanState *scanstate);&lt;br /&gt;
 } FdwRoutine;&lt;br /&gt;
&lt;br /&gt;
FDW routines are designed to be used in the executor module. The executor seems to be the best-balanced layer for query optimization and data abstraction. It would be harder with other approaches like AM (access methods) or storage manager (smgr) layers to optimize complex queries like JOIN several foreign tables in the same foreign server.&lt;br /&gt;
&lt;br /&gt;
Only interfaces of FdwRoutine, FSConnection are defined in PostgreSQL core, and the actual contents are implemented by each FDW library.&lt;br /&gt;
&lt;br /&gt;
In contrast, ForeignServer and UserMapping are implemented in core.&lt;br /&gt;
&lt;br /&gt;
== On-disk structure ==&lt;br /&gt;
=== pg_catalog.pg_foreign_data_wrapper ===&lt;br /&gt;
A FDW handler function returns FDW routine set. A new pseudo type &#039;fdw_handler&#039; is added to represent the routine set. FDW handlers take no arguments and return fdw_handler type.&lt;br /&gt;
&lt;br /&gt;
A FDW handler is registered in fdwhandler column of pg_foreign_data_wrapper catalog.  InvalidOid for fdwhandler means that the foreign-data wrapper has no FDW handler, so it can&#039;t be used to define any foreign table.  This specification supports usage in which foreign-data wrapper is used as container of connection information like the past.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_data_wrapper (&lt;br /&gt;
     fdwname      name      NOT NULL UNIQUE,&lt;br /&gt;
     fdwowner     oid       NOT NULL REFERENCES pg_authid (oid),&lt;br /&gt;
     fdwvalidator oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwhandler   oid       NOT NULL REFERENCES pg_proc (oid),&lt;br /&gt;
     fdwacl       aclitem[],&lt;br /&gt;
     fdwoptions   text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITH OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_foreign_table ===&lt;br /&gt;
A foreign table is registered in pg_class with relkind = &#039;f&#039; (RELKIND_FOREIGN_TABLE). It also has a corresponding pg_foreign_table tuple, in that we store the foreign server id and generic options for the foreign table.&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE pg_catalog.pg_foreign_table (&lt;br /&gt;
     ftrelid   oid    PRIMARY KEY REFERENCES pg_class (oid),&lt;br /&gt;
     ftserver  oid    NOT NULL REFERENCES pg_foreign_server (oid),&lt;br /&gt;
     ftoptions text[]&lt;br /&gt;
 )&lt;br /&gt;
 WITHOUT OIDS;&lt;br /&gt;
&lt;br /&gt;
=== pg_catalog.pg_attribute ===&lt;br /&gt;
To store per-column generic options, pg_attribute has new column attgenoptions which has been typed text[].&lt;br /&gt;
&lt;br /&gt;
== Planner and Executor changes ==&lt;br /&gt;
The access layer of foreign tables will be implemented in the planner module and the executor module. We will have new ForeignPath and ForeignScan nodes for the purpose.&lt;br /&gt;
&lt;br /&gt;
=== Planner ===&lt;br /&gt;
The Planner module is responsible to find the best access path, so FDW should provide the cost for a ForeignPath.&lt;br /&gt;
&lt;br /&gt;
In planning phase, cost_foreignscan() calls EstimateCosts() of related FDW&#039;s FdwRoutine for each ForeignScan node.&lt;br /&gt;
&lt;br /&gt;
EstimateCosts() should provide proper costs which have been estimated in the way each FDW would like to use.&lt;br /&gt;
&lt;br /&gt;
To estimate costs as correctly as possible, FDWs might want to have their own statistics.  In this step, we don&#039;t provide common mechanism to store statistics.  Once such mechanism has been implemented, FdwRoutine should have another function which is called from ANALYZE.  With such function, FDW can update their statistics in their way.&lt;br /&gt;
&lt;br /&gt;
=== Executor ===&lt;br /&gt;
The Executor module executes ForeignScan nodes with calling FDW routines.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScan&lt;br /&gt;
 {&lt;br /&gt;
     Scan        scan;&lt;br /&gt;
 &lt;br /&gt;
     /* no additional fields now, but might be added later */&lt;br /&gt;
 } ForeignScan;&lt;br /&gt;
&lt;br /&gt;
;ExecInitForeignScan()&lt;br /&gt;
:Collect catalog information about the foreign table.&lt;br /&gt;
:Connect to the foreign server if needed (see [[SQL/MED#Connection caching|connection caching]] for detail).&lt;br /&gt;
:Call FdwRoutine.Open() to prepare to execute query such as deparsing SQL and so on.&lt;br /&gt;
;ExecForeignScan()&lt;br /&gt;
:Call FdwRoutine.Iterate() to retrieve a tuple from the foreign table.&lt;br /&gt;
;ExecForeignReScan()&lt;br /&gt;
:Call FdwRoutine.ReOpen() to re-initialize scanning.&lt;br /&gt;
;ExecEndScan()&lt;br /&gt;
:Call FdwRoutine.Close() to finalize the foreign scan.&lt;br /&gt;
;ExecForeignMarkPos()/ExecForeignRestrPos()&lt;br /&gt;
:Currently MarkPos() and RestrPos() for ForeignScan are not supported, so ExecSupportsMarkRestore() returns false　for ForeignScan.  The reason not to support is that they are used to perform merge join, and merge join needs sorted results.  If a FDW could deparse Sort nodes into ORDER BY clause properly and supports MarkPos() and RestrPos(), then merge join of foreign tables are supported.&lt;br /&gt;
&lt;br /&gt;
ExecInitForeignScan() generates ForeignScanState from ForeignScan and FDW routines use it to manage the status of scan.&lt;br /&gt;
&lt;br /&gt;
 typedef struct ForeignScanState&lt;br /&gt;
 {&lt;br /&gt;
     ScanState       ss;&lt;br /&gt;
     FdwRoutine     *routine;&lt;br /&gt;
     ForeignDataWrapper *wrapper;&lt;br /&gt;
     ForeignServer  *server;&lt;br /&gt;
     FSConnection   *conn;&lt;br /&gt;
     UserMapping    *user;&lt;br /&gt;
     ForeignTable   *table;&lt;br /&gt;
     FdwReply       *reply;&lt;br /&gt;
 } ForeignScanState;&lt;br /&gt;
&lt;br /&gt;
FdwReply is an abstract type to pass foreign-data wrapper specific data between FDW routines.  Each foreign-data wrapper can define private data structure and store it into ForeignScanState.reply with casting to FdwReply.&lt;br /&gt;
&lt;br /&gt;
== Connection caching ==&lt;br /&gt;
 Currently, connection caching is not been implemented to focus on FDW API.  Ideas below once had been implemented but have been removed.&lt;br /&gt;
&lt;br /&gt;
Connections to foreign servers are cached and reused during the lifetime of the backend.  When a scanning to a foreign table is initialized at ExecInitForeignScan(), the backend searches the reusable connection from cache.  If reusable connection is not in cache, then call FdwRoutine.ConnectServer() to get concrete connection and store it in the connection cache.&lt;br /&gt;
&lt;br /&gt;
Connections are identified by name.  A connection&#039;s name is same as the name of the server which the connection use.&lt;br /&gt;
&lt;br /&gt;
The pg_foreign_connections view displays all the foreign connections that are available in the current session.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
!Name&lt;br /&gt;
!Type&lt;br /&gt;
!Reference&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|connname&lt;br /&gt;
|Text&lt;br /&gt;
|&lt;br /&gt;
|name of the connection&lt;br /&gt;
|-&lt;br /&gt;
|srvname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_server.srvname&lt;br /&gt;
|name of the foreign server&lt;br /&gt;
|-&lt;br /&gt;
|usename&lt;br /&gt;
|Name&lt;br /&gt;
|pg_authid.rolname&lt;br /&gt;
|name of the local role which was used to map foreign user&lt;br /&gt;
|-&lt;br /&gt;
|fdwname&lt;br /&gt;
|Name&lt;br /&gt;
|pg_foreign_data_wrapper.fdwname&lt;br /&gt;
|name of the foreign data wrapper which was used to connect to the foreign server&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Built-in foreign data wrappers ==&lt;br /&gt;
=== file_fdw ===&lt;br /&gt;
This can be used to read data from files in the server&#039;s local file system like &amp;lt;code&amp;gt;COPY FROM&amp;lt;/code&amp;gt; command.  It is implemented in the core, initially installed on initdb.  Its implementation bases on COPY FROM, but they are not integrated.&lt;br /&gt;
&lt;br /&gt;
Currently, stdin, although allowed in COPY FROM, is not supported.&lt;br /&gt;
&lt;br /&gt;
Because the FDW read from files on server-side, some security issues should be considered.  Maybe Non-superuser should not be allowed to create foreign tables which uses the file_fdw. At least by default.&lt;br /&gt;
&lt;br /&gt;
==== generic options ====&lt;br /&gt;
The file name is passed with &#039;&#039;filename&#039;&#039; generic option, and options which are valid in COPY FROM statement are also acceptable.  The &#039;&#039;force_not_null&#039;&#039; is the only option which has been changed from COPY option; it should be specified in per-column generic option and should be a boolean value such as &#039;&#039;true&#039;&#039; or &#039;&#039;false&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
This can be used to connect external postgres servers.&lt;br /&gt;
It is integrated with contrib/[[dblink]], and share the code and connections.&lt;br /&gt;
dblink will be installed optionally like as standard contrib modules.&lt;br /&gt;
&lt;br /&gt;
==== Connection options ====&lt;br /&gt;
The connection options are constructed from all GENERIC OPTIONS of foreign-data wrapper, foreign server and user mapping, because currently FDW for PostgreSQL assumes all GENERIC OPTIONS are connection options.&lt;br /&gt;
Note that non-superuser MUST specify password in GENERIC OPTIONS and require password authentication by the foreign server because of security issues.&lt;br /&gt;
&lt;br /&gt;
In current implementation, password is exposed as same as other options.  It might be necessary to hide some of generic options including password because of security issues.&lt;br /&gt;
&lt;br /&gt;
==== No transaction management ====&lt;br /&gt;
FDW for PostgreSQL never emit transaction command such as BEGIN, ROLLBACK and COMMIT.  Thus, all SQL statements are executed in each transaction when &#039;autocommit&#039; was set to &#039;on&#039;.&lt;br /&gt;
&lt;br /&gt;
==== WHERE-clause push-down ====&lt;br /&gt;
Currently SELECT clause is always &amp;quot;SELECT *&amp;quot;. It could be optimized with replacing unnecessary column name with &amp;quot;NULL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
WHERE clauses in the original query are [http://wiki.postgresql.org/wiki/ClusterFeatures#Function_scan_push-down pushed-down] into the reconstructed query sent to the foreign server.&lt;br /&gt;
There are restrictions for the conditions; their PlanState.qual must consist of only the following node types. If there are other conditions, the remote server will send rows without the conditions, and the local server will evaluate the rows with the conditions.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Element&lt;br /&gt;
! Tag name&lt;br /&gt;
! Note&lt;br /&gt;
|-&lt;br /&gt;
|Constant value&lt;br /&gt;
|Const&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Table column reference&lt;br /&gt;
|Var&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Array of some type&lt;br /&gt;
|Array&lt;br /&gt;
|expression like &amp;quot;&#039;{1, 2, 3}&#039;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|External parameter&lt;br /&gt;
|Param&lt;br /&gt;
|&amp;quot;External&amp;quot; means that &amp;quot;Param.paramkind == PARAM_EXTERNAL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Bool expression&lt;br /&gt;
|BoolExpr&lt;br /&gt;
|expressions such as &amp;quot;A AND B&amp;quot;, &amp;quot;A OR B&amp;quot;, &amp;quot;NOT A&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|NULL test&lt;br /&gt;
|NullTest&lt;br /&gt;
|expressions like &amp;quot;IS [NOT] NULL&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Operator&lt;br /&gt;
|OpExpr&lt;br /&gt;
|pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|DISTINCT operator&lt;br /&gt;
|DistinctExpr&lt;br /&gt;
|expressions like &amp;quot;A IS DISTINCT FROM B&amp;quot;&lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Scalar array operator&lt;br /&gt;
|ScalarArrayOpExpr&lt;br /&gt;
|expressions such as &amp;quot;ANY (...)&amp;quot;, &amp;quot;ALL (...)&amp;quot; &lt;br /&gt;
pg_operator.opcode MUST be a IMMUTABLE function&lt;br /&gt;
|-&lt;br /&gt;
|Function call&lt;br /&gt;
|FuncExpr&lt;br /&gt;
|MUST be a IMMUTABLE function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Neither ORDER BY, LIMIT, OFFSET, GROUP BY nor HAVING is used in a foreign query.&lt;br /&gt;
&lt;br /&gt;
==== Retrieving all tuples at once ====&lt;br /&gt;
The FDW retrieves all of the result tuples at once with libpq when the first call of Iterate() of Open() or ReOpen(). But we could use cursors instead to avoid too much memory consumption for huge result sets.&lt;br /&gt;
&lt;br /&gt;
After it receives tuples as a PGresult, it copies it into Tuplestorestate to avoid memory leaks on error. The libpq uses malloc() rather than palloc() to allocate the memory. We might need research to avoid the copy.&lt;br /&gt;
&lt;br /&gt;
= Open questions =&lt;br /&gt;
There are still several issues in the FDW design and implementation:&lt;br /&gt;
&lt;br /&gt;
; FdwRoutine vs. SETOF record function&lt;br /&gt;
: Some of fdw routines are similar to SETOF record function. We could merge them or share some of the internal routines. However, it seems to be hard to use SRF instead of FdwRoutine because FDW needs to support a couple of utility functions; connect, disconnect, handle WHERE conditions, etc.&lt;br /&gt;
&lt;br /&gt;
; fdw_handler vs. function table like pg_am&lt;br /&gt;
: FDW routines requires a set of functions. The fdw_handler can pack those functions in a C++ like interface. However, we have pg_am for index access methods, that is a table-based approach. Note that we probably need to write fdw routines with C because it accesses executor objects to extract expressions.&lt;br /&gt;
&lt;br /&gt;
; pg_foreign_table.ftoptions vs. pg_class.reloptions&lt;br /&gt;
: We could store ftserver and ftoptions into some fields in pg_class, ex. relam and reloptions, because we probably won&#039;t use those fields for foreign tables.&lt;br /&gt;
&lt;br /&gt;
; Which user identifier is appropriate to determine USER MAPPING ?&lt;br /&gt;
: Current implementation uses OuterUserId but not CurrentUserId to determine USER MAPPING.  Because OuterUserId is the role that the user specified explicitly with SET ROLE or SET SESSION AUTHORIZATOIN, on the other hand, CurrentUserId is changed implicitly during execution of a function which have been created with SECURITY DEFINER option.  It would not be what the user expect that a access to a foreign table via a SECURITY-DEFINER-function uses the USER MAPPING which related to the owner of the function.  Is this an appropriate specification ?&lt;br /&gt;
&lt;br /&gt;
; Which should we export foreign connection management functions from?&lt;br /&gt;
: Currently &amp;lt;code&amp;gt;DISCARD ALL&amp;lt;/code&amp;gt; disconnects all of connections, but we might provide SQL functions to manage each foreign connection. We could export those functions from the core like pg_connect()/pg_disconnect(), or continue to use contrib/dblink if they are optional.&lt;br /&gt;
&lt;br /&gt;
; Locking a foreign table&lt;br /&gt;
: Currently a foreign table can be locked in only ACCESS SHARE mode because only SELECT privilege can be granted on a foreign table.  In normal table case, at least one of INSERT/UPDATE/DELETE privilege is required to lock in other modes.  Should we relax the restriction if the target is a foreign server ?  We must consider about recursive locking via table inheritance.&lt;br /&gt;
&lt;br /&gt;
= Supported features =&lt;br /&gt;
== DDL ==&lt;br /&gt;
* ALTER FOREIGN DATA WRAPPER name {HANDLER name|NO HANDLER}&lt;br /&gt;
* CREATE FOREIGN TABLE name INHERITS (parent)&lt;br /&gt;
** Inherit a plain relation (tableoid system attribute is supported too)&lt;br /&gt;
* DROP FOREIGN TABLE&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name RENAME COLUMN column TO newname&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} column&lt;br /&gt;
* ALTER FOREIGN TABLE name {ADD|DROP} constraint&lt;br /&gt;
** Only NOT NULL and CHECK constraints are supported.&lt;br /&gt;
* ALTER FOREIGN TABLE name OWNER TO owner&lt;br /&gt;
* {GRANT|REVOKE} SELECT [(column list)] ON FOREIGN TABLE name {TO|FROM} user&lt;br /&gt;
** syntax below are valid too:&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON name {TO|FROM} user&lt;br /&gt;
*** {GRANT|REVOKE} SELECT [(column list)] ON TABLE name {TO|FROM} user&lt;br /&gt;
* CREATE RULE ... TO foreign_table&lt;br /&gt;
* COMMENT ON FOREIGN TABLE name IS &#039;table comment&#039;&lt;br /&gt;
* COMMENT ON COLUMN name.column IS &#039;column comment&#039;&lt;br /&gt;
&lt;br /&gt;
== DML ==&lt;br /&gt;
* SELECT statement using:&lt;br /&gt;
** multiple foreign-data wrappers&lt;br /&gt;
** multiple foreign servers&lt;br /&gt;
** multiple foreign tables (JOIN, UNION, Subquery, etc.)&lt;br /&gt;
** PREPARE/EXECUTE statement with parameters&lt;br /&gt;
* Deny execution of INSERT/UPDATE/DELETE for a foreign table&lt;br /&gt;
* Deny execution of VACUUM/TRUNCATE/CLUSTER for a foreign table&lt;br /&gt;
* Lock foreign tables and their children recursively&lt;br /&gt;
&lt;br /&gt;
; Execute-time constraint&lt;br /&gt;
: CHECK and/or NOT NULL constraint which are defined on foreign columns are evaluated when actual tuples are retrieved from the foreign server.&lt;br /&gt;
&lt;br /&gt;
; Support tableoid system column&lt;br /&gt;
: To have foreign tables support inheritance, tuples from a foreign table should supply tableoid column.&lt;br /&gt;
&lt;br /&gt;
== pg_dump ==&lt;br /&gt;
* dumping schema (definition) of foreign tables&lt;br /&gt;
** contents of a foreign table are not dumped because they are not part of the database&lt;br /&gt;
* dumping foreign-data wrappers with HANDLER specification&lt;br /&gt;
* dumping foreign-data wrappers, servers and user mappings excluding built-in objects&lt;br /&gt;
&lt;br /&gt;
= Future improvements =&lt;br /&gt;
== General ==&lt;br /&gt;
; FDW as a source for COPY FROM&lt;br /&gt;
: COPY FROM will be adjusted to use a foreign table as a input source. The traditional TSV and CSV parser is rebuild　as a built-in &#039;&#039;&#039;File data wrapper&#039;&#039;&#039;. For this purpose, FDW routines should be designed to be able to read many tuples as a stream. Overheads and result caching should be avoided in this layer.&lt;br /&gt;
&lt;br /&gt;
; Smart planning&lt;br /&gt;
: ANALYZE command can update pg_statistic and part of pg_class (reltuples and relpages) of the foreign tables with adding FDW routine Analyze(tableoid or tablename) which returns pg_statistic records for the foreign table.&lt;br /&gt;
: The costs to access foreign data will be different from the cost to access local data even if the data definition and contents are same.  GENERIC OPTION like &#039;&#039;&#039;cost_factor&#039;&#039;&#039; allow to tell the overhead to planner.&lt;br /&gt;
&lt;br /&gt;
== for SQL-based FDWs ==&lt;br /&gt;
; JOINs of two foreign tables in the same server&lt;br /&gt;
: They could be merged into one ForeignScan so that the foreign server can return the result after local JOINs in it.&lt;br /&gt;
&lt;br /&gt;
; Optimize SELECT clause&lt;br /&gt;
: Some foreign scan need only a part of columns. Unnecessary columns in such a scan are omissible from the SELECT clause. &lt;br /&gt;
&lt;br /&gt;
; Support internal parameter&lt;br /&gt;
: A certain kind of a plan, i.e. nested loop,  generates internal parameter to pass value(s) from parent node to child node.  The number of records acquired from an foreign server can be decreased by applying an internal parameter to external query. &lt;br /&gt;
&lt;br /&gt;
; Optimize parameter&lt;br /&gt;
: Some foreign scan uses only a part of parameters of EXECUTE statement. Unused parameters are omissible from the parameter of PQexecParams(). And parameters can be passed in binary format to avoid conversion between text and binary.&lt;br /&gt;
&lt;br /&gt;
; Support cursor mode for huge result&lt;br /&gt;
: Currently libpq does not support protocol level cursor, so the FDW for PostgreSQL executes SELECT statement directly via PQexecParams() and retrieves all tuples at once.  If parameterized cursor is supported, the FDW for PostgreSQL will be able to retrieve a part of the result at a time to improve response.&lt;br /&gt;
&lt;br /&gt;
; Push-down WHERE clause including CURRENT_TIMESTAMP&lt;br /&gt;
: Rewriting query like pgpool, or replacing the FuncExpr node with a Const node representing the result of CURRENT_TIMESTAMP.&lt;br /&gt;
&lt;br /&gt;
= SQL Conformance =&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Foreign table features in the SQL standard&lt;br /&gt;
! Identifier&lt;br /&gt;
! Description&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| M004&lt;br /&gt;
| Foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M005&lt;br /&gt;
| Foreign schema support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M006&lt;br /&gt;
| GetSQLString routine&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M007&lt;br /&gt;
| TransmitRequest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M009&lt;br /&gt;
| GetOpts and GetStatistics routines&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M010&lt;br /&gt;
| Foreign data wrapper support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M018&lt;br /&gt;
| Foreign data wrapper interface routines in Ada&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M019&lt;br /&gt;
| Foreign data wrapper interface routines in C&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M020&lt;br /&gt;
| Foreign data wrapper interface routines in COBOL&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M021&lt;br /&gt;
| Foreign data wrapper interface routines in Fortran&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M022&lt;br /&gt;
| Foreign data wrapper interface routines in MUMPS&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M023&lt;br /&gt;
| Foreign data wrapper interface routines in Pascal&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M024&lt;br /&gt;
| Foreign data wrapper interface routines in PL/I&lt;br /&gt;
| (not planned)&lt;br /&gt;
|-&lt;br /&gt;
| M030&lt;br /&gt;
| SQL-server foreign data support&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| M031&lt;br /&gt;
| Foreign data wrapper general routines&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Error codes for FDWs&lt;br /&gt;
! Code&lt;br /&gt;
! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| HV000&lt;br /&gt;
| FDW-specific condition&lt;br /&gt;
|-&lt;br /&gt;
| HV001&lt;br /&gt;
| MEMORY ALLOCATION ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV002&lt;br /&gt;
| DYNAMIC PARAMETER VALUE NEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV004&lt;br /&gt;
| INVALID DATA TYPE&lt;br /&gt;
|-&lt;br /&gt;
| HV005&lt;br /&gt;
| COLUMN NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV006&lt;br /&gt;
| INVALID DATA TYPE DESCRIPTORS&lt;br /&gt;
|-&lt;br /&gt;
| HV007&lt;br /&gt;
| INVALID COLUMN NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV008&lt;br /&gt;
| INVALID COLUMN NUMBER&lt;br /&gt;
|-&lt;br /&gt;
| HV009&lt;br /&gt;
| INVALID USE OF NULL POINTER&lt;br /&gt;
|-&lt;br /&gt;
| HV00A&lt;br /&gt;
| INVALID STRING FORMAT&lt;br /&gt;
|-&lt;br /&gt;
| HV00B&lt;br /&gt;
| INVALID HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00C&lt;br /&gt;
| INVALID OPTION INDEX&lt;br /&gt;
|-&lt;br /&gt;
| HV00D&lt;br /&gt;
| INVALID OPTION NAME&lt;br /&gt;
|-&lt;br /&gt;
| HV00J&lt;br /&gt;
| OPTION NAME NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00K&lt;br /&gt;
| REPLY HANDLE&lt;br /&gt;
|-&lt;br /&gt;
| HV00L&lt;br /&gt;
| UNABLE TO CREATE EXECUTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00M&lt;br /&gt;
| UNABLE TO CREATE REPLY&lt;br /&gt;
|-&lt;br /&gt;
| HV00N&lt;br /&gt;
| UNABLE TO ESTABLISH CONNECTION&lt;br /&gt;
|-&lt;br /&gt;
| HV00P&lt;br /&gt;
| NO SCHEMAS&lt;br /&gt;
|-&lt;br /&gt;
| HV00Q&lt;br /&gt;
| SCHEMA NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV00R&lt;br /&gt;
| TABLE NOT FOUND&lt;br /&gt;
|-&lt;br /&gt;
| HV010&lt;br /&gt;
| FUNCTION SEQUENCE ERROR&lt;br /&gt;
|-&lt;br /&gt;
| HV014&lt;br /&gt;
| LIMIT ON NUMBER OF HANDLES EXCEEDED&lt;br /&gt;
|-&lt;br /&gt;
| HV021&lt;br /&gt;
| INCONSISTENT DESCRIPTOR INFORMATION&lt;br /&gt;
|-&lt;br /&gt;
| HV024&lt;br /&gt;
| INVALID ATTRIBUTE VALUE&lt;br /&gt;
|-&lt;br /&gt;
| HV090&lt;br /&gt;
| INVALID STRING LENGTH OR BUFFER LENGTH&lt;br /&gt;
|-&lt;br /&gt;
| HV091&lt;br /&gt;
| INVALID DESCRIPTOR FIELD IDENTIFIER&lt;br /&gt;
|-&lt;br /&gt;
| 0X000&lt;br /&gt;
| invalid foreign server specification&lt;br /&gt;
|-&lt;br /&gt;
| 0Y000&lt;br /&gt;
| pass-through specific condition&lt;br /&gt;
|-&lt;br /&gt;
| 0Y001&lt;br /&gt;
| INVALID CURSOR OPTION&lt;br /&gt;
|-&lt;br /&gt;
| 0Y002&lt;br /&gt;
| INVALID CURSOR ALLOCATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL/MED]]&lt;/div&gt;</summary>
		<author><name>Hanada</name></author>
	</entry>
</feed>