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