OSDN Git Service

Code review for HeapTupleHeader changes. Add version number to page headers
[pg-rex/syncrep.git] / src / backend / catalog / pg_proc.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_proc.c
4  *        routines to support manipulation of the pg_proc relation
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.92 2002/09/02 01:05:04 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/heapam.h"
18 #include "catalog/catname.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_language.h"
22 #include "catalog/pg_proc.h"
23 #include "executor/executor.h"
24 #include "fmgr.h"
25 #include "miscadmin.h"
26 #include "parser/parse_coerce.h"
27 #include "parser/parse_expr.h"
28 #include "parser/parse_type.h"
29 #include "tcop/tcopprot.h"
30 #include "utils/builtins.h"
31 #include "utils/lsyscache.h"
32 #include "utils/sets.h"
33 #include "utils/syscache.h"
34
35
36 static void checkretval(Oid rettype, char fn_typtype, List *queryTreeList);
37 Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
38 Datum fmgr_c_validator(PG_FUNCTION_ARGS);
39 Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
40
41
42 /* ----------------------------------------------------------------
43  *              ProcedureCreate
44  * ----------------------------------------------------------------
45  */
46 Oid
47 ProcedureCreate(const char *procedureName,
48                                 Oid procNamespace,
49                                 bool replace,
50                                 bool returnsSet,
51                                 Oid returnType,
52                                 Oid languageObjectId,
53                                 Oid languageValidator,
54                                 const char *prosrc,
55                                 const char *probin,
56                                 bool isAgg,
57                                 bool security_definer,
58                                 bool isStrict,
59                                 char volatility,
60                                 int parameterCount,
61                                 const Oid *parameterTypes)
62 {
63         int                     i;
64         Relation        rel;
65         HeapTuple       tup;
66         HeapTuple       oldtup;
67         char            nulls[Natts_pg_proc];
68         Datum           values[Natts_pg_proc];
69         char            replaces[Natts_pg_proc];
70         Oid                     typev[FUNC_MAX_ARGS];
71         Oid                     relid;
72         NameData        procname;
73         TupleDesc       tupDesc;
74         Oid                     retval;
75         bool            is_update;
76         ObjectAddress   myself,
77                                         referenced;
78
79         /*
80          * sanity checks
81          */
82         Assert(PointerIsValid(prosrc));
83         Assert(PointerIsValid(probin));
84
85         if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
86                 elog(ERROR, "functions cannot have more than %d arguments",
87                          FUNC_MAX_ARGS);
88
89         /* Make sure we have a zero-padded param type array */
90         MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid));
91         if (parameterCount > 0)
92                 memcpy(typev, parameterTypes, parameterCount * sizeof(Oid));
93
94         if (languageObjectId == SQLlanguageId)
95         {
96                 /*
97                  * If this call is defining a set, check if the set is already
98                  * defined by looking to see whether this call's function text
99                  * matches a function already in pg_proc.  If so just return the
100                  * OID of the existing set.
101                  */
102                 if (strcmp(procedureName, GENERICSETNAME) == 0)
103                 {
104 #ifdef SETS_FIXED
105
106                         /*
107                          * The code below doesn't work any more because the PROSRC
108                          * system cache and the pg_proc_prosrc_index have been
109                          * removed. Instead a sequential heap scan or something better
110                          * must get implemented. The reason for removing is that
111                          * nbtree index crashes if sources exceed 2K --- what's likely
112                          * for procedural languages.
113                          *
114                          * 1999/09/30 Jan
115                          */
116                         text       *prosrctext;
117
118                         prosrctext = DatumGetTextP(DirectFunctionCall1(textin,
119                                                                                            CStringGetDatum(prosrc)));
120                         retval = GetSysCacheOid(PROSRC,
121                                                                         PointerGetDatum(prosrctext),
122                                                                         0, 0, 0);
123                         pfree(prosrctext);
124                         if (OidIsValid(retval))
125                                 return retval;
126 #else
127                         elog(ERROR, "lookup for procedure by source needs fix (Jan)");
128 #endif   /* SETS_FIXED */
129                 }
130         }
131
132         /*
133          * don't allow functions of complex types that have the same name as
134          * existing attributes of the type
135          */
136         if (parameterCount == 1 && OidIsValid(typev[0]) &&
137                 (relid = typeidTypeRelid(typev[0])) != 0 &&
138                 get_attnum(relid, (char *) procedureName) != InvalidAttrNumber)
139                 elog(ERROR, "method %s already an attribute of type %s",
140                          procedureName, format_type_be(typev[0]));
141
142         /*
143          * All seems OK; prepare the data to be inserted into pg_proc.
144          */
145
146         for (i = 0; i < Natts_pg_proc; ++i)
147         {
148                 nulls[i] = ' ';
149                 values[i] = (Datum) NULL;
150                 replaces[i] = 'r';
151         }
152
153         i = 0;
154         namestrcpy(&procname, procedureName);
155         values[i++] = NameGetDatum(&procname);          /* proname */
156         values[i++] = ObjectIdGetDatum(procNamespace); /* pronamespace */
157         values[i++] = Int32GetDatum(GetUserId());       /* proowner */
158         values[i++] = ObjectIdGetDatum(languageObjectId); /* prolang */
159         values[i++] = BoolGetDatum(isAgg);                      /* proisagg */
160         values[i++] = BoolGetDatum(security_definer); /* prosecdef */
161         values[i++] = BoolGetDatum(isStrict);           /* proisstrict */
162         values[i++] = BoolGetDatum(returnsSet);         /* proretset */
163         values[i++] = CharGetDatum(volatility);         /* provolatile */
164         values[i++] = UInt16GetDatum(parameterCount); /* pronargs */
165         values[i++] = ObjectIdGetDatum(returnType);     /* prorettype */
166         values[i++] = PointerGetDatum(typev);           /* proargtypes */
167         values[i++] = DirectFunctionCall1(textin,       /* prosrc */
168                                                                           CStringGetDatum(prosrc));
169         values[i++] = DirectFunctionCall1(textin,       /* probin */
170                                                                           CStringGetDatum(probin));
171         /* proacl will be handled below */
172
173         rel = heap_openr(ProcedureRelationName, RowExclusiveLock);
174         tupDesc = rel->rd_att;
175
176         /* Check for pre-existing definition */
177         oldtup = SearchSysCache(PROCNAMENSP,
178                                                         PointerGetDatum(procedureName),
179                                                         UInt16GetDatum(parameterCount),
180                                                         PointerGetDatum(typev),
181                                                         ObjectIdGetDatum(procNamespace));
182
183         if (HeapTupleIsValid(oldtup))
184         {
185                 /* There is one; okay to replace it? */
186                 Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
187
188                 if (!replace)
189                         elog(ERROR, "function %s already exists with same argument types",
190                                  procedureName);
191                 if (GetUserId() != oldproc->proowner && !superuser())
192                         elog(ERROR, "ProcedureCreate: you do not have permission to replace function %s",
193                                  procedureName);
194
195                 /*
196                  * Not okay to change the return type of the existing proc, since
197                  * existing rules, views, etc may depend on the return type.
198                  */
199                 if (returnType != oldproc->prorettype ||
200                         returnsSet != oldproc->proretset)
201                         elog(ERROR, "ProcedureCreate: cannot change return type of existing function."
202                                  "\n\tUse DROP FUNCTION first.");
203
204                 /* Can't change aggregate status, either */
205                 if (oldproc->proisagg != isAgg)
206                 {
207                         if (oldproc->proisagg)
208                                 elog(ERROR, "function %s is an aggregate",
209                                          procedureName);
210                         else
211                                 elog(ERROR, "function %s is not an aggregate",
212                                          procedureName);
213                 }
214
215                 /* do not change existing ownership or permissions, either */
216                 replaces[Anum_pg_proc_proowner-1] = ' ';
217                 replaces[Anum_pg_proc_proacl-1] = ' ';
218
219                 /* Okay, do it... */
220                 tup = heap_modifytuple(oldtup, rel, values, nulls, replaces);
221                 simple_heap_update(rel, &tup->t_self, tup);
222
223                 ReleaseSysCache(oldtup);
224                 is_update = true;
225         }
226         else
227         {
228                 /* Creating a new procedure */
229
230                 /* start out with empty permissions */
231                 nulls[Anum_pg_proc_proacl-1] = 'n';
232
233                 tup = heap_formtuple(tupDesc, values, nulls);
234                 simple_heap_insert(rel, tup);
235                 is_update = false;
236         }
237
238         /* Need to update indexes for either the insert or update case */
239         CatalogUpdateIndexes(rel, tup);
240
241         retval = HeapTupleGetOid(tup);
242
243         /*
244          * Create dependencies for the new function.  If we are updating an
245          * existing function, first delete any existing pg_depend entries.
246          */
247         if (is_update)
248                 deleteDependencyRecordsFor(RelOid_pg_proc, retval);
249
250         myself.classId = RelOid_pg_proc;
251         myself.objectId = retval;
252         myself.objectSubId = 0;
253
254         /* dependency on namespace */
255         referenced.classId = get_system_catalog_relid(NamespaceRelationName);
256         referenced.objectId = procNamespace;
257         referenced.objectSubId = 0;
258         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
259
260         /* dependency on implementation language */
261         referenced.classId = get_system_catalog_relid(LanguageRelationName);
262         referenced.objectId = languageObjectId;
263         referenced.objectSubId = 0;
264         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
265
266         /* dependency on return type */
267         referenced.classId = RelOid_pg_type;
268         referenced.objectId = returnType;
269         referenced.objectSubId = 0;
270         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
271
272         /* dependency on input types */
273         for (i = 0; i < parameterCount; i++)
274         {
275                 referenced.classId = RelOid_pg_type;
276                 referenced.objectId = typev[i];
277                 referenced.objectSubId = 0;
278                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
279         }
280
281         heap_freetuple(tup);
282
283         heap_close(rel, RowExclusiveLock);
284
285         /* Verify function body */
286         if (OidIsValid(languageValidator))
287         {
288                 /* Advance command counter so new tuple can be seen by validator */
289                 CommandCounterIncrement();
290                 OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
291         }
292
293         return retval;
294 }
295
296 /*
297  * checkretval() -- check return value of a list of sql parse trees.
298  *
299  * The return value of a sql function is the value returned by
300  * the final query in the function.  We do some ad-hoc define-time
301  * type checking here to be sure that the user is returning the
302  * type he claims.
303  */
304 static void
305 checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
306 {
307         Query      *parse;
308         int                     cmd;
309         List       *tlist;
310         List       *tlistitem;
311         int                     tlistlen;
312         Oid                     typerelid;
313         Oid                     restype;
314         Relation        reln;
315         int                     relnatts;               /* physical number of columns in rel */
316         int                     rellogcols;             /* # of nondeleted columns in rel */
317         int                     colindex;               /* physical column index */
318
319         /* guard against empty function body; OK only if void return type */
320         if (queryTreeList == NIL)
321         {
322                 if (rettype != VOIDOID)
323                         elog(ERROR, "function declared to return %s, but no SELECT provided",
324                                  format_type_be(rettype));
325                 return;
326         }
327
328         /* find the final query */
329         parse = (Query *) nth(length(queryTreeList) - 1, queryTreeList);
330
331         cmd = parse->commandType;
332         tlist = parse->targetList;
333
334         /*
335          * The last query must be a SELECT if and only if return type isn't VOID.
336          */
337         if (rettype == VOIDOID)
338         {
339                 if (cmd == CMD_SELECT)
340                         elog(ERROR, "function declared to return void, but final statement is a SELECT");
341                 return;
342         }
343
344         /* by here, the function is declared to return some type */
345         if (cmd != CMD_SELECT)
346                 elog(ERROR, "function declared to return %s, but final statement is not a SELECT",
347                          format_type_be(rettype));
348
349         /*
350          * Count the non-junk entries in the result targetlist.
351          */
352         tlistlen = ExecCleanTargetListLength(tlist);
353
354         typerelid = typeidTypeRelid(rettype);
355
356         if (fn_typtype == 'b' || fn_typtype == 'd')
357         {
358                 /* Shouldn't have a typerelid */
359                 Assert(typerelid == InvalidOid);
360
361                 /*
362                  * For base-type returns, the target list should have exactly one
363                  * entry, and its type should agree with what the user declared. (As
364                  * of Postgres 7.2, we accept binary-compatible types too.)
365                  */
366                 if (tlistlen != 1)
367                         elog(ERROR, "function declared to return %s returns multiple columns in final SELECT",
368                                  format_type_be(rettype));
369
370                 restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
371                 if (!IsBinaryCompatible(restype, rettype))
372                         elog(ERROR, "return type mismatch in function: declared to return %s, returns %s",
373                                  format_type_be(rettype), format_type_be(restype));
374         }
375         else if (fn_typtype == 'c')
376         {
377                 /* Must have a typerelid */
378                 Assert(typerelid != InvalidOid);
379
380                 /*
381                  * If the target list is of length 1, and the type of the varnode in
382                  * the target list matches the declared return type, this is okay.
383                  * This can happen, for example, where the body of the function is
384                  * 'SELECT func2()', where func2 has the same return type as the
385                  * function that's calling it.
386                  */
387                 if (tlistlen == 1)
388                 {
389                         restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
390                         if (IsBinaryCompatible(restype, rettype))
391                                 return;
392                 }
393
394                 /*
395                  * Otherwise verify that the targetlist matches the return tuple type.
396                  * This part of the typechecking is a hack. We look up the relation
397                  * that is the declared return type, and scan the non-deleted
398                  * attributes to ensure that they match the datatypes of the
399                  * non-resjunk columns.
400                  */
401                 reln = relation_open(typerelid, AccessShareLock);
402                 relnatts = reln->rd_rel->relnatts;
403                 rellogcols = 0;                         /* we'll count nondeleted cols as we go */
404                 colindex = 0;
405
406                 foreach(tlistitem, tlist)
407                 {
408                         TargetEntry *tle = (TargetEntry *) lfirst(tlistitem);
409                         Form_pg_attribute attr;
410                         Oid                     tletype;
411                         Oid                     atttype;
412
413                         if (tle->resdom->resjunk)
414                                 continue;
415
416                         do {
417                                 colindex++;
418                                 if (colindex > relnatts)
419                                         elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
420                                                  format_type_be(rettype), rellogcols);
421                                 attr = reln->rd_att->attrs[colindex - 1];
422                         } while (attr->attisdropped);
423                         rellogcols++;
424
425                         tletype = exprType(tle->expr);
426                         atttype = attr->atttypid;
427                         if (!IsBinaryCompatible(tletype, atttype))
428                                 elog(ERROR, "function declared to return %s returns %s instead of %s at column %d",
429                                          format_type_be(rettype),
430                                          format_type_be(tletype),
431                                          format_type_be(atttype),
432                                          rellogcols);
433                 }
434
435                 for (;;)
436                 {
437                         colindex++;
438                         if (colindex > relnatts)
439                                 break;
440                         if (!reln->rd_att->attrs[colindex - 1]->attisdropped)
441                                 rellogcols++;
442                 }
443
444                 if (tlistlen != rellogcols)
445                         elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
446                                  format_type_be(rettype), rellogcols);
447
448                 relation_close(reln, AccessShareLock);
449         }
450         else if (fn_typtype == 'p' && rettype == RECORDOID)
451         {
452                 /* Shouldn't have a typerelid */
453                 Assert(typerelid == InvalidOid);
454
455                 /*
456                  * For RECORD return type, defer this check until we get the
457                  * first tuple.
458                  */
459         }
460         else
461                 elog(ERROR, "Unknown kind of return type specified for function");
462 }
463
464
465
466 /*
467  * Validator for internal functions
468  *
469  * Check that the given internal function name (the "prosrc" value) is
470  * a known builtin function.
471  */
472 Datum
473 fmgr_internal_validator(PG_FUNCTION_ARGS)
474 {
475         Oid                     funcoid = PG_GETARG_OID(0);
476         HeapTuple       tuple;
477         Form_pg_proc proc;
478         bool            isnull;
479         Datum           tmp;
480         char       *prosrc;
481
482         tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
483         if (!HeapTupleIsValid(tuple))
484                 elog(ERROR, "cache lookup of function %u failed", funcoid);
485         proc = (Form_pg_proc) GETSTRUCT(tuple);
486
487         tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
488         if (isnull)
489                 elog(ERROR, "null prosrc");
490         prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
491
492         if (fmgr_internal_function(prosrc) == InvalidOid)
493                 elog(ERROR, "there is no built-in function named \"%s\"", prosrc);
494
495         ReleaseSysCache(tuple);
496
497         PG_RETURN_VOID();
498 }
499
500
501
502 /*
503  * Validator for C language functions
504  *
505  * Make sure that the library file exists, is loadable, and contains
506  * the specified link symbol. Also check for a valid function
507  * information record.
508  */
509 Datum
510 fmgr_c_validator(PG_FUNCTION_ARGS)
511 {
512         Oid                     funcoid = PG_GETARG_OID(0);
513         void       *libraryhandle;
514         HeapTuple       tuple;
515         Form_pg_proc proc;
516         bool            isnull;
517         Datum           tmp;
518         char       *prosrc;
519         char       *probin;
520
521         tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
522         if (!HeapTupleIsValid(tuple))
523                 elog(ERROR, "cache lookup of function %u failed", funcoid);
524         proc = (Form_pg_proc) GETSTRUCT(tuple);
525
526         tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
527         if (isnull)
528                 elog(ERROR, "null prosrc");
529         prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
530
531         tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull);
532         if (isnull)
533                 elog(ERROR, "null probin");
534         probin = DatumGetCString(DirectFunctionCall1(textout, tmp));
535         
536         (void) load_external_function(probin, prosrc, true, &libraryhandle);
537         (void) fetch_finfo_record(libraryhandle, prosrc);
538
539         ReleaseSysCache(tuple);
540
541         PG_RETURN_VOID();
542 }
543
544
545 /*
546  * Validator for SQL language functions
547  *
548  * Parse it here in order to be sure that it contains no syntax
549  * errors.
550  */
551 Datum
552 fmgr_sql_validator(PG_FUNCTION_ARGS)
553 {
554         Oid                     funcoid = PG_GETARG_OID(0);
555         HeapTuple       tuple;
556         Form_pg_proc proc;
557         List       *querytree_list;
558         bool            isnull;
559         Datum           tmp;
560         char       *prosrc;
561         char            functyptype;
562         int                     i;
563
564         tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
565         if (!HeapTupleIsValid(tuple))
566                 elog(ERROR, "cache lookup of function %u failed", funcoid);
567         proc = (Form_pg_proc) GETSTRUCT(tuple);
568
569         functyptype = get_typtype(proc->prorettype);
570
571         /* Disallow pseudotypes in arguments and result */
572         /* except that return type can be RECORD or VOID */
573         if (functyptype == 'p' &&
574                 proc->prorettype != RECORDOID &&
575                 proc->prorettype != VOIDOID)
576                 elog(ERROR, "SQL functions cannot return type %s",
577                          format_type_be(proc->prorettype));
578
579         for (i = 0; i < proc->pronargs; i++)
580         {
581                 if (get_typtype(proc->proargtypes[i]) == 'p')
582                         elog(ERROR, "SQL functions cannot have arguments of type %s",
583                                  format_type_be(proc->proargtypes[i]));
584         }
585
586         tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
587         if (isnull)
588                 elog(ERROR, "null prosrc");
589
590         prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
591
592         querytree_list = pg_parse_and_rewrite(prosrc, proc->proargtypes, proc->pronargs);
593         checkretval(proc->prorettype, functyptype, querytree_list);
594
595         ReleaseSysCache(tuple);
596
597         PG_RETURN_VOID();
598 }