aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c253
1 files changed, 89 insertions, 164 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 0018ffc6a8a..116e00bce4e 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -271,7 +271,8 @@ typedef struct
* child RTE's attno and rightattnos[i] is zero; and conversely for a
* column of the right child. But for merged columns produced by JOIN
* USING/NATURAL JOIN, both leftattnos[i] and rightattnos[i] are nonzero.
- * Also, if the column has been dropped, both are zero.
+ * Note that a simple reference might be to a child RTE column that's been
+ * dropped; but that's OK since the column could not be used in the query.
*
* If it's a JOIN USING, usingNames holds the alias names selected for the
* merged columns (these might be different from the original USING list,
@@ -368,8 +369,6 @@ static char *make_colname_unique(char *colname, deparse_namespace *dpns,
static void expand_colnames_array_to(deparse_columns *colinfo, int n);
static void identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
deparse_columns *colinfo);
-static void flatten_join_using_qual(Node *qual,
- List **leftvars, List **rightvars);
static char *get_rtable_name(int rtindex, deparse_context *context);
static void set_deparse_plan(deparse_namespace *dpns, Plan *plan);
static void push_child_plan(deparse_namespace *dpns, Plan *plan,
@@ -3722,13 +3721,13 @@ has_dangerous_join_using(deparse_namespace *dpns, Node *jtnode)
* dangerous situation and must pick unique aliases.
*/
RangeTblEntry *jrte = rt_fetch(j->rtindex, dpns->rtable);
- ListCell *lc;
- foreach(lc, jrte->joinaliasvars)
+ /* We need only examine the merged columns */
+ for (int i = 0; i < jrte->joinmergedcols; i++)
{
- Var *aliasvar = (Var *) lfirst(lc);
+ Node *aliasvar = list_nth(jrte->joinaliasvars, i);
- if (aliasvar != NULL && !IsA(aliasvar, Var))
+ if (!IsA(aliasvar, Var))
return true;
}
}
@@ -4137,12 +4136,8 @@ set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
char *colname = colinfo->colnames[i];
char *real_colname;
- /* Ignore dropped column (only possible for non-merged column) */
- if (colinfo->leftattnos[i] == 0 && colinfo->rightattnos[i] == 0)
- {
- Assert(colname == NULL);
- continue;
- }
+ /* Join column must refer to at least one input column */
+ Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
/* Get the child column name */
if (colinfo->leftattnos[i] > 0)
@@ -4154,7 +4149,13 @@ set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
/* We're joining system columns --- use eref name */
real_colname = strVal(list_nth(rte->eref->colnames, i));
}
- Assert(real_colname != NULL);
+
+ /* If child col has been dropped, no need to assign a join colname */
+ if (real_colname == NULL)
+ {
+ colinfo->colnames[i] = NULL;
+ continue;
+ }
/* In an unnamed join, just report child column names as-is */
if (rte->alias == NULL)
@@ -4479,7 +4480,8 @@ identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
deparse_columns *colinfo)
{
int numjoincols;
- int i;
+ int jcolno;
+ int rcolno;
ListCell *lc;
/* Extract left/right child RT indexes */
@@ -4508,146 +4510,32 @@ identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
- /* Scan the joinaliasvars list to identify simple column references */
- i = 0;
- foreach(lc, jrte->joinaliasvars)
- {
- Var *aliasvar = (Var *) lfirst(lc);
-
- /* get rid of any implicit coercion above the Var */
- aliasvar = (Var *) strip_implicit_coercions((Node *) aliasvar);
-
- if (aliasvar == NULL)
- {
- /* It's a dropped column; nothing to do here */
- }
- else if (IsA(aliasvar, Var))
- {
- Assert(aliasvar->varlevelsup == 0);
- Assert(aliasvar->varattno != 0);
- if (aliasvar->varno == colinfo->leftrti)
- colinfo->leftattnos[i] = aliasvar->varattno;
- else if (aliasvar->varno == colinfo->rightrti)
- colinfo->rightattnos[i] = aliasvar->varattno;
- else
- elog(ERROR, "unexpected varno %d in JOIN RTE",
- aliasvar->varno);
- }
- else if (IsA(aliasvar, CoalesceExpr))
- {
- /*
- * It's a merged column in FULL JOIN USING. Ignore it for now and
- * let the code below identify the merged columns.
- */
- }
- else
- elog(ERROR, "unrecognized node type in join alias vars: %d",
- (int) nodeTag(aliasvar));
-
- i++;
- }
-
/*
- * If there's a USING clause, deconstruct the join quals to identify the
- * merged columns. This is a tad painful but if we cannot rely on the
- * column names, there is no other representation of which columns were
- * joined by USING. (Unless the join type is FULL, we can't tell from the
- * joinaliasvars list which columns are merged.) Note: we assume that the
- * merged columns are the first output column(s) of the join.
+ * Deconstruct RTE's joinleftcols/joinrightcols into desired format.
+ * Recall that the column(s) merged due to USING are the first column(s)
+ * of the join output. We need not do anything special while scanning
+ * joinleftcols, but while scanning joinrightcols we must distinguish
+ * merged from unmerged columns.
*/
- if (j->usingClause)
- {
- List *leftvars = NIL;
- List *rightvars = NIL;
- ListCell *lc2;
-
- /* Extract left- and right-side Vars from the qual expression */
- flatten_join_using_qual(j->quals, &leftvars, &rightvars);
- Assert(list_length(leftvars) == list_length(j->usingClause));
- Assert(list_length(rightvars) == list_length(j->usingClause));
-
- /* Mark the output columns accordingly */
- i = 0;
- forboth(lc, leftvars, lc2, rightvars)
- {
- Var *leftvar = (Var *) lfirst(lc);
- Var *rightvar = (Var *) lfirst(lc2);
-
- Assert(leftvar->varlevelsup == 0);
- Assert(leftvar->varattno != 0);
- if (leftvar->varno != colinfo->leftrti)
- elog(ERROR, "unexpected varno %d in JOIN USING qual",
- leftvar->varno);
- colinfo->leftattnos[i] = leftvar->varattno;
-
- Assert(rightvar->varlevelsup == 0);
- Assert(rightvar->varattno != 0);
- if (rightvar->varno != colinfo->rightrti)
- elog(ERROR, "unexpected varno %d in JOIN USING qual",
- rightvar->varno);
- colinfo->rightattnos[i] = rightvar->varattno;
-
- i++;
- }
- }
-}
-
-/*
- * flatten_join_using_qual: extract Vars being joined from a JOIN/USING qual
- *
- * We assume that transformJoinUsingClause won't have produced anything except
- * AND nodes, equality operator nodes, and possibly implicit coercions, and
- * that the AND node inputs match left-to-right with the original USING list.
- *
- * Caller must initialize the result lists to NIL.
- */
-static void
-flatten_join_using_qual(Node *qual, List **leftvars, List **rightvars)
-{
- if (IsA(qual, BoolExpr))
+ jcolno = 0;
+ foreach(lc, jrte->joinleftcols)
{
- /* Handle AND nodes by recursion */
- BoolExpr *b = (BoolExpr *) qual;
- ListCell *lc;
+ int leftattno = lfirst_int(lc);
- Assert(b->boolop == AND_EXPR);
- foreach(lc, b->args)
- {
- flatten_join_using_qual((Node *) lfirst(lc),
- leftvars, rightvars);
- }
+ colinfo->leftattnos[jcolno++] = leftattno;
}
- else if (IsA(qual, OpExpr))
- {
- /* Otherwise we should have an equality operator */
- OpExpr *op = (OpExpr *) qual;
- Var *var;
-
- if (list_length(op->args) != 2)
- elog(ERROR, "unexpected unary operator in JOIN/USING qual");
- /* Arguments should be Vars with perhaps implicit coercions */
- var = (Var *) strip_implicit_coercions((Node *) linitial(op->args));
- if (!IsA(var, Var))
- elog(ERROR, "unexpected node type in JOIN/USING qual: %d",
- (int) nodeTag(var));
- *leftvars = lappend(*leftvars, var);
- var = (Var *) strip_implicit_coercions((Node *) lsecond(op->args));
- if (!IsA(var, Var))
- elog(ERROR, "unexpected node type in JOIN/USING qual: %d",
- (int) nodeTag(var));
- *rightvars = lappend(*rightvars, var);
- }
- else
+ rcolno = 0;
+ foreach(lc, jrte->joinrightcols)
{
- /* Perhaps we have an implicit coercion to boolean? */
- Node *q = strip_implicit_coercions(qual);
+ int rightattno = lfirst_int(lc);
- if (q != qual)
- flatten_join_using_qual(q, leftvars, rightvars);
+ if (rcolno < jrte->joinmergedcols) /* merged column? */
+ colinfo->rightattnos[rcolno] = rightattno;
else
- elog(ERROR, "unexpected node type in JOIN/USING qual: %d",
- (int) nodeTag(qual));
+ colinfo->rightattnos[jcolno++] = rightattno;
+ rcolno++;
}
+ Assert(jcolno == numjoincols);
}
/*
@@ -6717,6 +6605,8 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
AttrNumber attnum;
int netlevelsup;
deparse_namespace *dpns;
+ Index varno;
+ AttrNumber varattno;
deparse_columns *colinfo;
char *refname;
char *attname;
@@ -6730,16 +6620,32 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
netlevelsup);
/*
+ * If we have a syntactic referent for the Var, and we're working from a
+ * parse tree, prefer to use the syntactic referent. Otherwise, fall back
+ * on the semantic referent. (Forcing use of the semantic referent when
+ * printing plan trees is a design choice that's perhaps more motivated by
+ * backwards compatibility than anything else. But it does have the
+ * advantage of making plans more explicit.)
+ */
+ if (var->varnosyn > 0 && dpns->plan == NULL)
+ {
+ varno = var->varnosyn;
+ varattno = var->varattnosyn;
+ }
+ else
+ {
+ varno = var->varno;
+ varattno = var->varattno;
+ }
+
+ /*
* Try to find the relevant RTE in this rtable. In a plan tree, it's
* likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
* down into the subplans, or INDEX_VAR, which is resolved similarly. Also
* find the aliases previously assigned for this RTE.
*/
- if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
+ if (varno >= 1 && varno <= list_length(dpns->rtable))
{
- Index varno = var->varno;
- AttrNumber varattno = var->varattno;
-
/*
* We might have been asked to map child Vars to some parent relation.
*/
@@ -6962,7 +6868,8 @@ resolve_special_varno(Node *node, deparse_context *context,
var->varlevelsup);
/*
- * If varno is special, recurse.
+ * If varno is special, recurse. (Don't worry about varnosyn; if we're
+ * here, we already decided not to use that.)
*/
if (var->varno == OUTER_VAR && dpns->outer_tlist)
{
@@ -7054,6 +6961,8 @@ get_name_for_var_field(Var *var, int fieldno,
AttrNumber attnum;
int netlevelsup;
deparse_namespace *dpns;
+ Index varno;
+ AttrNumber varattno;
TupleDesc tupleDesc;
Node *expr;
@@ -7114,6 +7023,22 @@ get_name_for_var_field(Var *var, int fieldno,
netlevelsup);
/*
+ * If we have a syntactic referent for the Var, and we're working from a
+ * parse tree, prefer to use the syntactic referent. Otherwise, fall back
+ * on the semantic referent. (See comments in get_variable().)
+ */
+ if (var->varnosyn > 0 && dpns->plan == NULL)
+ {
+ varno = var->varnosyn;
+ varattno = var->varattnosyn;
+ }
+ else
+ {
+ varno = var->varno;
+ varattno = var->varattno;
+ }
+
+ /*
* Try to find the relevant RTE in this rtable. In a plan tree, it's
* likely that varno is OUTER_VAR or INNER_VAR, in which case we must dig
* down into the subplans, or INDEX_VAR, which is resolved similarly.
@@ -7122,20 +7047,20 @@ get_name_for_var_field(Var *var, int fieldno,
* about inheritance mapping: a child Var should have the same datatype as
* its parent, and here we're really only interested in the Var's type.
*/
- if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
+ if (varno >= 1 && varno <= list_length(dpns->rtable))
{
- rte = rt_fetch(var->varno, dpns->rtable);
- attnum = var->varattno;
+ rte = rt_fetch(varno, dpns->rtable);
+ attnum = varattno;
}
- else if (var->varno == OUTER_VAR && dpns->outer_tlist)
+ else if (varno == OUTER_VAR && dpns->outer_tlist)
{
TargetEntry *tle;
deparse_namespace save_dpns;
const char *result;
- tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
+ tle = get_tle_by_resno(dpns->outer_tlist, varattno);
if (!tle)
- elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
+ elog(ERROR, "bogus varattno for OUTER_VAR var: %d", varattno);
Assert(netlevelsup == 0);
push_child_plan(dpns, dpns->outer_plan, &save_dpns);
@@ -7146,15 +7071,15 @@ get_name_for_var_field(Var *var, int fieldno,
pop_child_plan(dpns, &save_dpns);
return result;
}
- else if (var->varno == INNER_VAR && dpns->inner_tlist)
+ else if (varno == INNER_VAR && dpns->inner_tlist)
{
TargetEntry *tle;
deparse_namespace save_dpns;
const char *result;
- tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
+ tle = get_tle_by_resno(dpns->inner_tlist, varattno);
if (!tle)
- elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
+ elog(ERROR, "bogus varattno for INNER_VAR var: %d", varattno);
Assert(netlevelsup == 0);
push_child_plan(dpns, dpns->inner_plan, &save_dpns);
@@ -7165,14 +7090,14 @@ get_name_for_var_field(Var *var, int fieldno,
pop_child_plan(dpns, &save_dpns);
return result;
}
- else if (var->varno == INDEX_VAR && dpns->index_tlist)
+ else if (varno == INDEX_VAR && dpns->index_tlist)
{
TargetEntry *tle;
const char *result;
- tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
+ tle = get_tle_by_resno(dpns->index_tlist, varattno);
if (!tle)
- elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
+ elog(ERROR, "bogus varattno for INDEX_VAR var: %d", varattno);
Assert(netlevelsup == 0);
@@ -7183,7 +7108,7 @@ get_name_for_var_field(Var *var, int fieldno,
}
else
{
- elog(ERROR, "bogus varno: %d", var->varno);
+ elog(ERROR, "bogus varno: %d", varno);
return NULL; /* keep compiler quiet */
}