diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 48 | ||||
-rw-r--r-- | src/backend/utils/fmgr/funcapi.c | 104 |
2 files changed, 141 insertions, 11 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index bf9ebfefaa3..1a226bd49c3 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -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; diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index b6ccd63d4dd..598168a70a0 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -628,6 +628,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 * * Given a pg_proc row for a function, return a tuple descriptor for the |