newvar = (Node *) lfirst(lv);
attnum++;
/* Ignore dropped columns */
- if (IsA(newvar, Const))
+ if (newvar == NULL)
continue;
newvar = copyObject(newvar);
/* Expand join alias reference */
Assert(var->varattno > 0);
newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
+ Assert(newvar != NULL);
newvar = copyObject(newvar);
/*
#include "funcapi.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
+#include "optimizer/clauses.h"
#include "parser/parsetree.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
* The aliasvar could be either a Var or a COALESCE expression,
* but in the latter case we should already have marked the two
* referent variables as being selected, due to their use in the
- * JOIN clause. So we need only be concerned with the simple Var
- * case.
+ * JOIN clause. So we need only be concerned with the Var case.
+ * But we do need to drill down through implicit coercions.
*/
Var *aliasvar;
Assert(col > 0 && col <= list_length(rte->joinaliasvars));
aliasvar = (Var *) list_nth(rte->joinaliasvars, col - 1);
- if (IsA(aliasvar, Var))
+ aliasvar = (Var *) strip_implicit_coercions((Node *) aliasvar);
+ if (aliasvar && IsA(aliasvar, Var))
markVarForSelectPriv(pstate, aliasvar, NULL);
}
}
* deleted columns in the join; but we have to check since
* this routine is also used by the rewriter, and joins
* found in stored rules might have join columns for
- * since-deleted columns. This will be signaled by a NULL
- * Const in the alias-vars list.
+ * since-deleted columns. This will be signaled by a null
+ * pointer in the alias-vars list.
*/
- if (IsA(avar, Const))
+ if (avar == NULL)
{
if (include_dropped)
{
*colnames = lappend(*colnames,
makeString(pstrdup("")));
if (colvars)
+ {
+ /*
+ * Can't use join's column type here (it might
+ * be dropped!); but it doesn't really matter
+ * what type the Const claims to be.
+ */
*colvars = lappend(*colvars,
- copyObject(avar));
+ makeNullConst(INT4OID, -1,
+ InvalidOid));
+ }
}
continue;
}
Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
aliasvar = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
+ Assert(aliasvar != NULL);
*vartype = exprType(aliasvar);
*vartypmod = exprTypmod(aliasvar);
*varcollid = exprCollation(aliasvar);
* but one in a stored rule might contain columns that were
* dropped from the underlying tables, if said columns are
* nowhere explicitly referenced in the rule. This will be
- * signaled to us by a NULL Const in the joinaliasvars list.
+ * signaled to us by a null pointer in the joinaliasvars list.
*/
Var *aliasvar;
elog(ERROR, "invalid varattno %d", attnum);
aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
- result = IsA(aliasvar, Const);
+ result = (aliasvar == NULL);
}
break;
case RTE_FUNCTION:
Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
+ /* We intentionally don't strip implicit coercions here */
markTargetListOrigin(pstate, tle, aliasvar, netlevelsup);
}
break;
/* Join RTE --- recursively inspect the alias variable */
Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
+ Assert(expr != NULL);
+ /* We intentionally don't strip implicit coercions here */
if (IsA(expr, Var))
return expandRecordVariable(pstate, (Var *) expr, netlevelsup);
/* else fall through to inspect the expression */
#include "commands/trigger.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
+#include "optimizer/clauses.h"
#include "parser/analyze.h"
#include "parser/parse_coerce.h"
#include "parser/parsetree.h"
* such a list in a stored rule to include references to dropped columns.
* (If the column is not explicitly referenced anywhere else in the query,
* the dependency mechanism won't consider it used by the rule and so won't
- * prevent the column drop.) To support get_rte_attribute_is_dropped(),
- * we replace join alias vars that reference dropped columns with NULL Const
- * nodes.
+ * prevent the column drop.) To support get_rte_attribute_is_dropped(), we
+ * replace join alias vars that reference dropped columns with null pointers.
*
* (In PostgreSQL 8.0, we did not do this processing but instead had
* get_rte_attribute_is_dropped() recurse to detect dropped columns in joins.
/*
* Scan the join's alias var list to see if any columns have
- * been dropped, and if so replace those Vars with NULL
- * Consts.
+ * been dropped, and if so replace those Vars with null
+ * pointers.
*
* Since a join has only two inputs, we can expect to see
* multiple references to the same input RTE; optimize away
curinputrte = NULL;
foreach(ll, rte->joinaliasvars)
{
- Var *aliasvar = (Var *) lfirst(ll);
+ Var *aliasitem = (Var *) lfirst(ll);
+ Var *aliasvar = aliasitem;
+
+ /* Look through any implicit coercion */
+ aliasvar = (Var *) strip_implicit_coercions((Node *) aliasvar);
/*
* If the list item isn't a simple Var, then it must
* represent a merged column, ie a USING column, and so it
* couldn't possibly be dropped, since it's referenced in
- * the join clause. (Conceivably it could also be a NULL
- * constant already? But that's OK too.)
+ * the join clause. (Conceivably it could also be a null
+ * pointer already? But that's OK too.)
*/
- if (IsA(aliasvar, Var))
+ if (aliasvar && IsA(aliasvar, Var))
{
/*
* The elements of an alias list have to refer to
if (get_rte_attribute_is_dropped(curinputrte,
aliasvar->varattno))
{
- /*
- * can't use vartype here, since that might be a
- * now-dropped type OID, but it doesn't really
- * matter what type the Const claims to be.
- */
- aliasvar = (Var *) makeNullConst(INT4OID, -1, InvalidOid);
+ /* Replace the join alias item with a NULL */
+ aliasitem = NULL;
}
}
- newaliasvars = lappend(newaliasvars, aliasvar);
+ newaliasvars = lappend(newaliasvars, aliasitem);
}
rte->joinaliasvars = newaliasvars;
break;
Var *aliasvar;
aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
- if (IsA(aliasvar, Var))
+ /* we intentionally don't strip implicit coercions here */
+ if (aliasvar && IsA(aliasvar, Var))
{
return get_variable(aliasvar, var->varlevelsup + levelsup,
istoplevel, context);
elog(ERROR, "cannot decompile join alias var in plan tree");
Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
+ Assert(expr != NULL);
+ /* we intentionally don't strip implicit coercions here */
if (IsA(expr, Var))
return get_name_for_var_field((Var *) expr, fieldno,
var->varlevelsup + levelsup,
* a stored rule might contain entries for columns dropped since the rule
* was created. (This is only possible for columns not actually referenced
* in the rule.) When loading a stored rule, we replace the joinaliasvars
- * items for any such columns with NULL Consts. (We can't simply delete
+ * items for any such columns with null pointers. (We can't simply delete
* them from the joinaliasvars list, because that would affect the attnums
* of Vars referencing the rest of the list.)
*
/*
* Fields valid for a join RTE (else NULL/zero):
*
- * joinaliasvars is a list of Vars or COALESCE expressions corresponding
- * to the columns of the join result. An alias Var referencing column K
- * of the join result can be replaced by the K'th element of joinaliasvars
- * --- but to simplify the task of reverse-listing aliases correctly, we
- * do not do that until planning time. In a Query loaded from a stored
- * rule, it is also possible for joinaliasvars items to be NULL Consts,
- * denoting columns dropped since the rule was made.
+ * joinaliasvars is a list of (usually) Vars corresponding to the columns
+ * of the join result. An alias Var referencing column K of the join
+ * result can be replaced by the K'th element of joinaliasvars --- but to
+ * simplify the task of reverse-listing aliases correctly, we do not do
+ * that until planning time. In detail: an element of joinaliasvars can
+ * be a Var of one of the join's input relations, or such a Var with an
+ * implicit coercion to the join's output column type, or a COALESCE
+ * expression containing the two input column Vars (possibly coerced).
+ * Within a Query loaded from a stored rule, it is also possible for
+ * joinaliasvars items to be null pointers, which are placeholders for
+ * (necessarily unreferenced) columns dropped since the rule was made.
+ * Also, once planning begins, joinaliasvars items can be almost anything,
+ * as a result of subquery-flattening substitutions.
*/
JoinType jointype; /* type of join */
List *joinaliasvars; /* list of alias-var expansions */