8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
33
33
#include "utils/syscache.h"
34
34
35
35
36
- static void checkretval (Oid rettype , char fn_typtype , List * queryTreeList );
37
36
Datum fmgr_internal_validator (PG_FUNCTION_ARGS );
38
37
Datum fmgr_c_validator (PG_FUNCTION_ARGS );
39
38
Datum fmgr_sql_validator (PG_FUNCTION_ARGS );
@@ -317,15 +316,20 @@ ProcedureCreate(const char *procedureName,
317
316
}
318
317
319
318
/*
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.
321
320
*
322
321
* 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.)
326
330
*/
327
- static void
328
- checkretval (Oid rettype , char fn_typtype , List * queryTreeList )
331
+ void
332
+ check_sql_fn_retval (Oid rettype , char fn_typtype , List * queryTreeList )
329
333
{
330
334
Query * parse ;
331
335
int cmd ;
@@ -472,7 +476,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
472
476
473
477
relation_close (reln , AccessShareLock );
474
478
}
475
- else if (fn_typtype == 'p' && rettype == RECORDOID )
479
+ else if (rettype == RECORDOID )
476
480
{
477
481
/* Shouldn't have a typerelid */
478
482
Assert (typerelid == InvalidOid );
@@ -482,6 +486,14 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
482
486
* tuple.
483
487
*/
484
488
}
489
+ else if (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
+ }
485
497
else
486
498
elog (ERROR , "return type %s is not supported for SQL functions" ,
487
499
format_type_be (rettype ));
@@ -505,7 +517,9 @@ fmgr_internal_validator(PG_FUNCTION_ARGS)
505
517
Datum tmp ;
506
518
char * prosrc ;
507
519
508
- tuple = SearchSysCache (PROCOID , funcoid , 0 , 0 , 0 );
520
+ tuple = SearchSysCache (PROCOID ,
521
+ ObjectIdGetDatum (funcoid ),
522
+ 0 , 0 , 0 );
509
523
if (!HeapTupleIsValid (tuple ))
510
524
elog (ERROR , "cache lookup of function %u failed" , funcoid );
511
525
proc = (Form_pg_proc ) GETSTRUCT (tuple );
@@ -544,7 +558,9 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
544
558
char * prosrc ;
545
559
char * probin ;
546
560
547
- tuple = SearchSysCache (PROCOID , funcoid , 0 , 0 , 0 );
561
+ tuple = SearchSysCache (PROCOID ,
562
+ ObjectIdGetDatum (funcoid ),
563
+ 0 , 0 , 0 );
548
564
if (!HeapTupleIsValid (tuple ))
549
565
elog (ERROR , "cache lookup of function %u failed" , funcoid );
550
566
proc = (Form_pg_proc ) GETSTRUCT (tuple );
@@ -585,38 +601,62 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
585
601
Datum tmp ;
586
602
char * prosrc ;
587
603
char functyptype ;
604
+ bool haspolyarg ;
588
605
int i ;
589
606
590
- tuple = SearchSysCache (PROCOID , funcoid , 0 , 0 , 0 );
607
+ tuple = SearchSysCache (PROCOID ,
608
+ ObjectIdGetDatum (funcoid ),
609
+ 0 , 0 , 0 );
591
610
if (!HeapTupleIsValid (tuple ))
592
611
elog (ERROR , "cache lookup of function %u failed" , funcoid );
593
612
proc = (Form_pg_proc ) GETSTRUCT (tuple );
594
613
595
614
functyptype = get_typtype (proc -> prorettype );
596
615
597
- /* Disallow pseudotypes in arguments and result */
598
- /* except that return type can be RECORD or VOID */
616
+ /* Disallow pseudotype result */
617
+ /* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */
599
618
if (functyptype == 'p' &&
600
619
proc -> prorettype != RECORDOID &&
601
- proc -> prorettype != VOIDOID )
620
+ proc -> prorettype != VOIDOID &&
621
+ proc -> prorettype != ANYARRAYOID &&
622
+ proc -> prorettype != ANYELEMENTOID )
602
623
elog (ERROR , "SQL functions cannot return type %s" ,
603
624
format_type_be (proc -> prorettype ));
604
625
626
+ /* Disallow pseudotypes in arguments */
627
+ /* except for ANYARRAY or ANYELEMENT */
628
+ haspolyarg = false;
605
629
for (i = 0 ; i < proc -> pronargs ; i ++ )
606
630
{
607
631
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
+ }
610
640
}
611
641
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" );
615
652
616
- prosrc = DatumGetCString (DirectFunctionCall1 (textout , tmp ));
653
+ prosrc = DatumGetCString (DirectFunctionCall1 (textout , tmp ));
617
654
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
+ }
620
660
621
661
ReleaseSysCache (tuple );
622
662
0 commit comments