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

Commitd6d07a0

Browse files
committed
SQL functions can have arguments and results declared ANYARRAY or
ANYELEMENT. The effect is to postpone typechecking of the functionbody until runtime. Documentation is still lacking.Original patch by Joe Conway, modified to postpone type checkingby Tom Lane.
1 parent71e9f3b commitd6d07a0

File tree

8 files changed

+152
-57
lines changed

8 files changed

+152
-57
lines changed

‎src/backend/catalog/pg_proc.c

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.97 2003/06/15 17:59:10 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.98 2003/07/01 00:04:37 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -33,7 +33,6 @@
3333
#include"utils/syscache.h"
3434

3535

36-
staticvoidcheckretval(Oidrettype,charfn_typtype,List*queryTreeList);
3736
Datumfmgr_internal_validator(PG_FUNCTION_ARGS);
3837
Datumfmgr_c_validator(PG_FUNCTION_ARGS);
3938
Datumfmgr_sql_validator(PG_FUNCTION_ARGS);
@@ -317,15 +316,20 @@ ProcedureCreate(const char *procedureName,
317316
}
318317

319318
/*
320-
*checkretval() -- check return value of a list of sql parse trees.
319+
*check_sql_fn_retval() -- check return value of a list of sql parse trees.
321320
*
322321
* The return value of a sql function is the value returned by
323-
* the final query in the function. We do some ad-hoc define-time
324-
* type checking here to be sure that the user is returning the
325-
* type he claims.
322+
* the final query in the function. We do some ad-hoc type checking here
323+
* to be sure that the user is returning the type he claims.
324+
*
325+
* This is normally applied during function definition, but in the case
326+
* of a function with polymorphic arguments, we instead apply it during
327+
* function execution startup. The rettype is then the actual resolved
328+
* output type of the function, rather than the declared type. (Therefore,
329+
* we should never see ANYARRAY or ANYELEMENT as rettype.)
326330
*/
327-
staticvoid
328-
checkretval(Oidrettype,charfn_typtype,List*queryTreeList)
331+
void
332+
check_sql_fn_retval(Oidrettype,charfn_typtype,List*queryTreeList)
329333
{
330334
Query*parse;
331335
intcmd;
@@ -472,7 +476,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
472476

473477
relation_close(reln,AccessShareLock);
474478
}
475-
elseif (fn_typtype=='p'&&rettype==RECORDOID)
479+
elseif (rettype==RECORDOID)
476480
{
477481
/* Shouldn't have a typerelid */
478482
Assert(typerelid==InvalidOid);
@@ -482,6 +486,14 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
482486
* tuple.
483487
*/
484488
}
489+
elseif (rettype==ANYARRAYOID||rettype==ANYELEMENTOID)
490+
{
491+
/*
492+
* This should already have been caught ...
493+
*/
494+
elog(ERROR,"functions returning ANYARRAY or ANYELEMENT must " \
495+
"have at least one argument of either type");
496+
}
485497
else
486498
elog(ERROR,"return type %s is not supported for SQL functions",
487499
format_type_be(rettype));
@@ -505,7 +517,9 @@ fmgr_internal_validator(PG_FUNCTION_ARGS)
505517
Datumtmp;
506518
char*prosrc;
507519

508-
tuple=SearchSysCache(PROCOID,funcoid,0,0,0);
520+
tuple=SearchSysCache(PROCOID,
521+
ObjectIdGetDatum(funcoid),
522+
0,0,0);
509523
if (!HeapTupleIsValid(tuple))
510524
elog(ERROR,"cache lookup of function %u failed",funcoid);
511525
proc= (Form_pg_proc)GETSTRUCT(tuple);
@@ -544,7 +558,9 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
544558
char*prosrc;
545559
char*probin;
546560

547-
tuple=SearchSysCache(PROCOID,funcoid,0,0,0);
561+
tuple=SearchSysCache(PROCOID,
562+
ObjectIdGetDatum(funcoid),
563+
0,0,0);
548564
if (!HeapTupleIsValid(tuple))
549565
elog(ERROR,"cache lookup of function %u failed",funcoid);
550566
proc= (Form_pg_proc)GETSTRUCT(tuple);
@@ -585,38 +601,62 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
585601
Datumtmp;
586602
char*prosrc;
587603
charfunctyptype;
604+
boolhaspolyarg;
588605
inti;
589606

590-
tuple=SearchSysCache(PROCOID,funcoid,0,0,0);
607+
tuple=SearchSysCache(PROCOID,
608+
ObjectIdGetDatum(funcoid),
609+
0,0,0);
591610
if (!HeapTupleIsValid(tuple))
592611
elog(ERROR,"cache lookup of function %u failed",funcoid);
593612
proc= (Form_pg_proc)GETSTRUCT(tuple);
594613

595614
functyptype=get_typtype(proc->prorettype);
596615

597-
/* Disallowpseudotypes in arguments and result */
598-
/* exceptthat return type can be RECORDorVOID */
616+
/* Disallowpseudotype result */
617+
/* exceptfor RECORD, VOID, ANYARRAY,orANYELEMENT */
599618
if (functyptype=='p'&&
600619
proc->prorettype!=RECORDOID&&
601-
proc->prorettype!=VOIDOID)
620+
proc->prorettype!=VOIDOID&&
621+
proc->prorettype!=ANYARRAYOID&&
622+
proc->prorettype!=ANYELEMENTOID)
602623
elog(ERROR,"SQL functions cannot return type %s",
603624
format_type_be(proc->prorettype));
604625

626+
/* Disallow pseudotypes in arguments */
627+
/* except for ANYARRAY or ANYELEMENT */
628+
haspolyarg= false;
605629
for (i=0;i<proc->pronargs;i++)
606630
{
607631
if (get_typtype(proc->proargtypes[i])=='p')
608-
elog(ERROR,"SQL functions cannot have arguments of type %s",
609-
format_type_be(proc->proargtypes[i]));
632+
{
633+
if (proc->proargtypes[i]==ANYARRAYOID||
634+
proc->proargtypes[i]==ANYELEMENTOID)
635+
haspolyarg= true;
636+
else
637+
elog(ERROR,"SQL functions cannot have arguments of type %s",
638+
format_type_be(proc->proargtypes[i]));
639+
}
610640
}
611641

612-
tmp=SysCacheGetAttr(PROCOID,tuple,Anum_pg_proc_prosrc,&isnull);
613-
if (isnull)
614-
elog(ERROR,"null prosrc");
642+
/*
643+
* We can't precheck the function definition if there are any polymorphic
644+
* input types, because actual datatypes of expression results will be
645+
* unresolvable. The check will be done at runtime instead.
646+
*/
647+
if (!haspolyarg)
648+
{
649+
tmp=SysCacheGetAttr(PROCOID,tuple,Anum_pg_proc_prosrc,&isnull);
650+
if (isnull)
651+
elog(ERROR,"null prosrc");
615652

616-
prosrc=DatumGetCString(DirectFunctionCall1(textout,tmp));
653+
prosrc=DatumGetCString(DirectFunctionCall1(textout,tmp));
617654

618-
querytree_list=pg_parse_and_rewrite(prosrc,proc->proargtypes,proc->pronargs);
619-
checkretval(proc->prorettype,functyptype,querytree_list);
655+
querytree_list=pg_parse_and_rewrite(prosrc,
656+
proc->proargtypes,
657+
proc->pronargs);
658+
check_sql_fn_retval(proc->prorettype,functyptype,querytree_list);
659+
}
620660

621661
ReleaseSysCache(tuple);
622662

‎src/backend/executor/functions.c

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.66 2003/06/12 17:29:26 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.67 2003/07/01 00:04:37 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -24,6 +24,7 @@
2424
#include"tcop/tcopprot.h"
2525
#include"tcop/utility.h"
2626
#include"utils/builtins.h"
27+
#include"utils/lsyscache.h"
2728
#include"utils/syscache.h"
2829

2930

@@ -76,7 +77,8 @@ typedef SQLFunctionCache *SQLFunctionCachePtr;
7677

7778
/* non-export function prototypes */
7879
staticexecution_state*init_execution_state(char*src,
79-
Oid*argOidVect,intnargs);
80+
Oid*argOidVect,intnargs,
81+
Oidrettype,boolhaspolyarg);
8082
staticvoidinit_sql_fcache(FmgrInfo*finfo);
8183
staticvoidpostquel_start(execution_state*es,SQLFunctionCachePtrfcache);
8284
staticTupleTableSlot*postquel_getnext(execution_state*es);
@@ -90,7 +92,8 @@ static void ShutdownSQLFunction(Datum arg);
9092

9193

9294
staticexecution_state*
93-
init_execution_state(char*src,Oid*argOidVect,intnargs)
95+
init_execution_state(char*src,Oid*argOidVect,intnargs,
96+
Oidrettype,boolhaspolyarg)
9497
{
9598
execution_state*firstes;
9699
execution_state*preves;
@@ -99,6 +102,13 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
99102

100103
queryTree_list=pg_parse_and_rewrite(src,argOidVect,nargs);
101104

105+
/*
106+
* If the function has any arguments declared as polymorphic types,
107+
* then it wasn't type-checked at definition time; must do so now.
108+
*/
109+
if (haspolyarg)
110+
check_sql_fn_retval(rettype,get_typtype(rettype),queryTree_list);
111+
102112
firstes=NULL;
103113
preves=NULL;
104114

@@ -133,17 +143,21 @@ static void
133143
init_sql_fcache(FmgrInfo*finfo)
134144
{
135145
Oidfoid=finfo->fn_oid;
146+
Oidrettype;
136147
HeapTupleprocedureTuple;
137148
HeapTupletypeTuple;
138149
Form_pg_procprocedureStruct;
139150
Form_pg_typetypeStruct;
140151
SQLFunctionCachePtrfcache;
141152
Oid*argOidVect;
153+
boolhaspolyarg;
142154
char*src;
143155
intnargs;
144156
Datumtmp;
145157
boolisNull;
146158

159+
fcache= (SQLFunctionCachePtr)palloc0(sizeof(SQLFunctionCache));
160+
147161
/*
148162
* get the procedure tuple corresponding to the given function Oid
149163
*/
@@ -153,30 +167,37 @@ init_sql_fcache(FmgrInfo *finfo)
153167
if (!HeapTupleIsValid(procedureTuple))
154168
elog(ERROR,"init_sql_fcache: Cache lookup failed for procedure %u",
155169
foid);
156-
157170
procedureStruct= (Form_pg_proc)GETSTRUCT(procedureTuple);
158171

159172
/*
160-
* get the return type from the procedure tuple
173+
* get the result type from the procedure tuple, and check for
174+
* polymorphic result type; if so, find out the actual result type.
161175
*/
176+
rettype=procedureStruct->prorettype;
177+
178+
if (rettype==ANYARRAYOID||rettype==ANYELEMENTOID)
179+
{
180+
rettype=get_fn_expr_rettype(finfo);
181+
if (rettype==InvalidOid)
182+
elog(ERROR,"could not determine actual result type for function declared %s",
183+
format_type_be(procedureStruct->prorettype));
184+
}
185+
186+
/* Now look up the actual result type */
162187
typeTuple=SearchSysCache(TYPEOID,
163-
ObjectIdGetDatum(procedureStruct->prorettype),
188+
ObjectIdGetDatum(rettype),
164189
0,0,0);
165190
if (!HeapTupleIsValid(typeTuple))
166191
elog(ERROR,"init_sql_fcache: Cache lookup failed for type %u",
167-
procedureStruct->prorettype);
168-
192+
rettype);
169193
typeStruct= (Form_pg_type)GETSTRUCT(typeTuple);
170194

171-
fcache= (SQLFunctionCachePtr)palloc0(sizeof(SQLFunctionCache));
172-
173195
/*
174196
* get the type length and by-value flag from the type tuple
175197
*/
176198
fcache->typlen=typeStruct->typlen;
177199

178-
if (typeStruct->typtype!='c'&&
179-
procedureStruct->prorettype!=RECORDOID)
200+
if (typeStruct->typtype!='c'&&rettype!=RECORDOID)
180201
{
181202
/* The return type is not a composite type, so just use byval */
182203
fcache->typbyval=typeStruct->typbyval;
@@ -205,17 +226,35 @@ init_sql_fcache(FmgrInfo *finfo)
205226
fcache->funcSlot=NULL;
206227

207228
/*
208-
* Parse and plan the queries. We need the argument info to pass
229+
* Parse and plan the queries. We need the argumenttypeinfo to pass
209230
* to the parser.
210231
*/
211232
nargs=procedureStruct->pronargs;
233+
haspolyarg= false;
212234

213235
if (nargs>0)
214236
{
237+
intargnum;
238+
215239
argOidVect= (Oid*)palloc(nargs*sizeof(Oid));
216240
memcpy(argOidVect,
217241
procedureStruct->proargtypes,
218242
nargs*sizeof(Oid));
243+
/* Resolve any polymorphic argument types */
244+
for (argnum=0;argnum<nargs;argnum++)
245+
{
246+
Oidargtype=argOidVect[argnum];
247+
248+
if (argtype==ANYARRAYOID||argtype==ANYELEMENTOID)
249+
{
250+
argtype=get_fn_expr_argtype(finfo,argnum);
251+
if (argtype==InvalidOid)
252+
elog(ERROR,"could not determine actual type of argument declared %s",
253+
format_type_be(argOidVect[argnum]));
254+
argOidVect[argnum]=argtype;
255+
haspolyarg= true;
256+
}
257+
}
219258
}
220259
else
221260
argOidVect= (Oid*)NULL;
@@ -229,7 +268,8 @@ init_sql_fcache(FmgrInfo *finfo)
229268
foid);
230269
src=DatumGetCString(DirectFunctionCall1(textout,tmp));
231270

232-
fcache->func_state=init_execution_state(src,argOidVect,nargs);
271+
fcache->func_state=init_execution_state(src,argOidVect,nargs,
272+
rettype,haspolyarg);
233273

234274
pfree(src);
235275

‎src/backend/optimizer/util/clauses.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.142 2003/06/29 00:33:43 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.143 2003/07/01 00:04:37 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHORDATEMAJOR EVENT
@@ -1731,6 +1731,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
17311731
int*usecounts;
17321732
List*arg;
17331733
inti;
1734+
intj;
17341735

17351736
/*
17361737
* Forget it if the function is not SQL-language or has other
@@ -1742,12 +1743,20 @@ inline_function(Oid funcid, Oid result_type, List *args,
17421743
funcform->pronargs!=length(args))
17431744
returnNULL;
17441745

1745-
/* Forget it if declared return type istupleorvoid */
1746+
/* Forget it if declared return type isnot baseordomain */
17461747
result_typtype=get_typtype(funcform->prorettype);
17471748
if (result_typtype!='b'&&
17481749
result_typtype!='d')
17491750
returnNULL;
17501751

1752+
/* Forget it if any declared argument type is polymorphic */
1753+
for (j=0;j<funcform->pronargs;j++)
1754+
{
1755+
if (funcform->proargtypes[j]==ANYARRAYOID||
1756+
funcform->proargtypes[j]==ANYELEMENTOID)
1757+
returnNULL;
1758+
}
1759+
17511760
/* Check for recursive function, and give up trying to expand if so */
17521761
if (oidMember(funcid,active_fns))
17531762
returnNULL;

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Copyright (c) 2003, PostgreSQL Global Development Group
77
*
88
* IDENTIFICATION
9-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.4 2003/06/27 00:33:25 tgl Exp $
9+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.5 2003/07/01 00:04:38 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -37,8 +37,8 @@ array_push(PG_FUNCTION_ARGS)
3737
int16typlen;
3838
booltypbyval;
3939
chartypalign;
40-
Oidarg0_typeid=get_fn_expr_argtype(fcinfo,0);
41-
Oidarg1_typeid=get_fn_expr_argtype(fcinfo,1);
40+
Oidarg0_typeid=get_fn_expr_argtype(fcinfo->flinfo,0);
41+
Oidarg1_typeid=get_fn_expr_argtype(fcinfo->flinfo,1);
4242
Oidarg0_elemid;
4343
Oidarg1_elemid;
4444
ArrayMetaState*my_extra;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp