1 /*-------------------------------------------------------------------------
2 *
3 * pg_proc.c
4 * routines to support manipulation of the pg_proc relation
5 *
6 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/catalog/pg_proc.c
12 *
13 *-------------------------------------------------------------------------
14 */
15 #include "postgres.h"
16
17 #include "access/htup_details.h"
18 #include "access/xact.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/objectaccess.h"
22 #include "catalog/pg_language.h"
23 #include "catalog/pg_namespace.h"
24 #include "catalog/pg_proc.h"
25 #include "catalog/pg_proc_fn.h"
26 #include "catalog/pg_transform.h"
27 #include "catalog/pg_type.h"
28 #include "commands/defrem.h"
29 #include "executor/functions.h"
30 #include "funcapi.h"
31 #include "mb/pg_wchar.h"
32 #include "miscadmin.h"
33 #include "nodes/nodeFuncs.h"
34 #include "parser/parse_type.h"
35 #include "tcop/pquery.h"
36 #include "tcop/tcopprot.h"
37 #include "utils/acl.h"
38 #include "utils/builtins.h"
39 #include "utils/lsyscache.h"
40 #include "utils/rel.h"
41 #include "utils/syscache.h"
42
43
44 Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
45 Datum fmgr_c_validator(PG_FUNCTION_ARGS);
46 Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
47
48 typedef struct
49 {
50 char *proname;
51 char *prosrc;
52 } parse_error_callback_arg;
53
54 static void sql_function_parse_error_callback(void *arg);
55 static int match_prosrc_to_query(const char *prosrc, const char *queryText,
56 int cursorpos);
57 static bool match_prosrc_to_literal(const char *prosrc, const char *literal,
58 int cursorpos, int *newcursorpos);
59
60
61 /* ----------------------------------------------------------------
62 * ProcedureCreate
63 *
64 * Note: allParameterTypes, parameterModes, parameterNames, trftypes, and proconfig
65 * are either arrays of the proper types or NULL. We declare them Datum,
66 * not "ArrayType *", to avoid importing array.h into pg_proc_fn.h.
67 * ----------------------------------------------------------------
68 */
69 ObjectAddress
ProcedureCreate(const char * procedureName,Oid procNamespace,bool replace,bool returnsSet,Oid returnType,Oid proowner,Oid languageObjectId,Oid languageValidator,const char * prosrc,const char * probin,bool isAgg,bool isWindowFunc,bool security_definer,bool isLeakProof,bool isStrict,char volatility,char parallel,oidvector * parameterTypes,Datum allParameterTypes,Datum parameterModes,Datum parameterNames,List * parameterDefaults,Datum trftypes,Datum proconfig,float4 procost,float4 prorows)70 ProcedureCreate(const char *procedureName,
71 Oid procNamespace,
72 bool replace,
73 bool returnsSet,
74 Oid returnType,
75 Oid proowner,
76 Oid languageObjectId,
77 Oid languageValidator,
78 const char *prosrc,
79 const char *probin,
80 bool isAgg,
81 bool isWindowFunc,
82 bool security_definer,
83 bool isLeakProof,
84 bool isStrict,
85 char volatility,
86 char parallel,
87 oidvector *parameterTypes,
88 Datum allParameterTypes,
89 Datum parameterModes,
90 Datum parameterNames,
91 List *parameterDefaults,
92 Datum trftypes,
93 Datum proconfig,
94 float4 procost,
95 float4 prorows)
96 {
97 Oid retval;
98 int parameterCount;
99 int allParamCount;
100 Oid *allParams;
101 char *paramModes = NULL;
102 bool genericInParam = false;
103 bool genericOutParam = false;
104 bool anyrangeInParam = false;
105 bool anyrangeOutParam = false;
106 bool internalInParam = false;
107 bool internalOutParam = false;
108 Oid variadicType = InvalidOid;
109 Acl *proacl = NULL;
110 Relation rel;
111 HeapTuple tup;
112 HeapTuple oldtup;
113 bool nulls[Natts_pg_proc];
114 Datum values[Natts_pg_proc];
115 bool replaces[Natts_pg_proc];
116 Oid relid;
117 NameData procname;
118 TupleDesc tupDesc;
119 bool is_update;
120 ObjectAddress myself,
121 referenced;
122 int i;
123 Oid trfid;
124
125 /*
126 * sanity checks
127 */
128 Assert(PointerIsValid(prosrc));
129
130 parameterCount = parameterTypes->dim1;
131 if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
132 ereport(ERROR,
133 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
134 errmsg_plural("functions cannot have more than %d argument",
135 "functions cannot have more than %d arguments",
136 FUNC_MAX_ARGS,
137 FUNC_MAX_ARGS)));
138 /* note: the above is correct, we do NOT count output arguments */
139
140 /* Deconstruct array inputs */
141 if (allParameterTypes != PointerGetDatum(NULL))
142 {
143 /*
144 * We expect the array to be a 1-D OID array; verify that. We don't
145 * need to use deconstruct_array() since the array data is just going
146 * to look like a C array of OID values.
147 */
148 ArrayType *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes);
149
150 allParamCount = ARR_DIMS(allParamArray)[0];
151 if (ARR_NDIM(allParamArray) != 1 ||
152 allParamCount <= 0 ||
153 ARR_HASNULL(allParamArray) ||
154 ARR_ELEMTYPE(allParamArray) != OIDOID)
155 elog(ERROR, "allParameterTypes is not a 1-D Oid array");
156 allParams = (Oid *) ARR_DATA_PTR(allParamArray);
157 Assert(allParamCount >= parameterCount);
158 /* we assume caller got the contents right */
159 }
160 else
161 {
162 allParamCount = parameterCount;
163 allParams = parameterTypes->values;
164 }
165
166 if (parameterModes != PointerGetDatum(NULL))
167 {
168 /*
169 * We expect the array to be a 1-D CHAR array; verify that. We don't
170 * need to use deconstruct_array() since the array data is just going
171 * to look like a C array of char values.
172 */
173 ArrayType *modesArray = (ArrayType *) DatumGetPointer(parameterModes);
174
175 if (ARR_NDIM(modesArray) != 1 ||
176 ARR_DIMS(modesArray)[0] != allParamCount ||
177 ARR_HASNULL(modesArray) ||
178 ARR_ELEMTYPE(modesArray) != CHAROID)
179 elog(ERROR, "parameterModes is not a 1-D char array");
180 paramModes = (char *) ARR_DATA_PTR(modesArray);
181 }
182
183 /*
184 * Detect whether we have polymorphic or INTERNAL arguments. The first
185 * loop checks input arguments, the second output arguments.
186 */
187 for (i = 0; i < parameterCount; i++)
188 {
189 switch (parameterTypes->values[i])
190 {
191 case ANYARRAYOID:
192 case ANYELEMENTOID:
193 case ANYNONARRAYOID:
194 case ANYENUMOID:
195 genericInParam = true;
196 break;
197 case ANYRANGEOID:
198 genericInParam = true;
199 anyrangeInParam = true;
200 break;
201 case INTERNALOID:
202 internalInParam = true;
203 break;
204 }
205 }
206
207 if (allParameterTypes != PointerGetDatum(NULL))
208 {
209 for (i = 0; i < allParamCount; i++)
210 {
211 if (paramModes == NULL ||
212 paramModes[i] == PROARGMODE_IN ||
213 paramModes[i] == PROARGMODE_VARIADIC)
214 continue; /* ignore input-only params */
215
216 switch (allParams[i])
217 {
218 case ANYARRAYOID:
219 case ANYELEMENTOID:
220 case ANYNONARRAYOID:
221 case ANYENUMOID:
222 genericOutParam = true;
223 break;
224 case ANYRANGEOID:
225 genericOutParam = true;
226 anyrangeOutParam = true;
227 break;
228 case INTERNALOID:
229 internalOutParam = true;
230 break;
231 }
232 }
233 }
234
235 /*
236 * Do not allow polymorphic return type unless at least one input argument
237 * is polymorphic. ANYRANGE return type is even stricter: must have an
238 * ANYRANGE input (since we can't deduce the specific range type from
239 * ANYELEMENT). Also, do not allow return type INTERNAL unless at least
240 * one input argument is INTERNAL.
241 */
242 if ((IsPolymorphicType(returnType) || genericOutParam)
243 && !genericInParam)
244 ereport(ERROR,
245 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
246 errmsg("cannot determine result data type"),
247 errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
248
249 if ((returnType == ANYRANGEOID || anyrangeOutParam) &&
250 !anyrangeInParam)
251 ereport(ERROR,
252 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
253 errmsg("cannot determine result data type"),
254 errdetail("A function returning \"anyrange\" must have at least one \"anyrange\" argument.")));
255
256 if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
257 ereport(ERROR,
258 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
259 errmsg("unsafe use of pseudo-type \"internal\""),
260 errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
261
262 /*
263 * don't allow functions of complex types that have the same name as
264 * existing attributes of the type
265 */
266 if (parameterCount == 1 &&
267 OidIsValid(parameterTypes->values[0]) &&
268 (relid = typeidTypeRelid(parameterTypes->values[0])) != InvalidOid &&
269 get_attnum(relid, procedureName) != InvalidAttrNumber)
270 ereport(ERROR,
271 (errcode(ERRCODE_DUPLICATE_COLUMN),
272 errmsg("\"%s\" is already an attribute of type %s",
273 procedureName,
274 format_type_be(parameterTypes->values[0]))));
275
276 if (paramModes != NULL)
277 {
278 /*
279 * Only the last input parameter can be variadic; if it is, save its
280 * element type. Errors here are just elog since caller should have
281 * checked this already.
282 */
283 for (i = 0; i < allParamCount; i++)
284 {
285 switch (paramModes[i])
286 {
287 case PROARGMODE_IN:
288 case PROARGMODE_INOUT:
289 if (OidIsValid(variadicType))
290 elog(ERROR, "variadic parameter must be last");
291 break;
292 case PROARGMODE_OUT:
293 case PROARGMODE_TABLE:
294 /* okay */
295 break;
296 case PROARGMODE_VARIADIC:
297 if (OidIsValid(variadicType))
298 elog(ERROR, "variadic parameter must be last");
299 switch (allParams[i])
300 {
301 case ANYOID:
302 variadicType = ANYOID;
303 break;
304 case ANYARRAYOID:
305 variadicType = ANYELEMENTOID;
306 break;
307 default:
308 variadicType = get_element_type(allParams[i]);
309 if (!OidIsValid(variadicType))
310 elog(ERROR, "variadic parameter is not an array");
311 break;
312 }
313 break;
314 default:
315 elog(ERROR, "invalid parameter mode '%c'", paramModes[i]);
316 break;
317 }
318 }
319 }
320
321 /*
322 * All seems OK; prepare the data to be inserted into pg_proc.
323 */
324
325 for (i = 0; i < Natts_pg_proc; ++i)
326 {
327 nulls[i] = false;
328 values[i] = (Datum) 0;
329 replaces[i] = true;
330 }
331
332 namestrcpy(&procname, procedureName);
333 values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname);
334 values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace);
335 values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(proowner);
336 values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId);
337 values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost);
338 values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
339 values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
340 values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(InvalidOid);
341 values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg);
342 values[Anum_pg_proc_proiswindow - 1] = BoolGetDatum(isWindowFunc);
343 values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
344 values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof);
345 values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
346 values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet);
347 values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility);
348 values[Anum_pg_proc_proparallel - 1] = CharGetDatum(parallel);
349 values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount);
350 values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults));
351 values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType);
352 values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes);
353 if (allParameterTypes != PointerGetDatum(NULL))
354 values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes;
355 else
356 nulls[Anum_pg_proc_proallargtypes - 1] = true;
357 if (parameterModes != PointerGetDatum(NULL))
358 values[Anum_pg_proc_proargmodes - 1] = parameterModes;
359 else
360 nulls[Anum_pg_proc_proargmodes - 1] = true;
361 if (parameterNames != PointerGetDatum(NULL))
362 values[Anum_pg_proc_proargnames - 1] = parameterNames;
363 else
364 nulls[Anum_pg_proc_proargnames - 1] = true;
365 if (parameterDefaults != NIL)
366 values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults));
367 else
368 nulls[Anum_pg_proc_proargdefaults - 1] = true;
369 if (trftypes != PointerGetDatum(NULL))
370 values[Anum_pg_proc_protrftypes - 1] = trftypes;
371 else
372 nulls[Anum_pg_proc_protrftypes - 1] = true;
373 values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc);
374 if (probin)
375 values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);
376 else
377 nulls[Anum_pg_proc_probin - 1] = true;
378 if (proconfig != PointerGetDatum(NULL))
379 values[Anum_pg_proc_proconfig - 1] = proconfig;
380 else
381 nulls[Anum_pg_proc_proconfig - 1] = true;
382 /* proacl will be determined later */
383
384 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
385 tupDesc = RelationGetDescr(rel);
386
387 /* Check for pre-existing definition */
388 oldtup = SearchSysCache3(PROCNAMEARGSNSP,
389 PointerGetDatum(procedureName),
390 PointerGetDatum(parameterTypes),
391 ObjectIdGetDatum(procNamespace));
392
393 if (HeapTupleIsValid(oldtup))
394 {
395 /* There is one; okay to replace it? */
396 Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
397 Datum proargnames;
398 bool isnull;
399
400 if (!replace)
401 ereport(ERROR,
402 (errcode(ERRCODE_DUPLICATE_FUNCTION),
403 errmsg("function \"%s\" already exists with same argument types",
404 procedureName)));
405 if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
406 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
407 procedureName);
408
409 /*
410 * Not okay to change the return type of the existing proc, since
411 * existing rules, views, etc may depend on the return type.
412 */
413 if (returnType != oldproc->prorettype ||
414 returnsSet != oldproc->proretset)
415 ereport(ERROR,
416 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
417 errmsg("cannot change return type of existing function"),
418 errhint("Use DROP FUNCTION %s first.",
419 format_procedure(HeapTupleGetOid(oldtup)))));
420
421 /*
422 * If it returns RECORD, check for possible change of record type
423 * implied by OUT parameters
424 */
425 if (returnType == RECORDOID)
426 {
427 TupleDesc olddesc;
428 TupleDesc newdesc;
429
430 olddesc = build_function_result_tupdesc_t(oldtup);
431 newdesc = build_function_result_tupdesc_d(allParameterTypes,
432 parameterModes,
433 parameterNames);
434 if (olddesc == NULL && newdesc == NULL)
435 /* ok, both are runtime-defined RECORDs */ ;
436 else if (olddesc == NULL || newdesc == NULL ||
437 !equalTupleDescs(olddesc, newdesc))
438 ereport(ERROR,
439 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
440 errmsg("cannot change return type of existing function"),
441 errdetail("Row type defined by OUT parameters is different."),
442 errhint("Use DROP FUNCTION %s first.",
443 format_procedure(HeapTupleGetOid(oldtup)))));
444 }
445
446 /*
447 * If there were any named input parameters, check to make sure the
448 * names have not been changed, as this could break existing calls. We
449 * allow adding names to formerly unnamed parameters, though.
450 */
451 proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
452 Anum_pg_proc_proargnames,
453 &isnull);
454 if (!isnull)
455 {
456 Datum proargmodes;
457 char **old_arg_names;
458 char **new_arg_names;
459 int n_old_arg_names;
460 int n_new_arg_names;
461 int j;
462
463 proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
464 Anum_pg_proc_proargmodes,
465 &isnull);
466 if (isnull)
467 proargmodes = PointerGetDatum(NULL); /* just to be sure */
468
469 n_old_arg_names = get_func_input_arg_names(proargnames,
470 proargmodes,
471 &old_arg_names);
472 n_new_arg_names = get_func_input_arg_names(parameterNames,
473 parameterModes,
474 &new_arg_names);
475 for (j = 0; j < n_old_arg_names; j++)
476 {
477 if (old_arg_names[j] == NULL)
478 continue;
479 if (j >= n_new_arg_names || new_arg_names[j] == NULL ||
480 strcmp(old_arg_names[j], new_arg_names[j]) != 0)
481 ereport(ERROR,
482 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
483 errmsg("cannot change name of input parameter \"%s\"",
484 old_arg_names[j]),
485 errhint("Use DROP FUNCTION %s first.",
486 format_procedure(HeapTupleGetOid(oldtup)))));
487 }
488 }
489
490 /*
491 * If there are existing defaults, check compatibility: redefinition
492 * must not remove any defaults nor change their types. (Removing a
493 * default might cause a function to fail to satisfy an existing call.
494 * Changing type would only be possible if the associated parameter is
495 * polymorphic, and in such cases a change of default type might alter
496 * the resolved output type of existing calls.)
497 */
498 if (oldproc->pronargdefaults != 0)
499 {
500 Datum proargdefaults;
501 List *oldDefaults;
502 ListCell *oldlc;
503 ListCell *newlc;
504
505 if (list_length(parameterDefaults) < oldproc->pronargdefaults)
506 ereport(ERROR,
507 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
508 errmsg("cannot remove parameter defaults from existing function"),
509 errhint("Use DROP FUNCTION %s first.",
510 format_procedure(HeapTupleGetOid(oldtup)))));
511
512 proargdefaults = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
513 Anum_pg_proc_proargdefaults,
514 &isnull);
515 Assert(!isnull);
516 oldDefaults = (List *) stringToNode(TextDatumGetCString(proargdefaults));
517 Assert(IsA(oldDefaults, List));
518 Assert(list_length(oldDefaults) == oldproc->pronargdefaults);
519
520 /* new list can have more defaults than old, advance over 'em */
521 newlc = list_head(parameterDefaults);
522 for (i = list_length(parameterDefaults) - oldproc->pronargdefaults;
523 i > 0;
524 i--)
525 newlc = lnext(newlc);
526
527 foreach(oldlc, oldDefaults)
528 {
529 Node *oldDef = (Node *) lfirst(oldlc);
530 Node *newDef = (Node *) lfirst(newlc);
531
532 if (exprType(oldDef) != exprType(newDef))
533 ereport(ERROR,
534 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
535 errmsg("cannot change data type of existing parameter default value"),
536 errhint("Use DROP FUNCTION %s first.",
537 format_procedure(HeapTupleGetOid(oldtup)))));
538 newlc = lnext(newlc);
539 }
540 }
541
542 /* Can't change aggregate or window-function status, either */
543 if (oldproc->proisagg != isAgg)
544 {
545 if (oldproc->proisagg)
546 ereport(ERROR,
547 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
548 errmsg("function \"%s\" is an aggregate function",
549 procedureName)));
550 else
551 ereport(ERROR,
552 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
553 errmsg("function \"%s\" is not an aggregate function",
554 procedureName)));
555 }
556 if (oldproc->proiswindow != isWindowFunc)
557 {
558 if (oldproc->proiswindow)
559 ereport(ERROR,
560 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
561 errmsg("function \"%s\" is a window function",
562 procedureName)));
563 else
564 ereport(ERROR,
565 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
566 errmsg("function \"%s\" is not a window function",
567 procedureName)));
568 }
569
570 /*
571 * Do not change existing ownership or permissions, either. Note
572 * dependency-update code below has to agree with this decision.
573 */
574 replaces[Anum_pg_proc_proowner - 1] = false;
575 replaces[Anum_pg_proc_proacl - 1] = false;
576
577 /* Okay, do it... */
578 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
579 simple_heap_update(rel, &tup->t_self, tup);
580
581 ReleaseSysCache(oldtup);
582 is_update = true;
583 }
584 else
585 {
586 /* Creating a new procedure */
587
588 /* First, get default permissions and set up proacl */
589 proacl = get_user_default_acl(ACL_OBJECT_FUNCTION, proowner,
590 procNamespace);
591 if (proacl != NULL)
592 values[Anum_pg_proc_proacl - 1] = PointerGetDatum(proacl);
593 else
594 nulls[Anum_pg_proc_proacl - 1] = true;
595
596 tup = heap_form_tuple(tupDesc, values, nulls);
597 simple_heap_insert(rel, tup);
598 is_update = false;
599 }
600
601 /* Need to update indexes for either the insert or update case */
602 CatalogUpdateIndexes(rel, tup);
603
604 retval = HeapTupleGetOid(tup);
605
606 /*
607 * Create dependencies for the new function. If we are updating an
608 * existing function, first delete any existing pg_depend entries.
609 * (However, since we are not changing ownership or permissions, the
610 * shared dependencies do *not* need to change, and we leave them alone.)
611 */
612 if (is_update)
613 deleteDependencyRecordsFor(ProcedureRelationId, retval, true);
614
615 myself.classId = ProcedureRelationId;
616 myself.objectId = retval;
617 myself.objectSubId = 0;
618
619 /* dependency on namespace */
620 referenced.classId = NamespaceRelationId;
621 referenced.objectId = procNamespace;
622 referenced.objectSubId = 0;
623 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
624
625 /* dependency on implementation language */
626 referenced.classId = LanguageRelationId;
627 referenced.objectId = languageObjectId;
628 referenced.objectSubId = 0;
629 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
630
631 /* dependency on return type */
632 referenced.classId = TypeRelationId;
633 referenced.objectId = returnType;
634 referenced.objectSubId = 0;
635 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
636
637 /* dependency on transform used by return type, if any */
638 if ((trfid = get_transform_oid(returnType, languageObjectId, true)))
639 {
640 referenced.classId = TransformRelationId;
641 referenced.objectId = trfid;
642 referenced.objectSubId = 0;
643 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
644 }
645
646 /* dependency on parameter types */
647 for (i = 0; i < allParamCount; i++)
648 {
649 referenced.classId = TypeRelationId;
650 referenced.objectId = allParams[i];
651 referenced.objectSubId = 0;
652 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
653
654 /* dependency on transform used by parameter type, if any */
655 if ((trfid = get_transform_oid(allParams[i], languageObjectId, true)))
656 {
657 referenced.classId = TransformRelationId;
658 referenced.objectId = trfid;
659 referenced.objectSubId = 0;
660 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
661 }
662 }
663
664 /* dependency on parameter default expressions */
665 if (parameterDefaults)
666 recordDependencyOnExpr(&myself, (Node *) parameterDefaults,
667 NIL, DEPENDENCY_NORMAL);
668
669 /* dependency on owner */
670 if (!is_update)
671 recordDependencyOnOwner(ProcedureRelationId, retval, proowner);
672
673 /* dependency on any roles mentioned in ACL */
674 if (!is_update)
675 recordDependencyOnNewAcl(ProcedureRelationId, retval, 0,
676 proowner, proacl);
677
678 /* dependency on extension */
679 recordDependencyOnCurrentExtension(&myself, is_update);
680
681 heap_freetuple(tup);
682
683 /* Post creation hook for new function */
684 InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0);
685
686 heap_close(rel, RowExclusiveLock);
687
688 /* Verify function body */
689 if (OidIsValid(languageValidator))
690 {
691 ArrayType *set_items = NULL;
692 int save_nestlevel = 0;
693
694 /* Advance command counter so new tuple can be seen by validator */
695 CommandCounterIncrement();
696
697 /*
698 * Set per-function configuration parameters so that the validation is
699 * done with the environment the function expects. However, if
700 * check_function_bodies is off, we don't do this, because that would
701 * create dump ordering hazards that pg_dump doesn't know how to deal
702 * with. (For example, a SET clause might refer to a not-yet-created
703 * text search configuration.) This means that the validator
704 * shouldn't complain about anything that might depend on a GUC
705 * parameter when check_function_bodies is off.
706 */
707 if (check_function_bodies)
708 {
709 set_items = (ArrayType *) DatumGetPointer(proconfig);
710 if (set_items) /* Need a new GUC nesting level */
711 {
712 save_nestlevel = NewGUCNestLevel();
713 ProcessGUCArray(set_items,
714 (superuser() ? PGC_SUSET : PGC_USERSET),
715 PGC_S_SESSION,
716 GUC_ACTION_SAVE);
717 }
718 }
719
720 OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
721
722 if (set_items)
723 AtEOXact_GUC(true, save_nestlevel);
724 }
725
726 return myself;
727 }
728
729
730
731 /*
732 * Validator for internal functions
733 *
734 * Check that the given internal function name (the "prosrc" value) is
735 * a known builtin function.
736 */
737 Datum
fmgr_internal_validator(PG_FUNCTION_ARGS)738 fmgr_internal_validator(PG_FUNCTION_ARGS)
739 {
740 Oid funcoid = PG_GETARG_OID(0);
741 HeapTuple tuple;
742 bool isnull;
743 Datum tmp;
744 char *prosrc;
745
746 if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
747 PG_RETURN_VOID();
748
749 /*
750 * We do not honor check_function_bodies since it's unlikely the function
751 * name will be found later if it isn't there now.
752 */
753
754 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
755 if (!HeapTupleIsValid(tuple))
756 elog(ERROR, "cache lookup failed for function %u", funcoid);
757
758 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
759 if (isnull)
760 elog(ERROR, "null prosrc");
761 prosrc = TextDatumGetCString(tmp);
762
763 if (fmgr_internal_function(prosrc) == InvalidOid)
764 ereport(ERROR,
765 (errcode(ERRCODE_UNDEFINED_FUNCTION),
766 errmsg("there is no built-in function named \"%s\"",
767 prosrc)));
768
769 ReleaseSysCache(tuple);
770
771 PG_RETURN_VOID();
772 }
773
774
775
776 /*
777 * Validator for C language functions
778 *
779 * Make sure that the library file exists, is loadable, and contains
780 * the specified link symbol. Also check for a valid function
781 * information record.
782 */
783 Datum
fmgr_c_validator(PG_FUNCTION_ARGS)784 fmgr_c_validator(PG_FUNCTION_ARGS)
785 {
786 Oid funcoid = PG_GETARG_OID(0);
787 void *libraryhandle;
788 HeapTuple tuple;
789 bool isnull;
790 Datum tmp;
791 char *prosrc;
792 char *probin;
793
794 if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
795 PG_RETURN_VOID();
796
797 /*
798 * It'd be most consistent to skip the check if !check_function_bodies,
799 * but the purpose of that switch is to be helpful for pg_dump loading,
800 * and for pg_dump loading it's much better if we *do* check.
801 */
802
803 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
804 if (!HeapTupleIsValid(tuple))
805 elog(ERROR, "cache lookup failed for function %u", funcoid);
806
807 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
808 if (isnull)
809 elog(ERROR, "null prosrc for C function %u", funcoid);
810 prosrc = TextDatumGetCString(tmp);
811
812 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull);
813 if (isnull)
814 elog(ERROR, "null probin for C function %u", funcoid);
815 probin = TextDatumGetCString(tmp);
816
817 (void) load_external_function(probin, prosrc, true, &libraryhandle);
818 (void) fetch_finfo_record(libraryhandle, prosrc);
819
820 ReleaseSysCache(tuple);
821
822 PG_RETURN_VOID();
823 }
824
825
826 /*
827 * Validator for SQL language functions
828 *
829 * Parse it here in order to be sure that it contains no syntax errors.
830 */
831 Datum
fmgr_sql_validator(PG_FUNCTION_ARGS)832 fmgr_sql_validator(PG_FUNCTION_ARGS)
833 {
834 Oid funcoid = PG_GETARG_OID(0);
835 HeapTuple tuple;
836 Form_pg_proc proc;
837 List *raw_parsetree_list;
838 List *querytree_list;
839 ListCell *lc;
840 bool isnull;
841 Datum tmp;
842 char *prosrc;
843 parse_error_callback_arg callback_arg;
844 ErrorContextCallback sqlerrcontext;
845 bool haspolyarg;
846 int i;
847
848 if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
849 PG_RETURN_VOID();
850
851 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
852 if (!HeapTupleIsValid(tuple))
853 elog(ERROR, "cache lookup failed for function %u", funcoid);
854 proc = (Form_pg_proc) GETSTRUCT(tuple);
855
856 /* Disallow pseudotype result */
857 /* except for RECORD, VOID, or polymorphic */
858 if (get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
859 proc->prorettype != RECORDOID &&
860 proc->prorettype != VOIDOID &&
861 !IsPolymorphicType(proc->prorettype))
862 ereport(ERROR,
863 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
864 errmsg("SQL functions cannot return type %s",
865 format_type_be(proc->prorettype))));
866
867 /* Disallow pseudotypes in arguments */
868 /* except for polymorphic */
869 haspolyarg = false;
870 for (i = 0; i < proc->pronargs; i++)
871 {
872 if (get_typtype(proc->proargtypes.values[i]) == TYPTYPE_PSEUDO)
873 {
874 if (IsPolymorphicType(proc->proargtypes.values[i]))
875 haspolyarg = true;
876 else
877 ereport(ERROR,
878 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
879 errmsg("SQL functions cannot have arguments of type %s",
880 format_type_be(proc->proargtypes.values[i]))));
881 }
882 }
883
884 /* Postpone body checks if !check_function_bodies */
885 if (check_function_bodies)
886 {
887 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
888 if (isnull)
889 elog(ERROR, "null prosrc");
890
891 prosrc = TextDatumGetCString(tmp);
892
893 /*
894 * Setup error traceback support for ereport().
895 */
896 callback_arg.proname = NameStr(proc->proname);
897 callback_arg.prosrc = prosrc;
898
899 sqlerrcontext.callback = sql_function_parse_error_callback;
900 sqlerrcontext.arg = (void *) &callback_arg;
901 sqlerrcontext.previous = error_context_stack;
902 error_context_stack = &sqlerrcontext;
903
904 /*
905 * We can't do full prechecking of the function definition if there
906 * are any polymorphic input types, because actual datatypes of
907 * expression results will be unresolvable. The check will be done at
908 * runtime instead.
909 *
910 * We can run the text through the raw parser though; this will at
911 * least catch silly syntactic errors.
912 */
913 raw_parsetree_list = pg_parse_query(prosrc);
914
915 if (!haspolyarg)
916 {
917 /*
918 * OK to do full precheck: analyze and rewrite the queries, then
919 * verify the result type.
920 */
921 SQLFunctionParseInfoPtr pinfo;
922
923 /* But first, set up parameter information */
924 pinfo = prepare_sql_fn_parse_info(tuple, NULL, InvalidOid);
925
926 querytree_list = NIL;
927 foreach(lc, raw_parsetree_list)
928 {
929 Node *parsetree = (Node *) lfirst(lc);
930 List *querytree_sublist;
931
932 querytree_sublist = pg_analyze_and_rewrite_params(parsetree,
933 prosrc,
934 (ParserSetupHook) sql_fn_parser_setup,
935 pinfo);
936 querytree_list = list_concat(querytree_list,
937 querytree_sublist);
938 }
939
940 (void) check_sql_fn_retval(funcoid, proc->prorettype,
941 querytree_list,
942 NULL, NULL);
943 }
944
945 error_context_stack = sqlerrcontext.previous;
946 }
947
948 ReleaseSysCache(tuple);
949
950 PG_RETURN_VOID();
951 }
952
953 /*
954 * Error context callback for handling errors in SQL function definitions
955 */
956 static void
sql_function_parse_error_callback(void * arg)957 sql_function_parse_error_callback(void *arg)
958 {
959 parse_error_callback_arg *callback_arg = (parse_error_callback_arg *) arg;
960
961 /* See if it's a syntax error; if so, transpose to CREATE FUNCTION */
962 if (!function_parse_error_transpose(callback_arg->prosrc))
963 {
964 /* If it's not a syntax error, push info onto context stack */
965 errcontext("SQL function \"%s\"", callback_arg->proname);
966 }
967 }
968
969 /*
970 * Adjust a syntax error occurring inside the function body of a CREATE
971 * FUNCTION or DO command. This can be used by any function validator or
972 * anonymous-block handler, not only for SQL-language functions.
973 * It is assumed that the syntax error position is initially relative to the
974 * function body string (as passed in). If possible, we adjust the position
975 * to reference the original command text; if we can't manage that, we set
976 * up an "internal query" syntax error instead.
977 *
978 * Returns true if a syntax error was processed, false if not.
979 */
980 bool
function_parse_error_transpose(const char * prosrc)981 function_parse_error_transpose(const char *prosrc)
982 {
983 int origerrposition;
984 int newerrposition;
985 const char *queryText;
986
987 /*
988 * Nothing to do unless we are dealing with a syntax error that has a
989 * cursor position.
990 *
991 * Some PLs may prefer to report the error position as an internal error
992 * to begin with, so check that too.
993 */
994 origerrposition = geterrposition();
995 if (origerrposition <= 0)
996 {
997 origerrposition = getinternalerrposition();
998 if (origerrposition <= 0)
999 return false;
1000 }
1001
1002 /* We can get the original query text from the active portal (hack...) */
1003 Assert(ActivePortal && ActivePortal->status == PORTAL_ACTIVE);
1004 queryText = ActivePortal->sourceText;
1005
1006 /* Try to locate the prosrc in the original text */
1007 newerrposition = match_prosrc_to_query(prosrc, queryText, origerrposition);
1008
1009 if (newerrposition > 0)
1010 {
1011 /* Successful, so fix error position to reference original query */
1012 errposition(newerrposition);
1013 /* Get rid of any report of the error as an "internal query" */
1014 internalerrposition(0);
1015 internalerrquery(NULL);
1016 }
1017 else
1018 {
1019 /*
1020 * If unsuccessful, convert the position to an internal position
1021 * marker and give the function text as the internal query.
1022 */
1023 errposition(0);
1024 internalerrposition(origerrposition);
1025 internalerrquery(prosrc);
1026 }
1027
1028 return true;
1029 }
1030
1031 /*
1032 * Try to locate the string literal containing the function body in the
1033 * given text of the CREATE FUNCTION or DO command. If successful, return
1034 * the character (not byte) index within the command corresponding to the
1035 * given character index within the literal. If not successful, return 0.
1036 */
1037 static int
match_prosrc_to_query(const char * prosrc,const char * queryText,int cursorpos)1038 match_prosrc_to_query(const char *prosrc, const char *queryText,
1039 int cursorpos)
1040 {
1041 /*
1042 * Rather than fully parsing the original command, we just scan the
1043 * command looking for $prosrc$ or 'prosrc'. This could be fooled (though
1044 * not in any very probable scenarios), so fail if we find more than one
1045 * match.
1046 */
1047 int prosrclen = strlen(prosrc);
1048 int querylen = strlen(queryText);
1049 int matchpos = 0;
1050 int curpos;
1051 int newcursorpos;
1052
1053 for (curpos = 0; curpos < querylen - prosrclen; curpos++)
1054 {
1055 if (queryText[curpos] == '$' &&
1056 strncmp(prosrc, &queryText[curpos + 1], prosrclen) == 0 &&
1057 queryText[curpos + 1 + prosrclen] == '$')
1058 {
1059 /*
1060 * Found a $foo$ match. Since there are no embedded quoting
1061 * characters in a dollar-quoted literal, we don't have to do any
1062 * fancy arithmetic; just offset by the starting position.
1063 */
1064 if (matchpos)
1065 return 0; /* multiple matches, fail */
1066 matchpos = pg_mbstrlen_with_len(queryText, curpos + 1)
1067 + cursorpos;
1068 }
1069 else if (queryText[curpos] == '\'' &&
1070 match_prosrc_to_literal(prosrc, &queryText[curpos + 1],
1071 cursorpos, &newcursorpos))
1072 {
1073 /*
1074 * Found a 'foo' match. match_prosrc_to_literal() has adjusted
1075 * for any quotes or backslashes embedded in the literal.
1076 */
1077 if (matchpos)
1078 return 0; /* multiple matches, fail */
1079 matchpos = pg_mbstrlen_with_len(queryText, curpos + 1)
1080 + newcursorpos;
1081 }
1082 }
1083
1084 return matchpos;
1085 }
1086
1087 /*
1088 * Try to match the given source text to a single-quoted literal.
1089 * If successful, adjust newcursorpos to correspond to the character
1090 * (not byte) index corresponding to cursorpos in the source text.
1091 *
1092 * At entry, literal points just past a ' character. We must check for the
1093 * trailing quote.
1094 */
1095 static bool
match_prosrc_to_literal(const char * prosrc,const char * literal,int cursorpos,int * newcursorpos)1096 match_prosrc_to_literal(const char *prosrc, const char *literal,
1097 int cursorpos, int *newcursorpos)
1098 {
1099 int newcp = cursorpos;
1100 int chlen;
1101
1102 /*
1103 * This implementation handles backslashes and doubled quotes in the
1104 * string literal. It does not handle the SQL syntax for literals
1105 * continued across line boundaries.
1106 *
1107 * We do the comparison a character at a time, not a byte at a time, so
1108 * that we can do the correct cursorpos math.
1109 */
1110 while (*prosrc)
1111 {
1112 cursorpos--; /* characters left before cursor */
1113
1114 /*
1115 * Check for backslashes and doubled quotes in the literal; adjust
1116 * newcp when one is found before the cursor.
1117 */
1118 if (*literal == '\\')
1119 {
1120 literal++;
1121 if (cursorpos > 0)
1122 newcp++;
1123 }
1124 else if (*literal == '\'')
1125 {
1126 if (literal[1] != '\'')
1127 goto fail;
1128 literal++;
1129 if (cursorpos > 0)
1130 newcp++;
1131 }
1132 chlen = pg_mblen(prosrc);
1133 if (strncmp(prosrc, literal, chlen) != 0)
1134 goto fail;
1135 prosrc += chlen;
1136 literal += chlen;
1137 }
1138
1139 if (*literal == '\'' && literal[1] != '\'')
1140 {
1141 /* success */
1142 *newcursorpos = newcp;
1143 return true;
1144 }
1145
1146 fail:
1147 /* Must set *newcursorpos to suppress compiler warning */
1148 *newcursorpos = newcp;
1149 return false;
1150 }
1151
1152 List *
oid_array_to_list(Datum datum)1153 oid_array_to_list(Datum datum)
1154 {
1155 ArrayType *array = DatumGetArrayTypeP(datum);
1156 Datum *values;
1157 int nelems;
1158 int i;
1159 List *result = NIL;
1160
1161 deconstruct_array(array,
1162 OIDOID,
1163 sizeof(Oid), true, 'i',
1164 &values, NULL, &nelems);
1165 for (i = 0; i < nelems; i++)
1166 result = lappend_oid(result, values[i]);
1167 return result;
1168 }
1169