Simon Riggs wrote:
The notes say "Heikki doesn't think this is a long term solution", but
in the following discussion it was the *only* way of doing this that
will work with non-PostgreSQL databases. So it seems like the way we
would want to go, yes?

How did you come to the conclusion that this is the only way that will work with non-PostgreSQL databases? I don't see any limitations like that in any of the proposed approaches.

I guess I should clarify my position on this:

We should start moving towards a full SQL:MED solution that will ultimately support pushing down joins, aggregates etc. to the remote database. Including support for transaction control, using 2PC, and cost estimation and intelligent planning.

This should be done in an extensible way, so that people can write their own plugins to connect to different RDBMSs, as well as simple data sources like flat files. The plugin needs to be able to control which parts of a plan tree can be pushed down to the remote source, estimate the cost of remote execution, and map remote data types to local ones. And it then needs to be able to construct and execute the remote parts of a plan.

We're obviously not going to get all that overnight, but whatever we implement now should be the first step towards that, rather than something that we need to deprecate and replace in the future. Unfortunately I don't see a way to extend the proposed "exposing quals to functions" patch to do more than just that.

The list of functionality a full-blown plugin will need is quite long. I don't think there's any hope of supporting all that without reaching into some PostgreSQL internal data structures, particularly the planner structures like RelOptInfo, Path and Plan. The plugins will be more tightly integrated into the system than say user defined data types. They will need to be written in C, and they will be somewhat version dependent. Simpler plugins, like one to read CSV files, with no "pushing down" and no update support, will need less access to internals, and thus will be less version dependent, so pgfoundry projects like that will be feasible.

Note that the dependency on internal data structures doesn't go away by saying that they're passed as text; the text representation of our data structures is version dependent as well.

So what would the plugin API look like? To hook into the planner, I'm envisioning the plugin would define these functions:

  /*
   * Generate a remote plan for executing a whole subquery remotely. For
   * example, if the query is an aggregate, we might be able to execute
   * the whole aggregate in the remote database. This will be called
   * from grouping_planner(), like optimize_minmax_aggregates().
   * Returns NULL if remote execution is not possible. (a dummy
   * implementation can always return NULL.
   */
  Plan *generate_remote_path(PlannerInfo *, List *tlist);

  /*
   * Generate a path for executing one relation in remote
   * database. The relation can be a base (non-join) remote relation,
   * or a join involving a remote relation. Can return NULL for join
   * relations if the join can't be executed remotely.
   */
  Path *generate_remote_path(PlannerInfo *, RelOptInfo *)

  /*
   * Create a Plan node from a Path. Called from create_plan, when
   * the planner chooses to use a remote path. A typical implementation
   * would create the SQL string to be executed in the remote database,
   * and return a RemotePlan node with that SQL string in it.
   */
  Plan *create_remote_plan(PlannerInfo *, RemotePath *)

On the execution side, the plugin needs to be able to execute a previously generated RemotePlan. There would be a new executor node type, a RemoteScan, that would be similar to a seq scan or index scan, but delegates the actual execution to the plugin. The execution part of the plugin API would reflect the API of executor nodes, something like:

  void *scan_open(RemotePlan *)
  HeapTuple *scan_getnext(void *scanstate)
  void scan_close(void *scanstate)


The presumption here is that you would define remote tables with the appropriate SQL:MED statements beforehand (CREATE FOREIGN TABLE). However, it is flexible enough that you could implement the "exposing quals to functions" functionality with this as well: generate_remote_path() would need to recognize the function scans that it can handle, and return a RemotePath struct with all the same information as create_functionscan_path does (the cost estimates could be adjusted for the pushed down quals at this point as well). create_remote_plan would return a FunctionScan node, but with the extra qualifiers passed into the function as arguments. In case of dblink, it could just add extra WHERE clauses to the query that's being passed as argument. I'm not proposing that we do the stuff described in this paragraph, just using it as an example of the flexibility.

BTW, I think the "exposing quals to functions" functionality could be implemented as a planner hook as well. The hook would call the standard planner, and modify the plan tree after that, passing the quals as extra arguments to functions that can take advantage of them.

A "foreign data wrapper" interface is also defined in the SQL/MED standard. I've only looked at it briefly, but it seems provide roughly the same functionality as the API I defined above. It would be a good idea to look at that, though I don't think that part of the standard is very widely adopted.

--
  Heikki Linnakangas
  EnterpriseDB   http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to