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

Commite6c178b

Browse files
committed
Refactor our checks for valid function and aggregate signatures.
pg_proc.c and pg_aggregate.c had near-duplicate copies of the logicto decide whether a function or aggregate's signature is legal.This seems like a bad thing even without the problem that theupcoming "anycompatible" patch would roughly double the complexityof that logic. Hence, refactor so that the rules are localizedin new subroutines supplied by parse_coerce.c. (One could quibbleabout just where to add that code, but putting it besideenforce_generic_type_consistency seems not totally unreasonable.)The fact that the rules are about to change would mandate somechanges in the wording of the associated error messages in any case.I ended up spelling things out in a fairly literal fashion in theerrdetail messages, eg "A result of type anyelement requires atleast one input of type anyelement, anyarray, anynonarray, anyenum,or anyrange." Perhaps this is overkill, but once there's more thanone subgroup of polymorphic types, people might get confused bymore-abstract messages.Discussion:https://postgr.es/m/24137.1584139352@sss.pgh.pa.us
1 parentdbbb553 commite6c178b

File tree

8 files changed

+176
-122
lines changed

8 files changed

+176
-122
lines changed

‎src/backend/catalog/pg_aggregate.c

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,6 @@ AggregateCreate(const char *aggName,
9393
Oidmfinalfn=InvalidOid;/* can be omitted */
9494
Oidsortop=InvalidOid;/* can be omitted */
9595
Oid*aggArgTypes=parameterTypes->values;
96-
boolhasPolyArg;
97-
boolhasInternalArg;
9896
boolmtransIsStrict= false;
9997
Oidrettype;
10098
Oidfinaltype;
@@ -103,6 +101,7 @@ AggregateCreate(const char *aggName,
103101
intnargs_finalfn;
104102
OidprocOid;
105103
TupleDesctupDesc;
104+
char*detailmsg;
106105
inti;
107106
ObjectAddressmyself,
108107
referenced;
@@ -131,36 +130,33 @@ AggregateCreate(const char *aggName,
131130
FUNC_MAX_ARGS-1,
132131
FUNC_MAX_ARGS-1)));
133132

134-
/* check for polymorphic and INTERNAL arguments */
135-
hasPolyArg= false;
136-
hasInternalArg= false;
137-
for (i=0;i<numArgs;i++)
138-
{
139-
if (IsPolymorphicType(aggArgTypes[i]))
140-
hasPolyArg= true;
141-
elseif (aggArgTypes[i]==INTERNALOID)
142-
hasInternalArg= true;
143-
}
144-
145133
/*
146134
* If transtype is polymorphic, must have polymorphic argument also; else
147135
* we will have no way to deduce the actual transtype.
148136
*/
149-
if (IsPolymorphicType(aggTransType)&& !hasPolyArg)
137+
detailmsg=check_valid_polymorphic_signature(aggTransType,
138+
aggArgTypes,
139+
numArgs);
140+
if (detailmsg)
150141
ereport(ERROR,
151142
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
152143
errmsg("cannot determine transition data type"),
153-
errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
144+
errdetail_internal("%s",detailmsg)));
154145

155146
/*
156147
* Likewise for moving-aggregate transtype, if any
157148
*/
158-
if (OidIsValid(aggmTransType)&&
159-
IsPolymorphicType(aggmTransType)&& !hasPolyArg)
160-
ereport(ERROR,
161-
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
162-
errmsg("cannot determine transition data type"),
163-
errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
149+
if (OidIsValid(aggmTransType))
150+
{
151+
detailmsg=check_valid_polymorphic_signature(aggmTransType,
152+
aggArgTypes,
153+
numArgs);
154+
if (detailmsg)
155+
ereport(ERROR,
156+
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
157+
errmsg("cannot determine transition data type"),
158+
errdetail_internal("%s",detailmsg)));
159+
}
164160

165161
/*
166162
* An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In
@@ -492,24 +488,29 @@ AggregateCreate(const char *aggName,
492488
* that itself violates the rule against polymorphic result with no
493489
* polymorphic input.)
494490
*/
495-
if (IsPolymorphicType(finaltype)&& !hasPolyArg)
491+
detailmsg=check_valid_polymorphic_signature(finaltype,
492+
aggArgTypes,
493+
numArgs);
494+
if (detailmsg)
496495
ereport(ERROR,
497496
(errcode(ERRCODE_DATATYPE_MISMATCH),
498497
errmsg("cannot determine result data type"),
499-
errdetail("An aggregate returning a polymorphic type "
500-
"must have at least one polymorphic argument.")));
498+
errdetail_internal("%s",detailmsg)));
501499

502500
/*
503501
* Also, the return type can't be INTERNAL unless there's at least one
504502
* INTERNAL argument. This is the same type-safety restriction we enforce
505503
* for regular functions, but at the level of aggregates. We must test
506504
* this explicitly because we allow INTERNAL as the transtype.
507505
*/
508-
if (finaltype==INTERNALOID&& !hasInternalArg)
506+
detailmsg=check_valid_internal_signature(finaltype,
507+
aggArgTypes,
508+
numArgs);
509+
if (detailmsg)
509510
ereport(ERROR,
510511
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
511512
errmsg("unsafe use of pseudo-type \"internal\""),
512-
errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
513+
errdetail_internal("%s",detailmsg)));
513514

514515
/*
515516
* If a moving-aggregate implementation is supplied, look up its finalfn

‎src/backend/catalog/pg_proc.c

Lines changed: 45 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include"mb/pg_wchar.h"
3333
#include"miscadmin.h"
3434
#include"nodes/nodeFuncs.h"
35+
#include"parser/parse_coerce.h"
3536
#include"parser/parse_type.h"
3637
#include"tcop/pquery.h"
3738
#include"tcop/tcopprot.h"
@@ -97,12 +98,6 @@ ProcedureCreate(const char *procedureName,
9798
intallParamCount;
9899
Oid*allParams;
99100
char*paramModes=NULL;
100-
boolgenericInParam= false;
101-
boolgenericOutParam= false;
102-
boolanyrangeInParam= false;
103-
boolanyrangeOutParam= false;
104-
boolinternalInParam= false;
105-
boolinternalOutParam= false;
106101
OidvariadicType=InvalidOid;
107102
Acl*proacl=NULL;
108103
Relationrel;
@@ -116,6 +111,7 @@ ProcedureCreate(const char *procedureName,
116111
boolis_update;
117112
ObjectAddressmyself,
118113
referenced;
114+
char*detailmsg;
119115
inti;
120116
Oidtrfid;
121117

@@ -178,29 +174,34 @@ ProcedureCreate(const char *procedureName,
178174
}
179175

180176
/*
181-
*Detect whether we havepolymorphicor INTERNAL arguments. The first
182-
*loop checks input arguments,thesecond output arguments.
177+
*Do not allowpolymorphicreturn type unless there is a polymorphic
178+
*input argument that we can use to deducetheactual return type.
183179
*/
184-
for (i=0;i<parameterCount;i++)
185-
{
186-
switch (parameterTypes->values[i])
187-
{
188-
caseANYARRAYOID:
189-
caseANYELEMENTOID:
190-
caseANYNONARRAYOID:
191-
caseANYENUMOID:
192-
genericInParam= true;
193-
break;
194-
caseANYRANGEOID:
195-
genericInParam= true;
196-
anyrangeInParam= true;
197-
break;
198-
caseINTERNALOID:
199-
internalInParam= true;
200-
break;
201-
}
202-
}
180+
detailmsg=check_valid_polymorphic_signature(returnType,
181+
parameterTypes->values,
182+
parameterCount);
183+
if (detailmsg)
184+
ereport(ERROR,
185+
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
186+
errmsg("cannot determine result data type"),
187+
errdetail_internal("%s",detailmsg)));
203188

189+
/*
190+
* Also, do not allow return type INTERNAL unless at least one input
191+
* argument is INTERNAL.
192+
*/
193+
detailmsg=check_valid_internal_signature(returnType,
194+
parameterTypes->values,
195+
parameterCount);
196+
if (detailmsg)
197+
ereport(ERROR,
198+
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
199+
errmsg("unsafe use of pseudo-type \"internal\""),
200+
errdetail_internal("%s",detailmsg)));
201+
202+
/*
203+
* Apply the same tests to any OUT arguments.
204+
*/
204205
if (allParameterTypes!=PointerGetDatum(NULL))
205206
{
206207
for (i=0;i<allParamCount;i++)
@@ -210,52 +211,26 @@ ProcedureCreate(const char *procedureName,
210211
paramModes[i]==PROARGMODE_VARIADIC)
211212
continue;/* ignore input-only params */
212213

213-
switch(allParams[i])
214-
{
215-
caseANYARRAYOID:
216-
caseANYELEMENTOID:
217-
caseANYNONARRAYOID:
218-
caseANYENUMOID:
219-
genericOutParam= true;
220-
break;
221-
caseANYRANGEOID:
222-
genericOutParam= true;
223-
anyrangeOutParam= true;
224-
break;
225-
caseINTERNALOID:
226-
internalOutParam= true;
227-
break;
228-
}
214+
detailmsg=check_valid_polymorphic_signature(allParams[i],
215+
parameterTypes->values,
216+
parameterCount);
217+
if (detailmsg)
218+
ereport(ERROR,
219+
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
220+
errmsg("cannot determine result data type"),
221+
errdetail_internal("%s",detailmsg)));
222+
detailmsg=check_valid_internal_signature(allParams[i],
223+
parameterTypes->values,
224+
parameterCount);
225+
if (detailmsg)
226+
ereport(ERROR,
227+
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
228+
errmsg("unsafe use of pseudo-type \"internal\""),
229+
errdetail_internal("%s",detailmsg)));
229230
}
230231
}
231232

232-
/*
233-
* Do not allow polymorphic return type unless at least one input argument
234-
* is polymorphic. ANYRANGE return type is even stricter: must have an
235-
* ANYRANGE input (since we can't deduce the specific range type from
236-
* ANYELEMENT). Also, do not allow return type INTERNAL unless at least
237-
* one input argument is INTERNAL.
238-
*/
239-
if ((IsPolymorphicType(returnType)||genericOutParam)
240-
&& !genericInParam)
241-
ereport(ERROR,
242-
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
243-
errmsg("cannot determine result data type"),
244-
errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
245-
246-
if ((returnType==ANYRANGEOID||anyrangeOutParam)&&
247-
!anyrangeInParam)
248-
ereport(ERROR,
249-
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
250-
errmsg("cannot determine result data type"),
251-
errdetail("A function returning \"anyrange\" must have at least one \"anyrange\" argument.")));
252-
253-
if ((returnType==INTERNALOID||internalOutParam)&& !internalInParam)
254-
ereport(ERROR,
255-
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
256-
errmsg("unsafe use of pseudo-type \"internal\""),
257-
errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
258-
233+
/* Identify variadic argument type, if any */
259234
if (paramModes!=NULL)
260235
{
261236
/*

‎src/backend/parser/parse_coerce.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,77 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
19711971
returnrettype;
19721972
}
19731973

1974+
/*
1975+
* check_valid_polymorphic_signature()
1976+
*Is a proposed function signature valid per polymorphism rules?
1977+
*
1978+
* Returns NULL if the signature is valid (either ret_type is not polymorphic,
1979+
* or it can be deduced from the given declared argument types). Otherwise,
1980+
* returns a palloc'd, already translated errdetail string saying why not.
1981+
*/
1982+
char*
1983+
check_valid_polymorphic_signature(Oidret_type,
1984+
constOid*declared_arg_types,
1985+
intnargs)
1986+
{
1987+
if (ret_type==ANYRANGEOID)
1988+
{
1989+
/*
1990+
* ANYRANGE requires an ANYRANGE input, else we can't tell which of
1991+
* several range types with the same element type to use.
1992+
*/
1993+
for (inti=0;i<nargs;i++)
1994+
{
1995+
if (declared_arg_types[i]==ret_type)
1996+
returnNULL;/* OK */
1997+
}
1998+
returnpsprintf(_("A result of type %s requires at least one input of type %s."),
1999+
format_type_be(ret_type),format_type_be(ret_type));
2000+
}
2001+
elseif (IsPolymorphicType(ret_type))
2002+
{
2003+
/* Otherwise, any polymorphic type can be deduced from any other */
2004+
for (inti=0;i<nargs;i++)
2005+
{
2006+
if (IsPolymorphicType(declared_arg_types[i]))
2007+
returnNULL;/* OK */
2008+
}
2009+
returnpsprintf(_("A result of type %s requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange."),
2010+
format_type_be(ret_type));
2011+
}
2012+
else
2013+
returnNULL;/* OK, ret_type is not polymorphic */
2014+
}
2015+
2016+
/*
2017+
* check_valid_internal_signature()
2018+
*Is a proposed function signature valid per INTERNAL safety rules?
2019+
*
2020+
* Returns NULL if OK, or a suitable error message if ret_type is INTERNAL but
2021+
* none of the declared arg types are. (It's unsafe to create such a function
2022+
* since it would allow invocation of INTERNAL-consuming functions directly
2023+
* from SQL.) It's overkill to return the error detail message, since there
2024+
* is only one possibility, but we do it like this to keep the API similar to
2025+
* check_valid_polymorphic_signature().
2026+
*/
2027+
char*
2028+
check_valid_internal_signature(Oidret_type,
2029+
constOid*declared_arg_types,
2030+
intnargs)
2031+
{
2032+
if (ret_type==INTERNALOID)
2033+
{
2034+
for (inti=0;i<nargs;i++)
2035+
{
2036+
if (declared_arg_types[i]==ret_type)
2037+
returnNULL;/* OK */
2038+
}
2039+
returnpstrdup(_("A result of type internal requires at least one input of type internal."));
2040+
}
2041+
else
2042+
returnNULL;/* OK, ret_type is not INTERNAL */
2043+
}
2044+
19742045

19752046
/* TypeCategory()
19762047
*Assign a category to the specified type OID.

‎src/include/parser/parse_coerce.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ extern Oidenforce_generic_type_consistency(const Oid *actual_arg_types,
8080
Oidrettype,
8181
boolallow_poly);
8282

83+
externchar*check_valid_polymorphic_signature(Oidret_type,
84+
constOid*declared_arg_types,
85+
intnargs);
86+
externchar*check_valid_internal_signature(Oidret_type,
87+
constOid*declared_arg_types,
88+
intnargs);
89+
8390
externCoercionPathTypefind_coercion_pathway(OidtargetTypeId,
8491
OidsourceTypeId,
8592
CoercionContextccontext,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1811,7 +1811,7 @@ begin
18111811
return array[x + 1, x + 2];
18121812
end$$ language plpgsql;
18131813
ERROR: cannot determine result data type
1814-
DETAIL: Afunction returning "anyrange" must haveat least one"anyrange" argument.
1814+
DETAIL: Aresult of typeanyrange requiresat least oneinput of type anyrange.
18151815
create function f1(x anyrange) returns anyarray as $$
18161816
begin
18171817
return array[lower(x), upper(x)];

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp