Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
bdc4d5c
Added 'use_postgis' option to FDW TABLE options,
pramsey Jun 8, 2015
5f636f5
Add snapshot param
pramsey Jun 9, 2015
15ec556
Merge branch 'master' of github.com:postgres/postgres into fdw-extens…
pramsey Jul 6, 2015
fbfa660
Generalize support for passing extension ops/functions through FDW
pramsey Jul 15, 2015
4696ef3
Merge branch 'master' of github.com:postgres/postgres into fdw-extens…
pramsey Jul 15, 2015
7521751
Add doco for the 'extensions' option on CREATE SERVER
pramsey Jul 15, 2015
94201de
Merge branch 'master' into fdw-extension-suppport
pramsey Jul 16, 2015
fbbec9d
Patch review improvements
pramsey Jul 16, 2015
0edbbe1
Merge branch 'fdw-extension-suppport' of github.com:pramsey/postgres …
pramsey Jul 16, 2015
c91ac11
Use double quotes in error per PgSQL style guide
pramsey Jul 16, 2015
341553b
Add 'extensions' option at FDW level as well
pramsey Jul 21, 2015
09babba
Merge branch 'master' into fdw-extension-suppport
pramsey Jul 21, 2015
51b3bf3
Add cache for holding info about what functions
pramsey Jul 21, 2015
90ed619
Comment cleanup
pramsey Jul 21, 2015
1dd9e45
Match original whitespace
pramsey Jul 23, 2015
1bdf744
Merge branch 'master' into fdw-extension-suppport
pramsey Jul 23, 2015
91e826f
Clear the cache when there are changes to wrapper/server definitions
pramsey Jul 23, 2015
49888a4
Merge branch 'master' into fdw-extension-suppport
pramsey Jul 24, 2015
35ad513
Add note that extensions can be set on wrappers too
pramsey Jul 24, 2015
335ba69
Merge branch 'master' into fdw-extension-suppport
pramsey Sep 25, 2015
c6362af
Changes based on code review from Michael Paquier
pramsey Sep 25, 2015
1634fc8
Use 'cube' as extension basis for regression test
pramsey Sep 25, 2015
9b46597
Minor feedback changes
pramsey Sep 28, 2015
9dfe1d7
Clean up after regression tests, change parameter parse signature
pramsey Sep 30, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions contrib/postgres_fdw/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# contrib/postgres_fdw/Makefile

MODULE_big = postgres_fdw
OBJS = postgres_fdw.o option.o deparse.o connection.o $(WIN32RES)
OBJS = postgres_fdw.o option.o deparse.o connection.o shippable.o $(WIN32RES)
PGFILEDESC = "postgres_fdw - foreign data wrapper for PostgreSQL"

PG_CPPFLAGS = -I$(libpq_srcdir)
Expand All @@ -10,7 +10,9 @@ SHLIB_LINK = $(libpq)
EXTENSION = postgres_fdw
DATA = postgres_fdw--1.0.sql

REGRESS = postgres_fdw
# Note: shippable tests depend on postgres_fdw tests setup
REGRESS = postgres_fdw shippable
EXTRA_INSTALL = contrib/cube

ifdef USE_PGXS
PG_CONFIG = pg_config
Expand Down
25 changes: 19 additions & 6 deletions contrib/postgres_fdw/deparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ foreign_expr_walker(Node *node,
Oid collation;
FDWCollateState state;

/* Access extension metadata from fpinfo on baserel */
PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *)(glob_cxt->foreignrel->fdw_private);

/* Need do nothing for empty subexpressions */
if (node == NULL)
return true;
Expand Down Expand Up @@ -378,7 +381,7 @@ foreign_expr_walker(Node *node,
* can't be sent to remote because it might have incompatible
* semantics on remote side.
*/
if (!is_builtin(fe->funcid))
if (!is_builtin(fe->funcid) && !is_shippable(fe->funcid, fpinfo->extensions))
return false;

/*
Expand Down Expand Up @@ -426,7 +429,7 @@ foreign_expr_walker(Node *node,
* (If the operator is, surely its underlying function is
* too.)
*/
if (!is_builtin(oe->opno))
if (!is_builtin(oe->opno) && !is_shippable(oe->opno, fpinfo->extensions))
return false;

/*
Expand Down Expand Up @@ -466,7 +469,7 @@ foreign_expr_walker(Node *node,
/*
* Again, only built-in operators can be sent to remote.
*/
if (!is_builtin(oe->opno))
if (!is_builtin(oe->opno) && !is_shippable(oe->opno, fpinfo->extensions))
return false;

/*
Expand Down Expand Up @@ -616,7 +619,7 @@ foreign_expr_walker(Node *node,
* If result type of given expression is not built-in, it can't be sent to
* remote because it might have incompatible semantics on remote side.
*/
if (check_type && !is_builtin(exprType(node)))
if (check_type && !is_builtin(exprType(node)) && !is_shippable(exprType(node), fpinfo->extensions))
return false;

/*
Expand Down Expand Up @@ -1351,6 +1354,9 @@ deparseConst(Const *node, deparse_expr_cxt *context)
bool isfloat = false;
bool needlabel;

/* Access extension metadata from fpinfo on baserel */
PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *)(context->foreignrel->fdw_private);

if (node->constisnull)
{
appendStringInfoString(buf, "NULL");
Expand Down Expand Up @@ -1428,9 +1434,16 @@ deparseConst(Const *node, deparse_expr_cxt *context)
break;
}
if (needlabel)
{
/*
* References to extension types need to be fully qualified,
* but references to built-in types shouldn't be.
*/
appendStringInfo(buf, "::%s",
format_type_with_typemod(node->consttype,
node->consttypmod));
is_shippable(node->consttype, fpinfo->extensions) ?
format_type_be_qualified(node->consttype) :
format_type_with_typemod(node->consttype, node->consttypmod));
}
}

/*
Expand Down
138 changes: 138 additions & 0 deletions contrib/postgres_fdw/expected/shippable.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
-- ===================================================================
-- create FDW objects
-- ===================================================================
-- Error, extension isn't installed yet
ALTER SERVER loopback OPTIONS (ADD extensions 'cube');
ERROR: the "cube" extension must be installed locally before it can be used on a remote server
-- Try again
CREATE EXTENSION cube;
ALTER SERVER loopback OPTIONS (ADD extensions 'cube');
ALTER SERVER loopback OPTIONS (DROP extensions);
-- ===================================================================
-- create objects used through FDW loopback server
-- ===================================================================
CREATE SCHEMA "SH 1";
CREATE TABLE "SH 1"."TBL 1" (
"C 1" int NOT NULL,
c2 int NOT NULL,
c3 cube,
c4 timestamptz
);
INSERT INTO "SH 1"."TBL 1"
SELECT id,
2 * id,
cube(id,2*id),
'1970-01-01'::timestamptz + ((id % 100) || ' days')::interval
FROM generate_series(1, 1000) id;
ANALYZE "SH 1"."TBL 1";
-- ===================================================================
-- create foreign table
-- ===================================================================
CREATE FOREIGN TABLE shft1 (
"C 1" int NOT NULL,
c2 int NOT NULL,
c3 cube,
c4 timestamptz
) SERVER loopback
OPTIONS (schema_name 'SH 1', table_name 'TBL 1');
-- ===================================================================
-- simple queries
-- ===================================================================
-- without operator shipping
EXPLAIN (COSTS false) SELECT * FROM shft1 LIMIT 1;
QUERY PLAN
-----------------------------
Limit
-> Foreign Scan on shft1
(2 rows)

EXPLAIN VERBOSE SELECT c2 FROM shft1 WHERE c3 && cube(1.5,2.5);
QUERY PLAN
---------------------------------------------------------------------
Foreign Scan on public.shft1 (cost=100.00..205.06 rows=15 width=4)
Output: c2
Filter: (shft1.c3 && '(1.5),(2.5)'::cube)
Remote SQL: SELECT c2, c3 FROM "SH 1"."TBL 1"
(4 rows)

SELECT c2 FROM shft1 WHERE c3 && cube(1.5,2.5);
c2
----
2
4
(2 rows)

EXPLAIN VERBOSE SELECT c2 FROM shft1 WHERE c3 && '(1.5),(2.5)'::cube;
QUERY PLAN
---------------------------------------------------------------------
Foreign Scan on public.shft1 (cost=100.00..205.06 rows=15 width=4)
Output: c2
Filter: (shft1.c3 && '(1.5),(2.5)'::cube)
Remote SQL: SELECT c2, c3 FROM "SH 1"."TBL 1"
(4 rows)

-- with operator shipping
ALTER SERVER loopback OPTIONS (ADD extensions 'cube');
EXPLAIN VERBOSE SELECT c2 FROM shft1 WHERE c3 && cube(1.5,2.5);
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Foreign Scan on public.shft1 (cost=100.00..146.86 rows=15 width=4)
Output: c2
Remote SQL: SELECT c2 FROM "SH 1"."TBL 1" WHERE ((c3 OPERATOR(public.&&) '(1.5),(2.5)'::public.cube))
(3 rows)

SELECT c2 FROM shft1 WHERE c3 && cube(1.5,2.5);
c2
----
2
4
(2 rows)

EXPLAIN VERBOSE SELECT c2 FROM shft1 WHERE c3 && '(1.5),(2.5)'::cube;
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Foreign Scan on public.shft1 (cost=100.00..146.86 rows=15 width=4)
Output: c2
Remote SQL: SELECT c2 FROM "SH 1"."TBL 1" WHERE ((c3 OPERATOR(public.&&) '(1.5),(2.5)'::public.cube))
(3 rows)

EXPLAIN VERBOSE SELECT cube_dim(c3) FROM shft1 WHERE c3 && '(1.5),(2.5)'::cube;
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Foreign Scan on public.shft1 (cost=100.00..128.43 rows=7 width=32)
Output: cube_dim(c3)
Remote SQL: SELECT c3 FROM "SH 1"."TBL 1" WHERE ((c3 OPERATOR(public.&&) '(1.5),(2.5)'::public.cube))
(3 rows)

SELECT cube_dim(c3) FROM shft1 WHERE c3 && '(1.5),(2.5)'::cube;
cube_dim
----------
1
1
(2 rows)

EXPLAIN VERBOSE SELECT c2 FROM shft1 WHERE cube_dim(c3) = 1 LIMIT 2;
QUERY PLAN
-------------------------------------------------------------------------------------
Limit (cost=100.00..107.22 rows=2 width=4)
Output: c2
-> Foreign Scan on public.shft1 (cost=100.00..154.18 rows=15 width=4)
Output: c2
Remote SQL: SELECT c2 FROM "SH 1"."TBL 1" WHERE ((public.cube_dim(c3) = 1))
(5 rows)

SELECT c2 FROM shft1 WHERE cube_dim(c3) = 1 LIMIT 2;
c2
----
2
4
(2 rows)

-- ===================================================================
-- clean up
-- ===================================================================
DROP FOREIGN TABLE shft1;
DROP TABLE "SH 1"."TBL 1";
DROP SCHEMA "SH 1";
DROP EXTENSION cube;
ALTER SERVER loopback OPTIONS (DROP extensions);
8 changes: 8 additions & 0 deletions contrib/postgres_fdw/option.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "postgres_fdw.h"

#include "access/reloptions.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_user_mapping.h"
Expand Down Expand Up @@ -124,6 +125,10 @@ postgres_fdw_validator(PG_FUNCTION_ARGS)
errmsg("%s requires a non-negative numeric value",
def->defname)));
}
else if (strcmp(def->defname, "extensions") == 0)
{
extractExtensionList(defGetString(def), false);
}
}

PG_RETURN_VOID();
Expand Down Expand Up @@ -153,6 +158,9 @@ InitPgFdwOptions(void)
/* updatable is available on both server and table */
{"updatable", ForeignServerRelationId, false},
{"updatable", ForeignTableRelationId, false},
/* extensions is available on both wrapper and server */
{"extensions", ForeignServerRelationId, false},
{"extensions", ForeignDataWrapperRelationId, false},
{NULL, InvalidOid, false}
};

Expand Down
37 changes: 4 additions & 33 deletions contrib/postgres_fdw/postgres_fdw.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,39 +47,6 @@ PG_MODULE_MAGIC;
/* Default CPU cost to process 1 row (above and beyond cpu_tuple_cost). */
#define DEFAULT_FDW_TUPLE_COST 0.01

/*
* FDW-specific planner information kept in RelOptInfo.fdw_private for a
* foreign table. This information is collected by postgresGetForeignRelSize.
*/
typedef struct PgFdwRelationInfo
{
/* baserestrictinfo clauses, broken down into safe and unsafe subsets. */
List *remote_conds;
List *local_conds;

/* Bitmap of attr numbers we need to fetch from the remote server. */
Bitmapset *attrs_used;

/* Cost and selectivity of local_conds. */
QualCost local_conds_cost;
Selectivity local_conds_sel;

/* Estimated size and cost for a scan with baserestrictinfo quals. */
double rows;
int width;
Cost startup_cost;
Cost total_cost;

/* Options extracted from catalogs. */
bool use_remote_estimate;
Cost fdw_startup_cost;
Cost fdw_tuple_cost;

/* Cached catalog information. */
ForeignTable *table;
ForeignServer *server;
UserMapping *user; /* only set in use_remote_estimate mode */
} PgFdwRelationInfo;

/*
* Indexes of FDW-private information stored in fdw_private lists.
Expand Down Expand Up @@ -397,6 +364,7 @@ postgresGetForeignRelSize(PlannerInfo *root,
/* Look up foreign-table catalog info. */
fpinfo->table = GetForeignTable(foreigntableid);
fpinfo->server = GetForeignServer(fpinfo->table->serverid);
fpinfo->wrapper = GetForeignDataWrapper(fpinfo->server->fdwid);

/*
* Extract user-settable option values. Note that per-table setting of
Expand All @@ -405,6 +373,7 @@ postgresGetForeignRelSize(PlannerInfo *root,
fpinfo->use_remote_estimate = false;
fpinfo->fdw_startup_cost = DEFAULT_FDW_STARTUP_COST;
fpinfo->fdw_tuple_cost = DEFAULT_FDW_TUPLE_COST;
fpinfo->extensions = NIL;

foreach(lc, fpinfo->server->options)
{
Expand All @@ -416,6 +385,8 @@ postgresGetForeignRelSize(PlannerInfo *root,
fpinfo->fdw_startup_cost = strtod(defGetString(def), NULL);
else if (strcmp(def->defname, "fdw_tuple_cost") == 0)
fpinfo->fdw_tuple_cost = strtod(defGetString(def), NULL);
else if (strcmp(def->defname, "extensions") == 0)
fpinfo->extensions = extractExtensionList(defGetString(def), true);
}
foreach(lc, fpinfo->table->options)
{
Expand Down
42 changes: 42 additions & 0 deletions contrib/postgres_fdw/postgres_fdw.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,44 @@

#include "libpq-fe.h"

/*
* FDW-specific planner information kept in RelOptInfo.fdw_private for a
* foreign table. This information is collected by postgresGetForeignRelSize.
*/
typedef struct PgFdwRelationInfo
{
/* baserestrictinfo clauses, broken down into safe and unsafe subsets. */
List *remote_conds;
List *local_conds;

/* Bitmap of attr numbers we need to fetch from the remote server. */
Bitmapset *attrs_used;

/* Cost and selectivity of local_conds. */
QualCost local_conds_cost;
Selectivity local_conds_sel;

/* Estimated size and cost for a scan with baserestrictinfo quals. */
double rows;
int width;
Cost startup_cost;
Cost total_cost;

/* Options extracted from catalogs. */
bool use_remote_estimate;
Cost fdw_startup_cost;
Cost fdw_tuple_cost;

/* Optional extensions to support (list of oid) */
List *extensions;

/* Cached catalog information. */
ForeignDataWrapper *wrapper;
ForeignTable *table;
ForeignServer *server;
UserMapping *user; /* only set in use_remote_estimate mode */
} PgFdwRelationInfo;

/* in postgres_fdw.c */
extern int set_transmission_modes(void);
extern void reset_transmission_modes(int nestlevel);
Expand All @@ -38,6 +76,10 @@ extern int ExtractConnectionOptions(List *defelems,
const char **keywords,
const char **values);

/* in shippable.c */
extern List* extractExtensionList(char *extensionString, bool populateList);
extern bool is_shippable(Oid procnumber, List *extension_list);

/* in deparse.c */
extern void classifyConditions(PlannerInfo *root,
RelOptInfo *baserel,
Expand Down
Loading