static void get_rule_windowclause(Query *query, deparse_context *context);
static void get_rule_windowspec(WindowClause *wc, List *targetList,
deparse_context *context);
-static char *get_variable(Var *var, int levelsup, bool showstar,
+static char *get_variable(Var *var, int levelsup, bool istoplevel,
deparse_context *context);
static RangeTblEntry *find_rte_by_refname(const char *refname,
deparse_context *context);
* "foo.*", which is the preferred notation in most contexts, but at
* the top level of a SELECT list it's not right (the parser will
* expand that notation into multiple columns, yielding behavior
- * different from a whole-row Var). We want just "foo", instead.
+ * different from a whole-row Var). We need to call get_variable
+ * directly so that we can tell it to do the right thing.
*/
if (tle->expr && IsA(tle->expr, Var))
{
- attname = get_variable((Var *) tle->expr, 0, false, context);
+ attname = get_variable((Var *) tle->expr, 0, true, context);
}
else
{
* the Var's varlevelsup has to be interpreted with respect to a context
* above the current one; levelsup indicates the offset.
*
- * If showstar is TRUE, whole-row Vars are displayed as "foo.*";
- * if FALSE, merely as "foo".
+ * If istoplevel is TRUE, the Var is at the top level of a SELECT's
+ * targetlist, which means we need special treatment of whole-row Vars.
+ * Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
+ * dirty hack to prevent "tab.*" from being expanded into multiple columns.
+ * (The parser will strip the useless coercion, so no inefficiency is added in
+ * dump and reload.) We used to print just "tab" in such cases, but that is
+ * ambiguous and will yield the wrong result if "tab" is also a plain column
+ * name in the query.
*
- * Returns the attname of the Var, or NULL if not determinable.
+ * Returns the attname of the Var, or NULL if the Var has no attname (because
+ * it is a whole-row Var).
*/
static char *
-get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
+get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
{
StringInfo buf = context->buf;
RangeTblEntry *rte;
if (IsA(aliasvar, Var))
{
return get_variable(aliasvar, var->varlevelsup + levelsup,
- showstar, context);
+ istoplevel, context);
}
}
- /* Unnamed join has neither schemaname nor refname */
+
+ /*
+ * Unnamed join has neither schemaname nor refname. (Note: since
+ * it's unnamed, there is no way the user could have referenced it
+ * to create a whole-row Var for it. So we don't have to cover
+ * that case below.)
+ */
refname = NULL;
}
}
appendStringInfo(buf, "%s.",
quote_identifier(schemaname));
appendStringInfoString(buf, quote_identifier(refname));
- if (attname || showstar)
- appendStringInfoChar(buf, '.');
+ appendStringInfoChar(buf, '.');
}
if (attname)
appendStringInfoString(buf, quote_identifier(attname));
- else if (showstar)
+ else
+ {
appendStringInfoChar(buf, '*');
+ if (istoplevel)
+ appendStringInfo(buf, "::%s",
+ format_type_with_typemod(var->vartype,
+ var->vartypmod));
+ }
return attname;
}
switch (nodeTag(node))
{
case T_Var:
- (void) get_variable((Var *) node, 0, true, context);
+ (void) get_variable((Var *) node, 0, false, context);
break;
case T_Const: