aboutsummaryrefslogtreecommitdiff
path: root/contrib/postgres_fdw/postgres_fdw.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/postgres_fdw/postgres_fdw.c')
-rw-r--r--contrib/postgres_fdw/postgres_fdw.c60
1 files changed, 42 insertions, 18 deletions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index f8461bf18dc..53f890bb483 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -4974,11 +4974,14 @@ postgresAnalyzeForeignTable(Relation relation,
}
/*
- * postgresCountTuplesForForeignTable
+ * postgresGetAnalyzeInfoForForeignTable
* Count tuples in foreign table (just get pg_class.reltuples).
+ *
+ * can_tablesample determines if the remote relation supports acquiring the
+ * sample using TABLESAMPLE.
*/
static double
-postgresCountTuplesForForeignTable(Relation relation)
+postgresGetAnalyzeInfoForForeignTable(Relation relation, bool *can_tablesample)
{
ForeignTable *table;
UserMapping *user;
@@ -4986,6 +4989,10 @@ postgresCountTuplesForForeignTable(Relation relation)
StringInfoData sql;
PGresult *volatile res = NULL;
volatile double reltuples = -1;
+ volatile char relkind = 0;
+
+ /* assume the remote relation does not support TABLESAMPLE */
+ *can_tablesample = false;
/*
* Get the connection to use. We do the remote access as the table's
@@ -4999,7 +5006,7 @@ postgresCountTuplesForForeignTable(Relation relation)
* Construct command to get page count for relation.
*/
initStringInfo(&sql);
- deparseAnalyzeTuplesSql(&sql, relation);
+ deparseAnalyzeInfoSql(&sql, relation);
/* In what follows, do not risk leaking any PGresults. */
PG_TRY();
@@ -5008,9 +5015,10 @@ postgresCountTuplesForForeignTable(Relation relation)
if (PQresultStatus(res) != PGRES_TUPLES_OK)
pgfdw_report_error(ERROR, res, conn, false, sql.data);
- if (PQntuples(res) != 1 || PQnfields(res) != 1)
+ if (PQntuples(res) != 1 || PQnfields(res) != 2)
elog(ERROR, "unexpected result from deparseAnalyzeTuplesSql query");
reltuples = strtod(PQgetvalue(res, 0, 0), NULL);
+ relkind = *(PQgetvalue(res, 0, 1));
}
PG_FINALLY();
{
@@ -5021,6 +5029,11 @@ postgresCountTuplesForForeignTable(Relation relation)
ReleaseConnection(conn);
+ /* TABLESAMPLE is supported only for regular tables and matviews */
+ *can_tablesample = (relkind == RELKIND_RELATION ||
+ relkind == RELKIND_MATVIEW ||
+ relkind == RELKIND_PARTITIONED_TABLE);
+
return reltuples;
}
@@ -5148,26 +5161,24 @@ postgresAcquireSampleRowsFunc(Relation relation, int elevel,
errmsg("remote server does not support TABLESAMPLE feature")));
/*
- * For "auto" method, pick the one we believe is best. For servers with
- * TABLESAMPLE support we pick BERNOULLI, for old servers we fall-back to
- * random() to at least reduce network transfer.
- */
- if (method == ANALYZE_SAMPLE_AUTO)
- {
- if (server_version_num < 95000)
- method = ANALYZE_SAMPLE_RANDOM;
- else
- method = ANALYZE_SAMPLE_BERNOULLI;
- }
-
- /*
* If we've decided to do remote sampling, calculate the sampling rate. We
* need to get the number of tuples from the remote server, but skip that
* network round-trip if not needed.
*/
if (method != ANALYZE_SAMPLE_OFF)
{
- reltuples = postgresCountTuplesForForeignTable(relation);
+ bool can_tablesample;
+
+ reltuples = postgresGetAnalyzeInfoForForeignTable(relation,
+ &can_tablesample);
+
+ /*
+ * Make sure we're not choosing TABLESAMPLE when the remote relation does
+ * not support that. But only do this for "auto" - if the user explicitly
+ * requested BERNOULLI/SYSTEM, it's better to fail.
+ */
+ if (!can_tablesample && (method == ANALYZE_SAMPLE_AUTO))
+ method = ANALYZE_SAMPLE_RANDOM;
/*
* Remote's reltuples could be 0 or -1 if the table has never been
@@ -5213,6 +5224,19 @@ postgresAcquireSampleRowsFunc(Relation relation, int elevel,
}
/*
+ * For "auto" method, pick the one we believe is best. For servers with
+ * TABLESAMPLE support we pick BERNOULLI, for old servers we fall-back to
+ * random() to at least reduce network transfer.
+ */
+ if (method == ANALYZE_SAMPLE_AUTO)
+ {
+ if (server_version_num < 95000)
+ method = ANALYZE_SAMPLE_RANDOM;
+ else
+ method = ANALYZE_SAMPLE_BERNOULLI;
+ }
+
+ /*
* Construct cursor that retrieves whole rows from remote.
*/
cursor_number = GetCursorNumber(conn);