Commit cc592c48 authored by Robert Haas's avatar Robert Haas

postgres_fdw: More preliminary refactoring for upcoming join pushdown.

The code that generates a complete SQL query for a given foreign relation
was repeated in two places, and they didn't quite agree: the EXPLAIN case
left out the locking clause.  Centralize the code so we get the same
behavior everywhere, and adjust calling conventions and which functions
are static vs. extern accordingly .  Centralize the code so we get the same
behavior everywhere, and adjust calling conventions and which functions
are static vs. extern accordingly.

Ashutosh Bapat, reviewed and slightly adjusted by me.
parent 2251179e
...@@ -141,6 +141,11 @@ static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod, ...@@ -141,6 +141,11 @@ static void printRemoteParam(int paramindex, Oid paramtype, int32 paramtypmod,
deparse_expr_cxt *context); deparse_expr_cxt *context);
static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod, static void printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
deparse_expr_cxt *context); deparse_expr_cxt *context);
static void deparseSelectSql(Bitmapset *attrs_used, List **retrieved_attrs,
deparse_expr_cxt *context);
static void deparseLockingClause(deparse_expr_cxt *context);
static void appendWhereClause(List *exprs, deparse_expr_cxt *context);
static void appendOrderByClause(List *pathkeys, deparse_expr_cxt *context);
/* /*
...@@ -697,6 +702,51 @@ deparse_type_name(Oid type_oid, int32 typemod) ...@@ -697,6 +702,51 @@ deparse_type_name(Oid type_oid, int32 typemod)
return format_type_with_typemod_qualified(type_oid, typemod); return format_type_with_typemod_qualified(type_oid, typemod);
} }
/*
* Deparse SELECT statement for given relation into buf.
*
* remote_conds is the list of conditions to be deparsed as WHERE clause.
*
* pathkeys is the list of pathkeys to order the result by.
*
* List of columns selected is returned in retrieved_attrs.
*
* If params_list is not NULL, it receives a list of Params and other-relation
* Vars used in the clauses; these values must be transmitted to the remote
* server as parameter values.
*
* If params_list is NULL, we're generating the query for EXPLAIN purposes,
* so Params and other-relation Vars should be replaced by dummy values.
*/
extern void
deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel,
List *remote_conds, List *pathkeys,
List **retrieved_attrs, List **params_list)
{
PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) rel->fdw_private;
deparse_expr_cxt context;
/* Initialize params_list if caller needs one */
if (params_list)
*params_list = NIL;
context.buf = buf;
context.root = root;
context.foreignrel = rel;
context.params_list = params_list;
deparseSelectSql(fpinfo->attrs_used, retrieved_attrs, &context);
if (remote_conds)
appendWhereClause(remote_conds, &context);
/* Add ORDER BY clause if we found any useful pathkeys */
if (pathkeys)
appendOrderByClause(pathkeys, &context);
/* Add any necessary FOR UPDATE/SHARE. */
deparseLockingClause(&context);
}
/* /*
* Construct a simple SELECT statement that retrieves desired columns * Construct a simple SELECT statement that retrieves desired columns
...@@ -707,13 +757,13 @@ deparse_type_name(Oid type_oid, int32 typemod) ...@@ -707,13 +757,13 @@ deparse_type_name(Oid type_oid, int32 typemod)
* returned to *retrieved_attrs. * returned to *retrieved_attrs.
*/ */
void void
deparseSelectSql(StringInfo buf, deparseSelectSql(Bitmapset *attrs_used, List **retrieved_attrs,
PlannerInfo *root, deparse_expr_cxt *context)
RelOptInfo *baserel,
Bitmapset *attrs_used,
List **retrieved_attrs)
{ {
RangeTblEntry *rte = planner_rt_fetch(baserel->relid, root); StringInfo buf = context->buf;
RelOptInfo *foreignrel = context->foreignrel;
PlannerInfo *root = context->root;
RangeTblEntry *rte = planner_rt_fetch(foreignrel->relid, root);
Relation rel; Relation rel;
/* /*
...@@ -726,7 +776,7 @@ deparseSelectSql(StringInfo buf, ...@@ -726,7 +776,7 @@ deparseSelectSql(StringInfo buf,
* Construct SELECT list * Construct SELECT list
*/ */
appendStringInfoString(buf, "SELECT "); appendStringInfoString(buf, "SELECT ");
deparseTargetList(buf, root, baserel->relid, rel, attrs_used, deparseTargetList(buf, root, foreignrel->relid, rel, attrs_used,
retrieved_attrs); retrieved_attrs);
/* /*
...@@ -811,11 +861,15 @@ deparseTargetList(StringInfo buf, ...@@ -811,11 +861,15 @@ deparseTargetList(StringInfo buf,
/* /*
* Deparse the appropriate locking clause (FOR SELECT or FOR SHARE) for a * Deparse the appropriate locking clause (FOR SELECT or FOR SHARE) for a
* given relation. * given relation (context->foreignrel).
*/ */
void static void
deparseLockingClause(StringInfo buf, PlannerInfo *root, RelOptInfo *rel) deparseLockingClause(deparse_expr_cxt *context)
{ {
StringInfo buf = context->buf;
PlannerInfo *root = context->root;
RelOptInfo *rel = context->foreignrel;
/* /*
* Add FOR UPDATE/SHARE if appropriate. We apply locking during the * Add FOR UPDATE/SHARE if appropriate. We apply locking during the
* initial row fetch, rather than later on as is done for local tables. * initial row fetch, rather than later on as is done for local tables.
...@@ -868,39 +922,16 @@ deparseLockingClause(StringInfo buf, PlannerInfo *root, RelOptInfo *rel) ...@@ -868,39 +922,16 @@ deparseLockingClause(StringInfo buf, PlannerInfo *root, RelOptInfo *rel)
} }
/* /*
* Deparse WHERE clauses in given list of RestrictInfos and append them to buf. * Deparse WHERE clauses in given list of RestrictInfos and append them to
* * context->buf.
* baserel is the foreign table we're planning for.
*
* If no WHERE clause already exists in the buffer, is_first should be true.
*
* If params is not NULL, it receives a list of Params and other-relation Vars
* used in the clauses; these values must be transmitted to the remote server
* as parameter values.
*
* If params is NULL, we're generating the query for EXPLAIN purposes,
* so Params and other-relation Vars should be replaced by dummy values.
*/ */
void static void
appendWhereClause(StringInfo buf, appendWhereClause(List *exprs, deparse_expr_cxt *context)
PlannerInfo *root,
RelOptInfo *baserel,
List *exprs,
bool is_first,
List **params)
{ {
deparse_expr_cxt context;
int nestlevel; int nestlevel;
ListCell *lc; ListCell *lc;
bool is_first = true;
if (params) StringInfo buf = context->buf;
*params = NIL; /* initialize result list to empty */
/* Set up context struct for recursion */
context.root = root;
context.foreignrel = baserel;
context.buf = buf;
context.params_list = params;
/* Make sure any constants in the exprs are printed portably */ /* Make sure any constants in the exprs are printed portably */
nestlevel = set_transmission_modes(); nestlevel = set_transmission_modes();
...@@ -916,7 +947,7 @@ appendWhereClause(StringInfo buf, ...@@ -916,7 +947,7 @@ appendWhereClause(StringInfo buf,
appendStringInfoString(buf, " AND "); appendStringInfoString(buf, " AND ");
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
deparseExpr(ri->clause, &context); deparseExpr(ri->clause, context);
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
is_first = false; is_first = false;
...@@ -1946,20 +1977,14 @@ printRemotePlaceholder(Oid paramtype, int32 paramtypmod, ...@@ -1946,20 +1977,14 @@ printRemotePlaceholder(Oid paramtype, int32 paramtypmod,
* relation. From given pathkeys expressions belonging entirely to the given * relation. From given pathkeys expressions belonging entirely to the given
* base relation are obtained and deparsed. * base relation are obtained and deparsed.
*/ */
void static void
appendOrderByClause(StringInfo buf, PlannerInfo *root, RelOptInfo *baserel, appendOrderByClause(List *pathkeys, deparse_expr_cxt *context)
List *pathkeys)
{ {
ListCell *lcell; ListCell *lcell;
deparse_expr_cxt context;
int nestlevel; int nestlevel;
char *delim = " "; char *delim = " ";
RelOptInfo *baserel = context->foreignrel;
/* Set up context struct for recursion */ StringInfo buf = context->buf;
context.root = root;
context.foreignrel = baserel;
context.buf = buf;
context.params_list = NULL;
/* Make sure any constants in the exprs are printed portably */ /* Make sure any constants in the exprs are printed portably */
nestlevel = set_transmission_modes(); nestlevel = set_transmission_modes();
...@@ -1974,7 +1999,7 @@ appendOrderByClause(StringInfo buf, PlannerInfo *root, RelOptInfo *baserel, ...@@ -1974,7 +1999,7 @@ appendOrderByClause(StringInfo buf, PlannerInfo *root, RelOptInfo *baserel,
Assert(em_expr != NULL); Assert(em_expr != NULL);
appendStringInfoString(buf, delim); appendStringInfoString(buf, delim);
deparseExpr(em_expr, &context); deparseExpr(em_expr, context);
if (pathkey->pk_strategy == BTLessStrategyNumber) if (pathkey->pk_strategy == BTLessStrategyNumber)
appendStringInfoString(buf, " ASC"); appendStringInfoString(buf, " ASC");
else else
......
...@@ -1003,19 +1003,9 @@ postgresGetForeignPlan(PlannerInfo *root, ...@@ -1003,19 +1003,9 @@ postgresGetForeignPlan(PlannerInfo *root,
* expressions to be sent as parameters. * expressions to be sent as parameters.
*/ */
initStringInfo(&sql); initStringInfo(&sql);
deparseSelectSql(&sql, root, baserel, fpinfo->attrs_used, deparseSelectStmtForRel(&sql, root, baserel, remote_conds,
&retrieved_attrs); best_path->path.pathkeys, &retrieved_attrs,
if (remote_conds) &params_list);
appendWhereClause(&sql, root, baserel, remote_conds,
true, &params_list);
/* Add ORDER BY clause if we found any useful pathkeys */
if (best_path->path.pathkeys)
appendOrderByClause(&sql, root, baserel, best_path->path.pathkeys);
/* Add any necessary FOR UPDATE/SHARE. */
deparseLockingClause(&sql, root, baserel);
/* /*
* Build the fdw_private list that will be available to the executor. * Build the fdw_private list that will be available to the executor.
* Items in the list must match enum FdwScanPrivateIndex, above. * Items in the list must match enum FdwScanPrivateIndex, above.
...@@ -1909,6 +1899,7 @@ estimate_path_cost_size(PlannerInfo *root, ...@@ -1909,6 +1899,7 @@ estimate_path_cost_size(PlannerInfo *root,
PGconn *conn; PGconn *conn;
Selectivity local_sel; Selectivity local_sel;
QualCost local_cost; QualCost local_cost;
List *remote_conds;
/* /*
* join_conds might contain both clauses that are safe to send across, * join_conds might contain both clauses that are safe to send across,
...@@ -1917,6 +1908,14 @@ estimate_path_cost_size(PlannerInfo *root, ...@@ -1917,6 +1908,14 @@ estimate_path_cost_size(PlannerInfo *root,
classifyConditions(root, baserel, join_conds, classifyConditions(root, baserel, join_conds,
&remote_join_conds, &local_join_conds); &remote_join_conds, &local_join_conds);
/*
* The complete list of remote conditions includes everything from
* baserestrictinfo plus any extra join_conds relevant to this
* particular path.
*/
remote_conds = list_concat(list_copy(remote_join_conds),
fpinfo->remote_conds);
/* /*
* Construct EXPLAIN query including the desired SELECT, FROM, and * Construct EXPLAIN query including the desired SELECT, FROM, and
* WHERE clauses. Params and other-relation Vars are replaced by * WHERE clauses. Params and other-relation Vars are replaced by
...@@ -1924,17 +1923,8 @@ estimate_path_cost_size(PlannerInfo *root, ...@@ -1924,17 +1923,8 @@ estimate_path_cost_size(PlannerInfo *root,
*/ */
initStringInfo(&sql); initStringInfo(&sql);
appendStringInfoString(&sql, "EXPLAIN "); appendStringInfoString(&sql, "EXPLAIN ");
deparseSelectSql(&sql, root, baserel, fpinfo->attrs_used, deparseSelectStmtForRel(&sql, root, baserel, remote_conds, pathkeys,
&retrieved_attrs); &retrieved_attrs, NULL);
if (fpinfo->remote_conds)
appendWhereClause(&sql, root, baserel, fpinfo->remote_conds,
true, NULL);
if (remote_join_conds)
appendWhereClause(&sql, root, baserel, remote_join_conds,
(fpinfo->remote_conds == NIL), NULL);
if (pathkeys)
appendOrderByClause(&sql, root, baserel, pathkeys);
/* Get the remote estimate */ /* Get the remote estimate */
conn = GetConnection(fpinfo->user, false); conn = GetConnection(fpinfo->user, false);
......
...@@ -83,19 +83,6 @@ extern void classifyConditions(PlannerInfo *root, ...@@ -83,19 +83,6 @@ extern void classifyConditions(PlannerInfo *root,
extern bool is_foreign_expr(PlannerInfo *root, extern bool is_foreign_expr(PlannerInfo *root,
RelOptInfo *baserel, RelOptInfo *baserel,
Expr *expr); Expr *expr);
extern void deparseSelectSql(StringInfo buf,
PlannerInfo *root,
RelOptInfo *baserel,
Bitmapset *attrs_used,
List **retrieved_attrs);
extern void deparseLockingClause(StringInfo buf,
PlannerInfo *root, RelOptInfo *rel);
extern void appendWhereClause(StringInfo buf,
PlannerInfo *root,
RelOptInfo *baserel,
List *exprs,
bool is_first,
List **params);
extern void deparseInsertSql(StringInfo buf, PlannerInfo *root, extern void deparseInsertSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel, Index rtindex, Relation rel,
List *targetAttrs, bool doNothing, List *returningList, List *targetAttrs, bool doNothing, List *returningList,
...@@ -113,8 +100,9 @@ extern void deparseAnalyzeSql(StringInfo buf, Relation rel, ...@@ -113,8 +100,9 @@ extern void deparseAnalyzeSql(StringInfo buf, Relation rel,
List **retrieved_attrs); List **retrieved_attrs);
extern void deparseStringLiteral(StringInfo buf, const char *val); extern void deparseStringLiteral(StringInfo buf, const char *val);
extern Expr *find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel); extern Expr *find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel);
extern void appendOrderByClause(StringInfo buf, PlannerInfo *root, extern void deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root,
RelOptInfo *baserel, List *pathkeys); RelOptInfo *baserel, List *remote_conds, List *pathkeys,
List **retrieved_attrs, List **params_list);
/* in shippable.c */ /* in shippable.c */
extern bool is_builtin(Oid objectId); extern bool is_builtin(Oid objectId);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment