33 * functioncmds.c
44 *
55 * Routines for CREATE and DROP FUNCTION commands and CREATE and DROP
6- * CAST commands.
6+ * CAST commands.
77 *
88 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
99 * Portions Copyright (c) 1994, Regents of the University of California
1010 *
1111 *
1212 * IDENTIFICATION
13- * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.55 2005/03/13 05 :19:26 neilc Exp $
13+ * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.56 2005/03/14 00 :19:36 neilc Exp $
1414 *
1515 * DESCRIPTION
1616 * These routines take the parse tree and pick out the
@@ -195,12 +195,75 @@ examine_parameter_list(List *parameter, Oid languageOid,
195195return parameterCount ;
196196}
197197
198+ /*
199+ * Recognize one of the options that can be passed to both CREATE
200+ * FUNCTION and ALTER FUNCTION and return it via one of the out
201+ * parameters. Returns true if the passed option was recognized. If
202+ * the out parameter we were going to assign to points to non-NULL,
203+ * raise a duplicate error.
204+ */
205+ static bool
206+ compute_common_attribute (DefElem * defel ,
207+ DefElem * * volatility_item ,
208+ DefElem * * strict_item ,
209+ DefElem * * security_item )
210+ {
211+ if (strcmp (defel -> defname ,"volatility" )== 0 )
212+ {
213+ if (* volatility_item )
214+ gotoduplicate_error ;
215+
216+ * volatility_item = defel ;
217+ }
218+ else if (strcmp (defel -> defname ,"strict" )== 0 )
219+ {
220+ if (* strict_item )
221+ gotoduplicate_error ;
222+
223+ * strict_item = defel ;
224+ }
225+ else if (strcmp (defel -> defname ,"security" )== 0 )
226+ {
227+ if (* security_item )
228+ gotoduplicate_error ;
229+
230+ * security_item = defel ;
231+ }
232+ else
233+ return false;
234+
235+ /* Recognized an option */
236+ return true;
237+
238+ duplicate_error :
239+ ereport (ERROR ,
240+ (errcode (ERRCODE_SYNTAX_ERROR ),
241+ errmsg ("conflicting or redundant options" )));
242+ return false;/* keep compiler quiet */
243+ }
244+
245+ static char
246+ interpret_func_volatility (DefElem * defel )
247+ {
248+ char * str = strVal (defel -> arg );
249+
250+ if (strcmp (str ,"immutable" )== 0 )
251+ return PROVOLATILE_IMMUTABLE ;
252+ else if (strcmp (str ,"stable" )== 0 )
253+ return PROVOLATILE_STABLE ;
254+ else if (strcmp (str ,"volatile" )== 0 )
255+ return PROVOLATILE_VOLATILE ;
256+ else
257+ {
258+ elog (ERROR ,"invalid volatility \"%s\"" ,str );
259+ return 0 ;/* keep compiler quiet */
260+ }
261+ }
198262
199263/*
200264 * Dissect the list of options assembled in gram.y into function
201265 * attributes.
202266 */
203-
204267static void
205268compute_attributes_sql_style (List * options ,
206269List * * as ,
@@ -236,29 +299,13 @@ compute_attributes_sql_style(List *options,
236299errmsg ("conflicting or redundant options" )));
237300language_item = defel ;
238301}
239- else if (strcmp (defel -> defname ,"volatility" )== 0 )
302+ else if (compute_common_attribute (defel ,
303+ & volatility_item ,
304+ & strict_item ,
305+ & security_item ))
240306{
241- if (volatility_item )
242- ereport (ERROR ,
243- (errcode (ERRCODE_SYNTAX_ERROR ),
244- errmsg ("conflicting or redundant options" )));
245- volatility_item = defel ;
246- }
247- else if (strcmp (defel -> defname ,"strict" )== 0 )
248- {
249- if (strict_item )
250- ereport (ERROR ,
251- (errcode (ERRCODE_SYNTAX_ERROR ),
252- errmsg ("conflicting or redundant options" )));
253- strict_item = defel ;
254- }
255- else if (strcmp (defel -> defname ,"security" )== 0 )
256- {
257- if (security_item )
258- ereport (ERROR ,
259- (errcode (ERRCODE_SYNTAX_ERROR ),
260- errmsg ("conflicting or redundant options" )));
261- security_item = defel ;
307+ /* recognized common option */
308+ continue ;
262309}
263310else
264311elog (ERROR ,"option \"%s\" not recognized" ,
@@ -280,18 +327,7 @@ compute_attributes_sql_style(List *options,
280327errmsg ("no language specified" )));
281328
282329if (volatility_item )
283- {
284- if (strcmp (strVal (volatility_item -> arg ),"immutable" )== 0 )
285- * volatility_p = PROVOLATILE_IMMUTABLE ;
286- else if (strcmp (strVal (volatility_item -> arg ),"stable" )== 0 )
287- * volatility_p = PROVOLATILE_STABLE ;
288- else if (strcmp (strVal (volatility_item -> arg ),"volatile" )== 0 )
289- * volatility_p = PROVOLATILE_VOLATILE ;
290- else
291- elog (ERROR ,"invalid volatility \"%s\"" ,
292- strVal (volatility_item -> arg ));
293- }
294-
330+ * volatility_p = interpret_func_volatility (volatility_item );
295331if (strict_item )
296332* strict_p = intVal (strict_item -> arg );
297333if (security_item )
@@ -301,7 +337,7 @@ compute_attributes_sql_style(List *options,
301337
302338/*-------------
303339 * Interpret the parameters *parameters and return their contents via
304- *out parameters *isStrict_p and *volatility_p.
340+ * *isStrict_p and *volatility_p.
305341 *
306342 *These parameters supply optional information about a function.
307343 *All have defaults if not specified. Parameters:
@@ -347,9 +383,7 @@ compute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatili
347383 * In all other cases
348384 *
349385 * AS <object reference, or sql code>
350- *
351386 */
352-
353387static void
354388interpret_AS_clause (Oid languageOid ,const char * languageName ,List * as ,
355389char * * prosrc_str_p ,char * * probin_str_p )
@@ -799,7 +833,74 @@ AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId)
799833heap_close (rel ,NoLock );
800834}
801835
836+ /*
837+ * Implements the ALTER FUNCTION utility command (except for the
838+ * RENAME and OWNER clauses, which are handled as part of the generic
839+ * ALTER framework).
840+ */
841+ void
842+ AlterFunction (AlterFunctionStmt * stmt )
843+ {
844+ HeapTuple tup ;
845+ Oid funcOid ;
846+ Form_pg_proc procForm ;
847+ Relation rel ;
848+ ListCell * l ;
849+ DefElem * volatility_item = NULL ;
850+ DefElem * strict_item = NULL ;
851+ DefElem * security_def_item = NULL ;
852+
853+ rel = heap_openr (ProcedureRelationName ,RowExclusiveLock );
854+
855+ funcOid = LookupFuncNameTypeNames (stmt -> func -> funcname ,
856+ stmt -> func -> funcargs ,
857+ false);
858+
859+ tup = SearchSysCacheCopy (PROCOID ,
860+ ObjectIdGetDatum (funcOid ),
861+ 0 ,0 ,0 );
862+ if (!HeapTupleIsValid (tup ))/* should not happen */
863+ elog (ERROR ,"cache lookup failed for function %u" ,funcOid );
864+
865+ procForm = (Form_pg_proc )GETSTRUCT (tup );
802866
867+ /* Permission check: must own function */
868+ if (!pg_proc_ownercheck (funcOid ,GetUserId ()))
869+ aclcheck_error (ACLCHECK_NOT_OWNER ,ACL_KIND_PROC ,
870+ NameListToString (stmt -> func -> funcname ));
871+
872+ if (procForm -> proisagg )
873+ ereport (ERROR ,
874+ (errcode (ERRCODE_WRONG_OBJECT_TYPE ),
875+ errmsg ("\"%s\" is an aggregate function" ,
876+ NameListToString (stmt -> func -> funcname ))));
877+
878+ /* Examine requested actions. */
879+ foreach (l ,stmt -> actions )
880+ {
881+ DefElem * defel = (DefElem * )lfirst (l );
882+
883+ if (compute_common_attribute (defel ,
884+ & volatility_item ,
885+ & strict_item ,
886+ & security_def_item )== false)
887+ elog (ERROR ,"option \"%s\" not recognized" ,defel -> defname );
888+ }
889+
890+ if (volatility_item )
891+ procForm -> provolatile = interpret_func_volatility (volatility_item );
892+ if (strict_item )
893+ procForm -> proisstrict = intVal (strict_item -> arg );
894+ if (security_def_item )
895+ procForm -> prosecdef = intVal (security_def_item -> arg );
896+
897+ /* Do the update */
898+ simple_heap_update (rel ,& tup -> t_self ,tup );
899+ CatalogUpdateIndexes (rel ,tup );
900+
901+ heap_close (rel ,NoLock );
902+ heap_freetuple (tup );
903+ }
803904
804905/*
805906 * SetFunctionReturnType - change declared return type of a function