aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/postgres_fdw/deparse.c7
-rw-r--r--contrib/postgres_fdw/postgres_fdw.c60
-rw-r--r--contrib/postgres_fdw/postgres_fdw.h2
3 files changed, 47 insertions, 22 deletions
diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 4461fb06f02..21237d18ef8 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -2368,14 +2368,15 @@ deparseAnalyzeSizeSql(StringInfo buf, Relation rel)
}
/*
- * Construct SELECT statement to acquire the number of rows of a relation.
+ * Construct SELECT statement to acquire the number of rows and the relkind of
+ * a relation.
*
* Note: we just return the remote server's reltuples value, which might
* be off a good deal, but it doesn't seem worth working harder. See
* comments in postgresAcquireSampleRowsFunc.
*/
void
-deparseAnalyzeTuplesSql(StringInfo buf, Relation rel)
+deparseAnalyzeInfoSql(StringInfo buf, Relation rel)
{
StringInfoData relname;
@@ -2383,7 +2384,7 @@ deparseAnalyzeTuplesSql(StringInfo buf, Relation rel)
initStringInfo(&relname);
deparseRelation(&relname, rel);
- appendStringInfoString(buf, "SELECT reltuples FROM pg_catalog.pg_class WHERE oid = ");
+ appendStringInfoString(buf, "SELECT reltuples, relkind FROM pg_catalog.pg_class WHERE oid = ");
deparseStringLiteral(buf, relname.data);
appendStringInfoString(buf, "::pg_catalog.regclass");
}
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);
diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h
index 4a633c5357f..02c11523199 100644
--- a/contrib/postgres_fdw/postgres_fdw.h
+++ b/contrib/postgres_fdw/postgres_fdw.h
@@ -223,7 +223,7 @@ extern void deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root,
List *returningList,
List **retrieved_attrs);
extern void deparseAnalyzeSizeSql(StringInfo buf, Relation rel);
-extern void deparseAnalyzeTuplesSql(StringInfo buf, Relation rel);
+extern void deparseAnalyzeInfoSql(StringInfo buf, Relation rel);
extern void deparseAnalyzeSql(StringInfo buf, Relation rel,
PgFdwSamplingMethod sample_method,
double sample_frac,