Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9ea14ef

Browse files
committed
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 FROMthe function, rather than the function name as previously. I still thinkthis is a bad idea, but I lost the argument. Force decompilation offunction RTEs to specify full aliases always, to reduce the odds of thisdecision breaking dumped views.
1 parentfa63749 commit9ea14ef

File tree

6 files changed

+215
-41
lines changed

6 files changed

+215
-41
lines changed

‎src/backend/parser/parse_relation.c

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.113 2005/08/01 20:31:10 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.114 2005/10/06 19:51:13 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -505,6 +505,59 @@ buildRelationAliases(TupleDesc tupdesc, Alias *alias, Alias *eref)
505505
eref->aliasname,maxattrs-numdropped,numaliases)));
506506
}
507507

508+
/*
509+
* buildScalarFunctionAlias
510+
*Construct the eref column name list for a function RTE,
511+
*when the function returns a scalar type (not composite or RECORD).
512+
*
513+
* funcexpr: transformed expression tree for the function call
514+
* funcname: function name (used only for error message)
515+
* alias: the user-supplied alias, or NULL if none
516+
* eref: the eref Alias to store column names in
517+
*
518+
* eref->colnames is filled in.
519+
*/
520+
staticvoid
521+
buildScalarFunctionAlias(Node*funcexpr,char*funcname,
522+
Alias*alias,Alias*eref)
523+
{
524+
char*pname;
525+
526+
Assert(eref->colnames==NIL);
527+
528+
/* Use user-specified column alias if there is one. */
529+
if (alias&&alias->colnames!=NIL)
530+
{
531+
if (list_length(alias->colnames)!=1)
532+
ereport(ERROR,
533+
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
534+
errmsg("too many column aliases specified for function %s",
535+
funcname)));
536+
eref->colnames=copyObject(alias->colnames);
537+
return;
538+
}
539+
540+
/*
541+
* If the expression is a simple function call, and the function has a
542+
* single OUT parameter that is named, use the parameter's name.
543+
*/
544+
if (funcexpr&&IsA(funcexpr,FuncExpr))
545+
{
546+
pname=get_func_result_name(((FuncExpr*)funcexpr)->funcid);
547+
if (pname)
548+
{
549+
eref->colnames=list_make1(makeString(pname));
550+
return;
551+
}
552+
}
553+
554+
/*
555+
* Otherwise use the previously-determined alias (not necessarily the
556+
* function name!)
557+
*/
558+
eref->colnames=list_make1(makeString(eref->aliasname));
559+
}
560+
508561
/*
509562
* Add an entry for a relation to the pstate's range table (p_rtable).
510563
*
@@ -776,18 +829,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
776829
elseif (functypclass==TYPEFUNC_SCALAR)
777830
{
778831
/* Base data type, i.e. scalar */
779-
/* Just add one alias column named for the function. */
780-
if (alias&&alias->colnames!=NIL)
781-
{
782-
if (list_length(alias->colnames)!=1)
783-
ereport(ERROR,
784-
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
785-
errmsg("too many column aliases specified for function %s",
786-
funcname)));
787-
eref->colnames=copyObject(alias->colnames);
788-
}
789-
else
790-
eref->colnames=list_make1(makeString(eref->aliasname));
832+
buildScalarFunctionAlias(funcexpr,funcname,alias,eref);
791833
}
792834
elseif (functypclass==TYPEFUNC_RECORD)
793835
{

‎src/backend/utils/adt/ruleutils.c

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*back to source text
44
*
55
* IDENTIFICATION
6-
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.205 2005/08/01 20:31:12 tgl Exp $
6+
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.206 2005/10/06 19:51:14 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -204,8 +204,8 @@ static void get_from_clause(Query *query, const char *prefix,
204204
deparse_context*context);
205205
staticvoidget_from_clause_item(Node*jtnode,Query*query,
206206
deparse_context*context);
207-
staticvoidget_from_clause_alias(Alias*alias,intvarno,
208-
Query*query,deparse_context*context);
207+
staticvoidget_from_clause_alias(Alias*alias,RangeTblEntry*rte,
208+
deparse_context*context);
209209
staticvoidget_from_clause_coldeflist(List*coldeflist,
210210
deparse_context*context);
211211
staticvoidget_opclass_name(Oidopclass,Oidactual_datatype,
@@ -4113,16 +4113,15 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
41134113
elog(ERROR,"unrecognized RTE kind: %d", (int)rte->rtekind);
41144114
break;
41154115
}
4116+
41164117
if (rte->alias!=NULL)
41174118
{
41184119
appendStringInfo(buf," %s",
41194120
quote_identifier(rte->alias->aliasname));
41204121
gavealias= true;
4121-
if (coldeflist==NIL)
4122-
get_from_clause_alias(rte->alias,varno,query,context);
41234122
}
41244123
elseif (rte->rtekind==RTE_RELATION&&
4125-
strcmp(rte->eref->aliasname,get_rel_name(rte->relid))!=0)
4124+
strcmp(rte->eref->aliasname,get_rel_name(rte->relid))!=0)
41264125
{
41274126
/*
41284127
* 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)
41344133
quote_identifier(rte->eref->aliasname));
41354134
gavealias= true;
41364135
}
4136+
elseif (rte->rtekind==RTE_FUNCTION)
4137+
{
4138+
/*
4139+
* For a function RTE, always give an alias.
4140+
* This covers possible renaming of the function and/or
4141+
* instability of the FigureColname rules for things that
4142+
* aren't simple functions.
4143+
*/
4144+
appendStringInfo(buf," %s",
4145+
quote_identifier(rte->eref->aliasname));
4146+
gavealias= true;
4147+
}
4148+
41374149
if (coldeflist!=NIL)
41384150
{
41394151
if (!gavealias)
41404152
appendStringInfo(buf," AS ");
41414153
get_from_clause_coldeflist(coldeflist,context);
41424154
}
4155+
else
4156+
{
4157+
/*
4158+
* For a function RTE, always emit a complete column alias list;
4159+
* this is to protect against possible instability of the default
4160+
* column names (eg, from altering parameter names). Otherwise
4161+
* just report whatever the user originally gave as column
4162+
* aliases.
4163+
*/
4164+
if (rte->rtekind==RTE_FUNCTION)
4165+
get_from_clause_alias(rte->eref,rte,context);
4166+
else
4167+
get_from_clause_alias(rte->alias,rte,context);
4168+
}
4169+
41434170
}
41444171
elseif (IsA(jtnode,JoinExpr))
41454172
{
@@ -4273,7 +4300,9 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
42734300
{
42744301
appendStringInfo(buf," %s",
42754302
quote_identifier(j->alias->aliasname));
4276-
get_from_clause_alias(j->alias,j->rtindex,query,context);
4303+
get_from_clause_alias(j->alias,
4304+
rt_fetch(j->rtindex,query->rtable),
4305+
context);
42774306
}
42784307
}
42794308
else
@@ -4287,11 +4316,10 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
42874316
* This is tricky because we must ignore dropped columns.
42884317
*/
42894318
staticvoid
4290-
get_from_clause_alias(Alias*alias,intvarno,
4291-
Query*query,deparse_context*context)
4319+
get_from_clause_alias(Alias*alias,RangeTblEntry*rte,
4320+
deparse_context*context)
42924321
{
42934322
StringInfobuf=context->buf;
4294-
RangeTblEntry*rte=rt_fetch(varno,query->rtable);
42954323
ListCell*col;
42964324
AttrNumberattnum;
42974325
boolfirst= true;

‎src/backend/utils/fmgr/funcapi.c

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.24 2005/07/03 21:14:18 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.25 2005/10/06 19:51:15 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -627,6 +627,108 @@ get_type_func_class(Oid typid)
627627
}
628628

629629

630+
/*
631+
* get_func_result_name
632+
*
633+
* If the function has exactly one output parameter, and that parameter
634+
* is named, return the name (as a palloc'd string). Else return NULL.
635+
*
636+
* This is used to determine the default output column name for functions
637+
* returning scalar types.
638+
*/
639+
char*
640+
get_func_result_name(OidfunctionId)
641+
{
642+
char*result;
643+
HeapTupleprocTuple;
644+
Datumproargmodes;
645+
Datumproargnames;
646+
boolisnull;
647+
ArrayType*arr;
648+
intnumargs;
649+
char*argmodes;
650+
Datum*argnames;
651+
intnumoutargs;
652+
intnargnames;
653+
inti;
654+
655+
/* First fetch the function's pg_proc row */
656+
procTuple=SearchSysCache(PROCOID,
657+
ObjectIdGetDatum(functionId),
658+
0,0,0);
659+
if (!HeapTupleIsValid(procTuple))
660+
elog(ERROR,"cache lookup failed for function %u",functionId);
661+
662+
/* If there are no named OUT parameters, return NULL */
663+
if (heap_attisnull(procTuple,Anum_pg_proc_proargmodes)||
664+
heap_attisnull(procTuple,Anum_pg_proc_proargnames))
665+
result=NULL;
666+
else
667+
{
668+
/* Get the data out of the tuple */
669+
proargmodes=SysCacheGetAttr(PROCOID,procTuple,
670+
Anum_pg_proc_proargmodes,
671+
&isnull);
672+
Assert(!isnull);
673+
proargnames=SysCacheGetAttr(PROCOID,procTuple,
674+
Anum_pg_proc_proargnames,
675+
&isnull);
676+
Assert(!isnull);
677+
678+
/*
679+
* We expect the arrays to be 1-D arrays of the right types; verify
680+
* that. For the char array, we don't need to use deconstruct_array()
681+
* since the array data is just going to look like a C array of
682+
* values.
683+
*/
684+
arr=DatumGetArrayTypeP(proargmodes);/* ensure not toasted */
685+
numargs=ARR_DIMS(arr)[0];
686+
if (ARR_NDIM(arr)!=1||
687+
numargs<0||
688+
ARR_ELEMTYPE(arr)!=CHAROID)
689+
elog(ERROR,"proargmodes is not a 1-D char array");
690+
argmodes= (char*)ARR_DATA_PTR(arr);
691+
arr=DatumGetArrayTypeP(proargnames);/* ensure not toasted */
692+
if (ARR_NDIM(arr)!=1||
693+
ARR_DIMS(arr)[0]!=numargs||
694+
ARR_ELEMTYPE(arr)!=TEXTOID)
695+
elog(ERROR,"proargnames is not a 1-D text array");
696+
deconstruct_array(arr,TEXTOID,-1, false,'i',
697+
&argnames,&nargnames);
698+
Assert(nargnames==numargs);
699+
700+
/* scan for output argument(s) */
701+
result=NULL;
702+
numoutargs=0;
703+
for (i=0;i<numargs;i++)
704+
{
705+
if (argmodes[i]==PROARGMODE_IN)
706+
continue;
707+
Assert(argmodes[i]==PROARGMODE_OUT||
708+
argmodes[i]==PROARGMODE_INOUT);
709+
if (++numoutargs>1)
710+
{
711+
/* multiple out args, so forget it */
712+
result=NULL;
713+
break;
714+
}
715+
result=DatumGetCString(DirectFunctionCall1(textout,
716+
argnames[i]));
717+
if (result==NULL||result[0]=='\0')
718+
{
719+
/* Parameter is not named, so forget it */
720+
result=NULL;
721+
break;
722+
}
723+
}
724+
}
725+
726+
ReleaseSysCache(procTuple);
727+
728+
returnresult;
729+
}
730+
731+
630732
/*
631733
* build_function_result_tupdesc_t
632734
*

‎src/include/funcapi.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
1111
*
12-
* $PostgreSQL: pgsql/src/include/funcapi.h,v 1.18 2005/05/30 23:09:07 tgl Exp $
12+
* $PostgreSQL: pgsql/src/include/funcapi.h,v 1.19 2005/10/06 19:51:15 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -167,6 +167,8 @@ extern TypeFuncClass get_func_result_type(Oid functionId,
167167
Oid*resultTypeId,
168168
TupleDesc*resultTupleDesc);
169169

170+
externchar*get_func_result_name(OidfunctionId);
171+
170172
externboolresolve_polymorphic_argtypes(intnumargs,Oid*argtypes,
171173
char*argmodes,
172174
Node*call_expr);

‎src/test/regress/expected/plpgsql.out

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,7 +1762,7 @@ select f1(42);
17621762
(1 row)
17631763

17641764
select * from f1(42);
1765-
f1
1765+
j
17661766
----
17671767
43
17681768
(1 row)
@@ -1778,7 +1778,7 @@ select f1(42);
17781778
(1 row)
17791779

17801780
select * from f1(42);
1781-
f1
1781+
i
17821782
----
17831783
43
17841784
(1 row)
@@ -1793,7 +1793,7 @@ begin
17931793
return;
17941794
end$$ language plpgsql;
17951795
select * from f1(42);
1796-
f1
1796+
j
17971797
----
17981798
43
17991799
44

‎src/test/regress/expected/rangefuncs.out

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
SELECT name, setting FROM pg_settings WHERE name LIKE 'enable%';
2-
name | setting
2+
name | setting
33
-------------------+---------
4-
enable_bitmapscan| on
5-
enable_hashagg| on
6-
enable_hashjoin| on
7-
enable_indexscan| on
8-
enable_mergejoin| on
9-
enable_nestloop| on
10-
enable_seqscan| on
11-
enable_sort| on
12-
enable_tidscan| on
4+
enable_bitmapscan | on
5+
enable_hashagg | on
6+
enable_hashjoin | on
7+
enable_indexscan | on
8+
enable_mergejoin | on
9+
enable_nestloop | on
10+
enable_seqscan | on
11+
enable_sort | on
12+
enable_tidscan | on
1313
(9 rows)
1414

1515
CREATE TABLE foo2(fooid int, f2 int);
@@ -409,9 +409,9 @@ SELECT foo(42);
409409
(1 row)
410410

411411
SELECT * FROM foo(42);
412-
foo
413-
-----
414-
43
412+
f2
413+
----
414+
43
415415
(1 row)
416416

417417
SELECT * FROM foo(42) AS p(x);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp