diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 583cce7..84334e6 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -106,7 +106,8 @@ ALTER SERVER testserver1 OPTIONS ( sslcert 'value', sslkey 'value', sslrootcert 'value', - sslcrl 'value' + sslcrl 'value', + fetch_size '101' --requirepeer 'value', -- krbsrvname 'value', -- gsslib 'value', @@ -114,18 +115,34 @@ ALTER SERVER testserver1 OPTIONS ( ); ALTER USER MAPPING FOR public SERVER testserver1 OPTIONS (DROP user, DROP password); -ALTER FOREIGN TABLE ft1 OPTIONS (schema_name 'S 1', table_name 'T 1'); +ALTER FOREIGN TABLE ft1 OPTIONS (schema_name 'S 1', table_name 'T 1', fetch_size '102'); ALTER FOREIGN TABLE ft2 OPTIONS (schema_name 'S 1', table_name 'T 1'); ALTER FOREIGN TABLE ft1 ALTER COLUMN c1 OPTIONS (column_name 'C 1'); ALTER FOREIGN TABLE ft2 ALTER COLUMN c1 OPTIONS (column_name 'C 1'); \det+ - List of foreign tables - Schema | Table | Server | FDW Options | Description ---------+-------+----------+---------------------------------------+------------- - public | ft1 | loopback | (schema_name 'S 1', table_name 'T 1') | - public | ft2 | loopback | (schema_name 'S 1', table_name 'T 1') | + List of foreign tables + Schema | Table | Server | FDW Options | Description +--------+-------+----------+---------------------------------------------------------+------------- + public | ft1 | loopback | (schema_name 'S 1', table_name 'T 1', fetch_size '102') | + public | ft2 | loopback | (schema_name 'S 1', table_name 'T 1') | (2 rows) +-- Test what options made it into pg_foreign_server. +-- Filter for just the server we created. +SELECT srvoptions FROM pg_foreign_server WHERE srvname = 'testserver1'; + srvoptions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + {use_remote_estimate=false,updatable=true,fdw_startup_cost=123.456,fdw_tuple_cost=0.123,service=value,connect_timeout=value,dbname=value,host=value,hostaddr=value,port=value,application_name=value,keepalives=value,keepalives_idle=value,keepalives_interval=value,sslcompression=value,sslmode=value,sslcert=value,sslkey=value,sslrootcert=value,sslcrl=value,fetch_size=101} +(1 row) + +-- Test what options made it into pg_foreign_table. +-- Filter this heavily because we cannot specify which foreign server. +SELECT ftoptions FROM pg_foreign_table WHERE ftoptions @> array['table_name=T 1','fetch_size=102']; + ftoptions +----------------------------------------------------- + {"schema_name=S 1","table_name=T 1",fetch_size=102} +(1 row) + -- Now we should be able to run ANALYZE. -- To exercise multiple code paths, we use local stats on ft1 -- and remote-estimate mode on ft2. diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c index 7547ec2..2a3ab7d 100644 --- a/contrib/postgres_fdw/option.c +++ b/contrib/postgres_fdw/option.c @@ -153,6 +153,12 @@ InitPgFdwOptions(void) /* updatable is available on both server and table */ {"updatable", ForeignServerRelationId, false}, {"updatable", ForeignTableRelationId, false}, + /* + * fetch_size is available on both server and table, the table setting + * overrides the server setting. + */ + {"fetch_size", ForeignServerRelationId, false}, + {"fetch_size", ForeignTableRelationId, false}, {NULL, InvalidOid, false} }; diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 63f0577..733ffb6 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -134,6 +134,7 @@ typedef struct PgFdwScanState /* extracted fdw_private data */ char *query; /* text of SELECT command */ List *retrieved_attrs; /* list of retrieved attribute numbers */ + int fetch_size; /* number of tuples per fetch */ /* for remote query execution */ PGconn *conn; /* connection for the scan */ @@ -871,6 +872,22 @@ postgresGetForeignPlan(PlannerInfo *root, fdw_private); } +static DefElem* +get_option(List *options, char *optname) +{ + ListCell *lc; + + foreach(lc, options) + { + DefElem *def = (DefElem *) lfirst(lc); + + if (strcmp(def->defname, optname) == 0) + return def; + } + return NULL; +} + + /* * postgresBeginForeignScan * Initiate an executor scan of a foreign PostgreSQL table. @@ -889,6 +906,7 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags) int numParams; int i; ListCell *lc; + DefElem *def; /* * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL. @@ -915,6 +933,23 @@ postgresBeginForeignScan(ForeignScanState *node, int eflags) server = GetForeignServer(table->serverid); user = GetUserMapping(userid, server->serverid); + /* Reading table options */ + fsstate->fetch_size = -1; + + def = get_option(table->options, "fetch_size"); + if (!def) + def = get_option(server->options, "fetch_size"); + + if (def) + { + fsstate->fetch_size = strtod(defGetString(def), NULL); + if (fsstate->fetch_size < 0) + elog(ERROR, "invalid fetch size for foreign table \"%s\"", + get_rel_name(table->relid)); + } + else + fsstate->fetch_size = 100; + /* * Get connection to the foreign server. Connection manager will * establish new connection if necessary. @@ -2031,7 +2066,7 @@ fetch_more_data(ForeignScanState *node) int i; /* The fetch size is arbitrary, but shouldn't be enormous. */ - fetch_size = 100; + fetch_size = fsstate->fetch_size; snprintf(sql, sizeof(sql), "FETCH %d FROM c%u", fetch_size, fsstate->cursor_number); diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 83e8fa7..d12925a 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -115,7 +115,8 @@ ALTER SERVER testserver1 OPTIONS ( sslcert 'value', sslkey 'value', sslrootcert 'value', - sslcrl 'value' + sslcrl 'value', + fetch_size '101' --requirepeer 'value', -- krbsrvname 'value', -- gsslib 'value', @@ -123,12 +124,20 @@ ALTER SERVER testserver1 OPTIONS ( ); ALTER USER MAPPING FOR public SERVER testserver1 OPTIONS (DROP user, DROP password); -ALTER FOREIGN TABLE ft1 OPTIONS (schema_name 'S 1', table_name 'T 1'); +ALTER FOREIGN TABLE ft1 OPTIONS (schema_name 'S 1', table_name 'T 1', fetch_size '102'); ALTER FOREIGN TABLE ft2 OPTIONS (schema_name 'S 1', table_name 'T 1'); ALTER FOREIGN TABLE ft1 ALTER COLUMN c1 OPTIONS (column_name 'C 1'); ALTER FOREIGN TABLE ft2 ALTER COLUMN c1 OPTIONS (column_name 'C 1'); \det+ +-- Test what options made it into pg_foreign_server. +-- Filter for just the server we created. +SELECT srvoptions FROM pg_foreign_server WHERE srvname = 'testserver1'; + +-- Test what options made it into pg_foreign_table. +-- Filter this heavily because we cannot specify which foreign server. +SELECT ftoptions FROM pg_foreign_table WHERE ftoptions @> array['table_name=T 1','fetch_size=102']; + -- Now we should be able to run ANALYZE. -- To exercise multiple code paths, we use local stats on ft1 -- and remote-estimate mode on ft2. diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml index 43adb61..02b004d 100644 --- a/doc/src/sgml/postgres-fdw.sgml +++ b/doc/src/sgml/postgres-fdw.sgml @@ -294,6 +294,34 @@ + Fetch Size Options + + + By default, rows are fetched from the remote server 100 at a time. + This may be overridden using the following option: + + + + + + fetch_size + + + This option specifies the number of rows postgres_fdw + should get in each fetch operation. It can be specified for a foreign + table or a foreign server. The option specified on a table overrides + an option specified for the server. + The default is 100. + + + + + + + + + + Importing Options