diff options
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 253 |
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 */ } |