1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00

When a function not returning RECORD has a single OUT parameter, use

the parameter's name (if any) as the default column name for SELECT FROM
the function, rather than the function name as previously.  I still think
this is a bad idea, but I lost the argument.  Force decompilation of
function RTEs to specify full aliases always, to reduce the odds of this
decision breaking dumped views.
This commit is contained in:
Tom Lane
2005-10-06 19:51:16 +00:00
parent fa63749d21
commit 9ea14ef56a
6 changed files with 215 additions and 41 deletions

View File

@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.205 2005/08/01 20:31:12 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.206 2005/10/06 19:51:14 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -204,8 +204,8 @@ static void get_from_clause(Query *query, const char *prefix,
deparse_context *context);
static void get_from_clause_item(Node *jtnode, Query *query,
deparse_context *context);
static void get_from_clause_alias(Alias *alias, int varno,
Query *query, deparse_context *context);
static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
deparse_context *context);
static void get_from_clause_coldeflist(List *coldeflist,
deparse_context *context);
static void get_opclass_name(Oid opclass, Oid actual_datatype,
@@ -4113,16 +4113,15 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
break;
}
if (rte->alias != NULL)
{
appendStringInfo(buf, " %s",
quote_identifier(rte->alias->aliasname));
gavealias = true;
if (coldeflist == NIL)
get_from_clause_alias(rte->alias, varno, query, context);
}
else if (rte->rtekind == RTE_RELATION &&
strcmp(rte->eref->aliasname, get_rel_name(rte->relid)) != 0)
strcmp(rte->eref->aliasname, get_rel_name(rte->relid)) != 0)
{
/*
* Apparently the rel has been renamed since the rule was
@@ -4134,12 +4133,40 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
quote_identifier(rte->eref->aliasname));
gavealias = true;
}
else if (rte->rtekind == RTE_FUNCTION)
{
/*
* For a function RTE, always give an alias.
* This covers possible renaming of the function and/or
* instability of the FigureColname rules for things that
* aren't simple functions.
*/
appendStringInfo(buf, " %s",
quote_identifier(rte->eref->aliasname));
gavealias = true;
}
if (coldeflist != NIL)
{
if (!gavealias)
appendStringInfo(buf, " AS ");
get_from_clause_coldeflist(coldeflist, context);
}
else
{
/*
* For a function RTE, always emit a complete column alias list;
* this is to protect against possible instability of the default
* column names (eg, from altering parameter names). Otherwise
* just report whatever the user originally gave as column
* aliases.
*/
if (rte->rtekind == RTE_FUNCTION)
get_from_clause_alias(rte->eref, rte, context);
else
get_from_clause_alias(rte->alias, rte, context);
}
}
else if (IsA(jtnode, JoinExpr))
{
@@ -4273,7 +4300,9 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
{
appendStringInfo(buf, " %s",
quote_identifier(j->alias->aliasname));
get_from_clause_alias(j->alias, j->rtindex, query, context);
get_from_clause_alias(j->alias,
rt_fetch(j->rtindex, query->rtable),
context);
}
}
else
@@ -4287,11 +4316,10 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
* This is tricky because we must ignore dropped columns.
*/
static void
get_from_clause_alias(Alias *alias, int varno,
Query *query, deparse_context *context)
get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
deparse_context *context)
{
StringInfo buf = context->buf;
RangeTblEntry *rte = rt_fetch(varno, query->rtable);
ListCell *col;
AttrNumber attnum;
bool first = true;

View File

@@ -7,7 +7,7 @@
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.24 2005/07/03 21:14:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.25 2005/10/06 19:51:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -627,6 +627,108 @@ get_type_func_class(Oid typid)
}
/*
* get_func_result_name
*
* If the function has exactly one output parameter, and that parameter
* is named, return the name (as a palloc'd string). Else return NULL.
*
* This is used to determine the default output column name for functions
* returning scalar types.
*/
char *
get_func_result_name(Oid functionId)
{
char *result;
HeapTuple procTuple;
Datum proargmodes;
Datum proargnames;
bool isnull;
ArrayType *arr;
int numargs;
char *argmodes;
Datum *argnames;
int numoutargs;
int nargnames;
int i;
/* First fetch the function's pg_proc row */
procTuple = SearchSysCache(PROCOID,
ObjectIdGetDatum(functionId),
0, 0, 0);
if (!HeapTupleIsValid(procTuple))
elog(ERROR, "cache lookup failed for function %u", functionId);
/* If there are no named OUT parameters, return NULL */
if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes) ||
heap_attisnull(procTuple, Anum_pg_proc_proargnames))
result = NULL;
else
{
/* Get the data out of the tuple */
proargmodes = SysCacheGetAttr(PROCOID, procTuple,
Anum_pg_proc_proargmodes,
&isnull);
Assert(!isnull);
proargnames = SysCacheGetAttr(PROCOID, procTuple,
Anum_pg_proc_proargnames,
&isnull);
Assert(!isnull);
/*
* We expect the arrays to be 1-D arrays of the right types; verify
* that. For the char array, we don't need to use deconstruct_array()
* since the array data is just going to look like a C array of
* values.
*/
arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */
numargs = ARR_DIMS(arr)[0];
if (ARR_NDIM(arr) != 1 ||
numargs < 0 ||
ARR_ELEMTYPE(arr) != CHAROID)
elog(ERROR, "proargmodes is not a 1-D char array");
argmodes = (char *) ARR_DATA_PTR(arr);
arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */
if (ARR_NDIM(arr) != 1 ||
ARR_DIMS(arr)[0] != numargs ||
ARR_ELEMTYPE(arr) != TEXTOID)
elog(ERROR, "proargnames is not a 1-D text array");
deconstruct_array(arr, TEXTOID, -1, false, 'i',
&argnames, &nargnames);
Assert(nargnames == numargs);
/* scan for output argument(s) */
result = NULL;
numoutargs = 0;
for (i = 0; i < numargs; i++)
{
if (argmodes[i] == PROARGMODE_IN)
continue;
Assert(argmodes[i] == PROARGMODE_OUT ||
argmodes[i] == PROARGMODE_INOUT);
if (++numoutargs > 1)
{
/* multiple out args, so forget it */
result = NULL;
break;
}
result = DatumGetCString(DirectFunctionCall1(textout,
argnames[i]));
if (result == NULL || result[0] == '\0')
{
/* Parameter is not named, so forget it */
result = NULL;
break;
}
}
}
ReleaseSysCache(procTuple);
return result;
}
/*
* build_function_result_tupdesc_t
*