Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * regproc.c
4 : * Functions for the built-in types regproc, regclass, regtype, etc.
5 : *
6 : * These types are all binary-compatible with type Oid, and rely on Oid
7 : * for comparison and so forth. Their only interesting behavior is in
8 : * special I/O conversion routines.
9 : *
10 : *
11 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
12 : * Portions Copyright (c) 1994, Regents of the University of California
13 : *
14 : *
15 : * IDENTIFICATION
16 : * src/backend/utils/adt/regproc.c
17 : *
18 : *-------------------------------------------------------------------------
19 : */
20 : #include "postgres.h"
21 :
22 : #include <ctype.h>
23 :
24 : #include "access/htup_details.h"
25 : #include "catalog/namespace.h"
26 : #include "catalog/pg_class.h"
27 : #include "catalog/pg_collation.h"
28 : #include "catalog/pg_operator.h"
29 : #include "catalog/pg_proc.h"
30 : #include "catalog/pg_ts_config.h"
31 : #include "catalog/pg_ts_dict.h"
32 : #include "catalog/pg_type.h"
33 : #include "lib/stringinfo.h"
34 : #include "mb/pg_wchar.h"
35 : #include "miscadmin.h"
36 : #include "nodes/miscnodes.h"
37 : #include "parser/parse_type.h"
38 : #include "parser/scansup.h"
39 : #include "utils/acl.h"
40 : #include "utils/builtins.h"
41 : #include "utils/lsyscache.h"
42 : #include "utils/regproc.h"
43 : #include "utils/syscache.h"
44 : #include "utils/varlena.h"
45 :
46 : static bool parseNumericOid(char *string, Oid *result, Node *escontext);
47 : static bool parseDashOrOid(char *string, Oid *result, Node *escontext);
48 : static bool parseNameAndArgTypes(const char *string, bool allowNone,
49 : List **names, int *nargs, Oid *argtypes,
50 : Node *escontext);
51 :
52 :
53 : /*****************************************************************************
54 : * USER I/O ROUTINES *
55 : *****************************************************************************/
56 :
57 : /*
58 : * regprocin - converts "proname" to proc OID
59 : *
60 : * We also accept a numeric OID, for symmetry with the output routine.
61 : *
62 : * '-' signifies unknown (OID 0). In all other cases, the input must
63 : * match an existing pg_proc entry.
64 : */
65 : Datum
66 609454 : regprocin(PG_FUNCTION_ARGS)
67 : {
68 609454 : char *pro_name_or_oid = PG_GETARG_CSTRING(0);
69 609454 : Node *escontext = fcinfo->context;
70 : RegProcedure result;
71 : List *names;
72 : FuncCandidateList clist;
73 :
74 : /* Handle "-" or numeric OID */
75 609454 : if (parseDashOrOid(pro_name_or_oid, &result, escontext))
76 608744 : PG_RETURN_OID(result);
77 :
78 : /* Else it's a name, possibly schema-qualified */
79 :
80 : /*
81 : * We should never get here in bootstrap mode, as all references should
82 : * have been resolved by genbki.pl.
83 : */
84 710 : if (IsBootstrapProcessingMode())
85 0 : elog(ERROR, "regproc values must be OIDs in bootstrap mode");
86 :
87 : /*
88 : * Normal case: parse the name into components and see if it matches any
89 : * pg_proc entries in the current search path.
90 : */
91 710 : names = stringToQualifiedNameList(pro_name_or_oid, escontext);
92 710 : if (names == NIL)
93 0 : PG_RETURN_NULL();
94 :
95 710 : clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true);
96 :
97 710 : if (clist == NULL)
98 30 : ereturn(escontext, (Datum) 0,
99 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
100 : errmsg("function \"%s\" does not exist", pro_name_or_oid)));
101 680 : else if (clist->next != NULL)
102 0 : ereturn(escontext, (Datum) 0,
103 : (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
104 : errmsg("more than one function named \"%s\"",
105 : pro_name_or_oid)));
106 :
107 680 : result = clist->oid;
108 :
109 680 : PG_RETURN_OID(result);
110 : }
111 :
112 : /*
113 : * to_regproc - converts "proname" to proc OID
114 : *
115 : * If the name is not found, we return NULL.
116 : */
117 : Datum
118 24 : to_regproc(PG_FUNCTION_ARGS)
119 : {
120 24 : char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
121 : Datum result;
122 24 : ErrorSaveContext escontext = {T_ErrorSaveContext};
123 :
124 24 : if (!DirectInputFunctionCallSafe(regprocin, pro_name,
125 : InvalidOid, -1,
126 : (Node *) &escontext,
127 : &result))
128 12 : PG_RETURN_NULL();
129 12 : PG_RETURN_DATUM(result);
130 : }
131 :
132 : /*
133 : * regprocout - converts proc OID to "pro_name"
134 : */
135 : Datum
136 46276 : regprocout(PG_FUNCTION_ARGS)
137 : {
138 46276 : RegProcedure proid = PG_GETARG_OID(0);
139 : char *result;
140 : HeapTuple proctup;
141 :
142 46276 : if (proid == InvalidOid)
143 : {
144 22926 : result = pstrdup("-");
145 22926 : PG_RETURN_CSTRING(result);
146 : }
147 :
148 23350 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
149 :
150 23350 : if (HeapTupleIsValid(proctup))
151 : {
152 23350 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
153 23350 : char *proname = NameStr(procform->proname);
154 :
155 : /*
156 : * In bootstrap mode, skip the fancy namespace stuff and just return
157 : * the proc name. (This path is only needed for debugging output
158 : * anyway.)
159 : */
160 23350 : if (IsBootstrapProcessingMode())
161 0 : result = pstrdup(proname);
162 : else
163 : {
164 : char *nspname;
165 : FuncCandidateList clist;
166 :
167 : /*
168 : * Would this proc be found (uniquely!) by regprocin? If not,
169 : * qualify it.
170 : */
171 23350 : clist = FuncnameGetCandidates(list_make1(makeString(proname)),
172 : -1, NIL, false, false, false, false);
173 23350 : if (clist != NULL && clist->next == NULL &&
174 20864 : clist->oid == proid)
175 20864 : nspname = NULL;
176 : else
177 2486 : nspname = get_namespace_name(procform->pronamespace);
178 :
179 23350 : result = quote_qualified_identifier(nspname, proname);
180 : }
181 :
182 23350 : ReleaseSysCache(proctup);
183 : }
184 : else
185 : {
186 : /* If OID doesn't match any pg_proc entry, return it numerically */
187 0 : result = (char *) palloc(NAMEDATALEN);
188 0 : snprintf(result, NAMEDATALEN, "%u", proid);
189 : }
190 :
191 23350 : PG_RETURN_CSTRING(result);
192 : }
193 :
194 : /*
195 : * regprocrecv - converts external binary format to regproc
196 : */
197 : Datum
198 0 : regprocrecv(PG_FUNCTION_ARGS)
199 : {
200 : /* Exactly the same as oidrecv, so share code */
201 0 : return oidrecv(fcinfo);
202 : }
203 :
204 : /*
205 : * regprocsend - converts regproc to binary format
206 : */
207 : Datum
208 0 : regprocsend(PG_FUNCTION_ARGS)
209 : {
210 : /* Exactly the same as oidsend, so share code */
211 0 : return oidsend(fcinfo);
212 : }
213 :
214 :
215 : /*
216 : * regprocedurein - converts "proname(args)" to proc OID
217 : *
218 : * We also accept a numeric OID, for symmetry with the output routine.
219 : *
220 : * '-' signifies unknown (OID 0). In all other cases, the input must
221 : * match an existing pg_proc entry.
222 : */
223 : Datum
224 480 : regprocedurein(PG_FUNCTION_ARGS)
225 : {
226 480 : char *pro_name_or_oid = PG_GETARG_CSTRING(0);
227 480 : Node *escontext = fcinfo->context;
228 : RegProcedure result;
229 : List *names;
230 : int nargs;
231 : Oid argtypes[FUNC_MAX_ARGS];
232 : FuncCandidateList clist;
233 :
234 : /* Handle "-" or numeric OID */
235 480 : if (parseDashOrOid(pro_name_or_oid, &result, escontext))
236 2 : PG_RETURN_OID(result);
237 :
238 : /* The rest of this wouldn't work in bootstrap mode */
239 478 : if (IsBootstrapProcessingMode())
240 0 : elog(ERROR, "regprocedure values must be OIDs in bootstrap mode");
241 :
242 : /*
243 : * Else it's a name and arguments. Parse the name and arguments, look up
244 : * potential matches in the current namespace search list, and scan to see
245 : * which one exactly matches the given argument types. (There will not be
246 : * more than one match.)
247 : */
248 478 : if (!parseNameAndArgTypes(pro_name_or_oid, false,
249 : &names, &nargs, argtypes,
250 : escontext))
251 6 : PG_RETURN_NULL();
252 :
253 472 : clist = FuncnameGetCandidates(names, nargs, NIL, false, false,
254 : false, true);
255 :
256 472 : for (; clist; clist = clist->next)
257 : {
258 442 : if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
259 442 : break;
260 : }
261 :
262 472 : if (clist == NULL)
263 30 : ereturn(escontext, (Datum) 0,
264 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
265 : errmsg("function \"%s\" does not exist", pro_name_or_oid)));
266 :
267 442 : result = clist->oid;
268 :
269 442 : PG_RETURN_OID(result);
270 : }
271 :
272 : /*
273 : * to_regprocedure - converts "proname(args)" to proc OID
274 : *
275 : * If the name is not found, we return NULL.
276 : */
277 : Datum
278 24 : to_regprocedure(PG_FUNCTION_ARGS)
279 : {
280 24 : char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
281 : Datum result;
282 24 : ErrorSaveContext escontext = {T_ErrorSaveContext};
283 :
284 24 : if (!DirectInputFunctionCallSafe(regprocedurein, pro_name,
285 : InvalidOid, -1,
286 : (Node *) &escontext,
287 : &result))
288 12 : PG_RETURN_NULL();
289 12 : PG_RETURN_DATUM(result);
290 : }
291 :
292 : /*
293 : * format_procedure - converts proc OID to "pro_name(args)"
294 : *
295 : * This exports the useful functionality of regprocedureout for use
296 : * in other backend modules. The result is a palloc'd string.
297 : */
298 : char *
299 14228 : format_procedure(Oid procedure_oid)
300 : {
301 14228 : return format_procedure_extended(procedure_oid, 0);
302 : }
303 :
304 : char *
305 0 : format_procedure_qualified(Oid procedure_oid)
306 : {
307 0 : return format_procedure_extended(procedure_oid, FORMAT_PROC_FORCE_QUALIFY);
308 : }
309 :
310 : /*
311 : * format_procedure_extended - converts procedure OID to "pro_name(args)"
312 : *
313 : * This exports the useful functionality of regprocedureout for use
314 : * in other backend modules. The result is a palloc'd string, or NULL.
315 : *
316 : * Routine to produce regprocedure names; see format_procedure above.
317 : *
318 : * The following bits in 'flags' modify the behavior:
319 : * - FORMAT_PROC_INVALID_AS_NULL
320 : * if the procedure OID is invalid or unknown, return NULL instead
321 : * of the numeric OID.
322 : * - FORMAT_PROC_FORCE_QUALIFY
323 : * always schema-qualify procedure names, regardless of search_path
324 : */
325 : char *
326 17404 : format_procedure_extended(Oid procedure_oid, bits16 flags)
327 : {
328 : char *result;
329 : HeapTuple proctup;
330 :
331 17404 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
332 :
333 17404 : if (HeapTupleIsValid(proctup))
334 : {
335 17386 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
336 17386 : char *proname = NameStr(procform->proname);
337 17386 : int nargs = procform->pronargs;
338 : int i;
339 : char *nspname;
340 : StringInfoData buf;
341 :
342 : /* XXX no support here for bootstrap mode */
343 : Assert(!IsBootstrapProcessingMode());
344 :
345 17386 : initStringInfo(&buf);
346 :
347 : /*
348 : * Would this proc be found (given the right args) by regprocedurein?
349 : * If not, or if caller requests it, we need to qualify it.
350 : */
351 34496 : if ((flags & FORMAT_PROC_FORCE_QUALIFY) == 0 &&
352 17110 : FunctionIsVisible(procedure_oid))
353 16430 : nspname = NULL;
354 : else
355 956 : nspname = get_namespace_name(procform->pronamespace);
356 :
357 17386 : appendStringInfo(&buf, "%s(",
358 : quote_qualified_identifier(nspname, proname));
359 44318 : for (i = 0; i < nargs; i++)
360 : {
361 26932 : Oid thisargtype = procform->proargtypes.values[i];
362 :
363 26932 : if (i > 0)
364 15120 : appendStringInfoChar(&buf, ',');
365 26932 : appendStringInfoString(&buf,
366 26932 : (flags & FORMAT_PROC_FORCE_QUALIFY) != 0 ?
367 340 : format_type_be_qualified(thisargtype) :
368 26592 : format_type_be(thisargtype));
369 : }
370 17386 : appendStringInfoChar(&buf, ')');
371 :
372 17386 : result = buf.data;
373 :
374 17386 : ReleaseSysCache(proctup);
375 : }
376 18 : else if ((flags & FORMAT_PROC_INVALID_AS_NULL) != 0)
377 : {
378 : /* If object is undefined, return NULL as wanted by caller */
379 18 : result = NULL;
380 : }
381 : else
382 : {
383 : /* If OID doesn't match any pg_proc entry, return it numerically */
384 0 : result = (char *) palloc(NAMEDATALEN);
385 0 : snprintf(result, NAMEDATALEN, "%u", procedure_oid);
386 : }
387 :
388 17404 : return result;
389 : }
390 :
391 : /*
392 : * Output an objname/objargs representation for the procedure with the
393 : * given OID. If it doesn't exist, an error is thrown.
394 : *
395 : * This can be used to feed get_object_address.
396 : */
397 : void
398 124 : format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs,
399 : bool missing_ok)
400 : {
401 : HeapTuple proctup;
402 : Form_pg_proc procform;
403 : int nargs;
404 : int i;
405 :
406 124 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
407 :
408 124 : if (!HeapTupleIsValid(proctup))
409 : {
410 0 : if (!missing_ok)
411 0 : elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
412 0 : return;
413 : }
414 :
415 124 : procform = (Form_pg_proc) GETSTRUCT(proctup);
416 124 : nargs = procform->pronargs;
417 :
418 124 : *objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
419 : pstrdup(NameStr(procform->proname)));
420 124 : *objargs = NIL;
421 240 : for (i = 0; i < nargs; i++)
422 : {
423 116 : Oid thisargtype = procform->proargtypes.values[i];
424 :
425 116 : *objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
426 : }
427 :
428 124 : ReleaseSysCache(proctup);
429 : }
430 :
431 : /*
432 : * regprocedureout - converts proc OID to "pro_name(args)"
433 : */
434 : Datum
435 7862 : regprocedureout(PG_FUNCTION_ARGS)
436 : {
437 7862 : RegProcedure proid = PG_GETARG_OID(0);
438 : char *result;
439 :
440 7862 : if (proid == InvalidOid)
441 1476 : result = pstrdup("-");
442 : else
443 6386 : result = format_procedure(proid);
444 :
445 7862 : PG_RETURN_CSTRING(result);
446 : }
447 :
448 : /*
449 : * regprocedurerecv - converts external binary format to regprocedure
450 : */
451 : Datum
452 0 : regprocedurerecv(PG_FUNCTION_ARGS)
453 : {
454 : /* Exactly the same as oidrecv, so share code */
455 0 : return oidrecv(fcinfo);
456 : }
457 :
458 : /*
459 : * regproceduresend - converts regprocedure to binary format
460 : */
461 : Datum
462 0 : regproceduresend(PG_FUNCTION_ARGS)
463 : {
464 : /* Exactly the same as oidsend, so share code */
465 0 : return oidsend(fcinfo);
466 : }
467 :
468 :
469 : /*
470 : * regoperin - converts "oprname" to operator OID
471 : *
472 : * We also accept a numeric OID, for symmetry with the output routine.
473 : *
474 : * '0' signifies unknown (OID 0). In all other cases, the input must
475 : * match an existing pg_operator entry.
476 : */
477 : Datum
478 60 : regoperin(PG_FUNCTION_ARGS)
479 : {
480 60 : char *opr_name_or_oid = PG_GETARG_CSTRING(0);
481 60 : Node *escontext = fcinfo->context;
482 : Oid result;
483 : List *names;
484 : FuncCandidateList clist;
485 :
486 : /* Handle "0" or numeric OID */
487 60 : if (parseNumericOid(opr_name_or_oid, &result, escontext))
488 0 : PG_RETURN_OID(result);
489 :
490 : /* Else it's a name, possibly schema-qualified */
491 :
492 : /* The rest of this wouldn't work in bootstrap mode */
493 60 : if (IsBootstrapProcessingMode())
494 0 : elog(ERROR, "regoper values must be OIDs in bootstrap mode");
495 :
496 : /*
497 : * Normal case: parse the name into components and see if it matches any
498 : * pg_operator entries in the current search path.
499 : */
500 60 : names = stringToQualifiedNameList(opr_name_or_oid, escontext);
501 60 : if (names == NIL)
502 0 : PG_RETURN_NULL();
503 :
504 60 : clist = OpernameGetCandidates(names, '\0', true);
505 :
506 60 : if (clist == NULL)
507 30 : ereturn(escontext, (Datum) 0,
508 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
509 : errmsg("operator does not exist: %s", opr_name_or_oid)));
510 30 : else if (clist->next != NULL)
511 6 : ereturn(escontext, (Datum) 0,
512 : (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
513 : errmsg("more than one operator named %s",
514 : opr_name_or_oid)));
515 :
516 24 : result = clist->oid;
517 :
518 24 : PG_RETURN_OID(result);
519 : }
520 :
521 : /*
522 : * to_regoper - converts "oprname" to operator OID
523 : *
524 : * If the name is not found, we return NULL.
525 : */
526 : Datum
527 24 : to_regoper(PG_FUNCTION_ARGS)
528 : {
529 24 : char *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
530 : Datum result;
531 24 : ErrorSaveContext escontext = {T_ErrorSaveContext};
532 :
533 24 : if (!DirectInputFunctionCallSafe(regoperin, opr_name,
534 : InvalidOid, -1,
535 : (Node *) &escontext,
536 : &result))
537 12 : PG_RETURN_NULL();
538 12 : PG_RETURN_DATUM(result);
539 : }
540 :
541 : /*
542 : * regoperout - converts operator OID to "opr_name"
543 : */
544 : Datum
545 24 : regoperout(PG_FUNCTION_ARGS)
546 : {
547 24 : Oid oprid = PG_GETARG_OID(0);
548 : char *result;
549 : HeapTuple opertup;
550 :
551 24 : if (oprid == InvalidOid)
552 : {
553 0 : result = pstrdup("0");
554 0 : PG_RETURN_CSTRING(result);
555 : }
556 :
557 24 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
558 :
559 24 : if (HeapTupleIsValid(opertup))
560 : {
561 24 : Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
562 24 : char *oprname = NameStr(operform->oprname);
563 :
564 : /*
565 : * In bootstrap mode, skip the fancy namespace stuff and just return
566 : * the oper name. (This path is only needed for debugging output
567 : * anyway.)
568 : */
569 24 : if (IsBootstrapProcessingMode())
570 0 : result = pstrdup(oprname);
571 : else
572 : {
573 : FuncCandidateList clist;
574 :
575 : /*
576 : * Would this oper be found (uniquely!) by regoperin? If not,
577 : * qualify it.
578 : */
579 24 : clist = OpernameGetCandidates(list_make1(makeString(oprname)),
580 : '\0', false);
581 24 : if (clist != NULL && clist->next == NULL &&
582 24 : clist->oid == oprid)
583 24 : result = pstrdup(oprname);
584 : else
585 : {
586 : const char *nspname;
587 :
588 0 : nspname = get_namespace_name(operform->oprnamespace);
589 0 : nspname = quote_identifier(nspname);
590 0 : result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2);
591 0 : sprintf(result, "%s.%s", nspname, oprname);
592 : }
593 : }
594 :
595 24 : ReleaseSysCache(opertup);
596 : }
597 : else
598 : {
599 : /*
600 : * If OID doesn't match any pg_operator entry, return it numerically
601 : */
602 0 : result = (char *) palloc(NAMEDATALEN);
603 0 : snprintf(result, NAMEDATALEN, "%u", oprid);
604 : }
605 :
606 24 : PG_RETURN_CSTRING(result);
607 : }
608 :
609 : /*
610 : * regoperrecv - converts external binary format to regoper
611 : */
612 : Datum
613 0 : regoperrecv(PG_FUNCTION_ARGS)
614 : {
615 : /* Exactly the same as oidrecv, so share code */
616 0 : return oidrecv(fcinfo);
617 : }
618 :
619 : /*
620 : * regopersend - converts regoper to binary format
621 : */
622 : Datum
623 0 : regopersend(PG_FUNCTION_ARGS)
624 : {
625 : /* Exactly the same as oidsend, so share code */
626 0 : return oidsend(fcinfo);
627 : }
628 :
629 :
630 : /*
631 : * regoperatorin - converts "oprname(args)" to operator OID
632 : *
633 : * We also accept a numeric OID, for symmetry with the output routine.
634 : *
635 : * '0' signifies unknown (OID 0). In all other cases, the input must
636 : * match an existing pg_operator entry.
637 : */
638 : Datum
639 84 : regoperatorin(PG_FUNCTION_ARGS)
640 : {
641 84 : char *opr_name_or_oid = PG_GETARG_CSTRING(0);
642 84 : Node *escontext = fcinfo->context;
643 : Oid result;
644 : List *names;
645 : int nargs;
646 : Oid argtypes[FUNC_MAX_ARGS];
647 :
648 : /* Handle "0" or numeric OID */
649 84 : if (parseNumericOid(opr_name_or_oid, &result, escontext))
650 0 : PG_RETURN_OID(result);
651 :
652 : /* The rest of this wouldn't work in bootstrap mode */
653 84 : if (IsBootstrapProcessingMode())
654 0 : elog(ERROR, "regoperator values must be OIDs in bootstrap mode");
655 :
656 : /*
657 : * Else it's a name and arguments. Parse the name and arguments, look up
658 : * potential matches in the current namespace search list, and scan to see
659 : * which one exactly matches the given argument types. (There will not be
660 : * more than one match.)
661 : */
662 84 : if (!parseNameAndArgTypes(opr_name_or_oid, true,
663 : &names, &nargs, argtypes,
664 : escontext))
665 6 : PG_RETURN_NULL();
666 :
667 78 : if (nargs == 1)
668 0 : ereturn(escontext, (Datum) 0,
669 : (errcode(ERRCODE_UNDEFINED_PARAMETER),
670 : errmsg("missing argument"),
671 : errhint("Use NONE to denote the missing argument of a unary operator.")));
672 78 : if (nargs != 2)
673 0 : ereturn(escontext, (Datum) 0,
674 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
675 : errmsg("too many arguments"),
676 : errhint("Provide two argument types for operator.")));
677 :
678 78 : result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
679 :
680 78 : if (!OidIsValid(result))
681 30 : ereturn(escontext, (Datum) 0,
682 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
683 : errmsg("operator does not exist: %s", opr_name_or_oid)));
684 :
685 48 : PG_RETURN_OID(result);
686 : }
687 :
688 : /*
689 : * to_regoperator - converts "oprname(args)" to operator OID
690 : *
691 : * If the name is not found, we return NULL.
692 : */
693 : Datum
694 18 : to_regoperator(PG_FUNCTION_ARGS)
695 : {
696 18 : char *opr_name_or_oid = text_to_cstring(PG_GETARG_TEXT_PP(0));
697 : Datum result;
698 18 : ErrorSaveContext escontext = {T_ErrorSaveContext};
699 :
700 18 : if (!DirectInputFunctionCallSafe(regoperatorin, opr_name_or_oid,
701 : InvalidOid, -1,
702 : (Node *) &escontext,
703 : &result))
704 12 : PG_RETURN_NULL();
705 6 : PG_RETURN_DATUM(result);
706 : }
707 :
708 : /*
709 : * format_operator_extended - converts operator OID to "opr_name(args)"
710 : *
711 : * This exports the useful functionality of regoperatorout for use
712 : * in other backend modules. The result is a palloc'd string, or NULL.
713 : *
714 : * The following bits in 'flags' modify the behavior:
715 : * - FORMAT_OPERATOR_INVALID_AS_NULL
716 : * if the operator OID is invalid or unknown, return NULL instead
717 : * of the numeric OID.
718 : * - FORMAT_OPERATOR_FORCE_QUALIFY
719 : * always schema-qualify operator names, regardless of search_path
720 : */
721 : char *
722 2640 : format_operator_extended(Oid operator_oid, bits16 flags)
723 : {
724 : char *result;
725 : HeapTuple opertup;
726 :
727 2640 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
728 :
729 2640 : if (HeapTupleIsValid(opertup))
730 : {
731 2622 : Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
732 2622 : char *oprname = NameStr(operform->oprname);
733 : char *nspname;
734 : StringInfoData buf;
735 :
736 : /* XXX no support here for bootstrap mode */
737 : Assert(!IsBootstrapProcessingMode());
738 :
739 2622 : initStringInfo(&buf);
740 :
741 : /*
742 : * Would this oper be found (given the right args) by regoperatorin?
743 : * If not, or if caller explicitly requests it, we need to qualify it.
744 : */
745 2622 : if ((flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ||
746 2576 : !OperatorIsVisible(operator_oid))
747 : {
748 354 : nspname = get_namespace_name(operform->oprnamespace);
749 354 : appendStringInfo(&buf, "%s.",
750 : quote_identifier(nspname));
751 : }
752 :
753 2622 : appendStringInfo(&buf, "%s(", oprname);
754 :
755 2622 : if (operform->oprleft)
756 2610 : appendStringInfo(&buf, "%s,",
757 2610 : (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
758 46 : format_type_be_qualified(operform->oprleft) :
759 2564 : format_type_be(operform->oprleft));
760 : else
761 12 : appendStringInfoString(&buf, "NONE,");
762 :
763 2622 : if (operform->oprright)
764 2622 : appendStringInfo(&buf, "%s)",
765 2622 : (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
766 46 : format_type_be_qualified(operform->oprright) :
767 2576 : format_type_be(operform->oprright));
768 : else
769 0 : appendStringInfoString(&buf, "NONE)");
770 :
771 2622 : result = buf.data;
772 :
773 2622 : ReleaseSysCache(opertup);
774 : }
775 18 : else if ((flags & FORMAT_OPERATOR_INVALID_AS_NULL) != 0)
776 : {
777 : /* If object is undefined, return NULL as wanted by caller */
778 18 : result = NULL;
779 : }
780 : else
781 : {
782 : /*
783 : * If OID doesn't match any pg_operator entry, return it numerically
784 : */
785 0 : result = (char *) palloc(NAMEDATALEN);
786 0 : snprintf(result, NAMEDATALEN, "%u", operator_oid);
787 : }
788 :
789 2640 : return result;
790 : }
791 :
792 : char *
793 1858 : format_operator(Oid operator_oid)
794 : {
795 1858 : return format_operator_extended(operator_oid, 0);
796 : }
797 :
798 : char *
799 0 : format_operator_qualified(Oid operator_oid)
800 : {
801 0 : return format_operator_extended(operator_oid,
802 : FORMAT_OPERATOR_FORCE_QUALIFY);
803 : }
804 :
805 : void
806 6 : format_operator_parts(Oid operator_oid, List **objnames, List **objargs,
807 : bool missing_ok)
808 : {
809 : HeapTuple opertup;
810 : Form_pg_operator oprForm;
811 :
812 6 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
813 6 : if (!HeapTupleIsValid(opertup))
814 : {
815 0 : if (!missing_ok)
816 0 : elog(ERROR, "cache lookup failed for operator with OID %u",
817 : operator_oid);
818 0 : return;
819 : }
820 :
821 6 : oprForm = (Form_pg_operator) GETSTRUCT(opertup);
822 6 : *objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
823 : pstrdup(NameStr(oprForm->oprname)));
824 6 : *objargs = NIL;
825 6 : if (oprForm->oprleft)
826 6 : *objargs = lappend(*objargs,
827 6 : format_type_be_qualified(oprForm->oprleft));
828 6 : if (oprForm->oprright)
829 6 : *objargs = lappend(*objargs,
830 6 : format_type_be_qualified(oprForm->oprright));
831 :
832 6 : ReleaseSysCache(opertup);
833 : }
834 :
835 : /*
836 : * regoperatorout - converts operator OID to "opr_name(args)"
837 : */
838 : Datum
839 902 : regoperatorout(PG_FUNCTION_ARGS)
840 : {
841 902 : Oid oprid = PG_GETARG_OID(0);
842 : char *result;
843 :
844 902 : if (oprid == InvalidOid)
845 0 : result = pstrdup("0");
846 : else
847 902 : result = format_operator(oprid);
848 :
849 902 : PG_RETURN_CSTRING(result);
850 : }
851 :
852 : /*
853 : * regoperatorrecv - converts external binary format to regoperator
854 : */
855 : Datum
856 0 : regoperatorrecv(PG_FUNCTION_ARGS)
857 : {
858 : /* Exactly the same as oidrecv, so share code */
859 0 : return oidrecv(fcinfo);
860 : }
861 :
862 : /*
863 : * regoperatorsend - converts regoperator to binary format
864 : */
865 : Datum
866 0 : regoperatorsend(PG_FUNCTION_ARGS)
867 : {
868 : /* Exactly the same as oidsend, so share code */
869 0 : return oidsend(fcinfo);
870 : }
871 :
872 :
873 : /*
874 : * regclassin - converts "classname" to class OID
875 : *
876 : * We also accept a numeric OID, for symmetry with the output routine.
877 : *
878 : * '-' signifies unknown (OID 0). In all other cases, the input must
879 : * match an existing pg_class entry.
880 : */
881 : Datum
882 30372 : regclassin(PG_FUNCTION_ARGS)
883 : {
884 30372 : char *class_name_or_oid = PG_GETARG_CSTRING(0);
885 30372 : Node *escontext = fcinfo->context;
886 : Oid result;
887 : List *names;
888 :
889 : /* Handle "-" or numeric OID */
890 30372 : if (parseDashOrOid(class_name_or_oid, &result, escontext))
891 8242 : PG_RETURN_OID(result);
892 :
893 : /* Else it's a name, possibly schema-qualified */
894 :
895 : /* The rest of this wouldn't work in bootstrap mode */
896 22130 : if (IsBootstrapProcessingMode())
897 0 : elog(ERROR, "regclass values must be OIDs in bootstrap mode");
898 :
899 : /*
900 : * Normal case: parse the name into components and see if it matches any
901 : * pg_class entries in the current search path.
902 : */
903 22130 : names = stringToQualifiedNameList(class_name_or_oid, escontext);
904 22130 : if (names == NIL)
905 0 : PG_RETURN_NULL();
906 :
907 : /* We might not even have permissions on this relation; don't lock it. */
908 22130 : result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
909 :
910 22130 : if (!OidIsValid(result))
911 40 : ereturn(escontext, (Datum) 0,
912 : (errcode(ERRCODE_UNDEFINED_TABLE),
913 : errmsg("relation \"%s\" does not exist",
914 : NameListToString(names))));
915 :
916 22090 : PG_RETURN_OID(result);
917 : }
918 :
919 : /*
920 : * to_regclass - converts "classname" to class OID
921 : *
922 : * If the name is not found, we return NULL.
923 : */
924 : Datum
925 24 : to_regclass(PG_FUNCTION_ARGS)
926 : {
927 24 : char *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
928 : Datum result;
929 24 : ErrorSaveContext escontext = {T_ErrorSaveContext};
930 :
931 24 : if (!DirectInputFunctionCallSafe(regclassin, class_name,
932 : InvalidOid, -1,
933 : (Node *) &escontext,
934 : &result))
935 12 : PG_RETURN_NULL();
936 12 : PG_RETURN_DATUM(result);
937 : }
938 :
939 : /*
940 : * regclassout - converts class OID to "class_name"
941 : */
942 : Datum
943 174542 : regclassout(PG_FUNCTION_ARGS)
944 : {
945 174542 : Oid classid = PG_GETARG_OID(0);
946 : char *result;
947 : HeapTuple classtup;
948 :
949 174542 : if (classid == InvalidOid)
950 : {
951 198 : result = pstrdup("-");
952 198 : PG_RETURN_CSTRING(result);
953 : }
954 :
955 174344 : classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
956 :
957 174344 : if (HeapTupleIsValid(classtup))
958 : {
959 174172 : Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
960 174172 : char *classname = NameStr(classform->relname);
961 :
962 : /*
963 : * In bootstrap mode, skip the fancy namespace stuff and just return
964 : * the class name. (This path is only needed for debugging output
965 : * anyway.)
966 : */
967 174172 : if (IsBootstrapProcessingMode())
968 0 : result = pstrdup(classname);
969 : else
970 : {
971 : char *nspname;
972 :
973 : /*
974 : * Would this class be found by regclassin? If not, qualify it.
975 : */
976 174172 : if (RelationIsVisible(classid))
977 114924 : nspname = NULL;
978 : else
979 59248 : nspname = get_namespace_name(classform->relnamespace);
980 :
981 174172 : result = quote_qualified_identifier(nspname, classname);
982 : }
983 :
984 174172 : ReleaseSysCache(classtup);
985 : }
986 : else
987 : {
988 : /* If OID doesn't match any pg_class entry, return it numerically */
989 172 : result = (char *) palloc(NAMEDATALEN);
990 172 : snprintf(result, NAMEDATALEN, "%u", classid);
991 : }
992 :
993 174344 : PG_RETURN_CSTRING(result);
994 : }
995 :
996 : /*
997 : * regclassrecv - converts external binary format to regclass
998 : */
999 : Datum
1000 0 : regclassrecv(PG_FUNCTION_ARGS)
1001 : {
1002 : /* Exactly the same as oidrecv, so share code */
1003 0 : return oidrecv(fcinfo);
1004 : }
1005 :
1006 : /*
1007 : * regclasssend - converts regclass to binary format
1008 : */
1009 : Datum
1010 0 : regclasssend(PG_FUNCTION_ARGS)
1011 : {
1012 : /* Exactly the same as oidsend, so share code */
1013 0 : return oidsend(fcinfo);
1014 : }
1015 :
1016 :
1017 : /*
1018 : * regcollationin - converts "collationname" to collation OID
1019 : *
1020 : * We also accept a numeric OID, for symmetry with the output routine.
1021 : *
1022 : * '-' signifies unknown (OID 0). In all other cases, the input must
1023 : * match an existing pg_collation entry.
1024 : */
1025 : Datum
1026 48 : regcollationin(PG_FUNCTION_ARGS)
1027 : {
1028 48 : char *collation_name_or_oid = PG_GETARG_CSTRING(0);
1029 48 : Node *escontext = fcinfo->context;
1030 : Oid result;
1031 : List *names;
1032 :
1033 : /* Handle "-" or numeric OID */
1034 48 : if (parseDashOrOid(collation_name_or_oid, &result, escontext))
1035 0 : PG_RETURN_OID(result);
1036 :
1037 : /* Else it's a name, possibly schema-qualified */
1038 :
1039 : /* The rest of this wouldn't work in bootstrap mode */
1040 48 : if (IsBootstrapProcessingMode())
1041 0 : elog(ERROR, "regcollation values must be OIDs in bootstrap mode");
1042 :
1043 : /*
1044 : * Normal case: parse the name into components and see if it matches any
1045 : * pg_collation entries in the current search path.
1046 : */
1047 48 : names = stringToQualifiedNameList(collation_name_or_oid, escontext);
1048 48 : if (names == NIL)
1049 0 : PG_RETURN_NULL();
1050 :
1051 48 : result = get_collation_oid(names, true);
1052 :
1053 48 : if (!OidIsValid(result))
1054 24 : ereturn(escontext, (Datum) 0,
1055 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1056 : errmsg("collation \"%s\" for encoding \"%s\" does not exist",
1057 : NameListToString(names), GetDatabaseEncodingName())));
1058 :
1059 24 : PG_RETURN_OID(result);
1060 : }
1061 :
1062 : /*
1063 : * to_regcollation - converts "collationname" to collation OID
1064 : *
1065 : * If the name is not found, we return NULL.
1066 : */
1067 : Datum
1068 24 : to_regcollation(PG_FUNCTION_ARGS)
1069 : {
1070 24 : char *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1071 : Datum result;
1072 24 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1073 :
1074 24 : if (!DirectInputFunctionCallSafe(regcollationin, collation_name,
1075 : InvalidOid, -1,
1076 : (Node *) &escontext,
1077 : &result))
1078 12 : PG_RETURN_NULL();
1079 12 : PG_RETURN_DATUM(result);
1080 : }
1081 :
1082 : /*
1083 : * regcollationout - converts collation OID to "collation_name"
1084 : */
1085 : Datum
1086 24 : regcollationout(PG_FUNCTION_ARGS)
1087 : {
1088 24 : Oid collationid = PG_GETARG_OID(0);
1089 : char *result;
1090 : HeapTuple collationtup;
1091 :
1092 24 : if (collationid == InvalidOid)
1093 : {
1094 0 : result = pstrdup("-");
1095 0 : PG_RETURN_CSTRING(result);
1096 : }
1097 :
1098 24 : collationtup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationid));
1099 :
1100 24 : if (HeapTupleIsValid(collationtup))
1101 : {
1102 24 : Form_pg_collation collationform = (Form_pg_collation) GETSTRUCT(collationtup);
1103 24 : char *collationname = NameStr(collationform->collname);
1104 :
1105 : /*
1106 : * In bootstrap mode, skip the fancy namespace stuff and just return
1107 : * the collation name. (This path is only needed for debugging output
1108 : * anyway.)
1109 : */
1110 24 : if (IsBootstrapProcessingMode())
1111 0 : result = pstrdup(collationname);
1112 : else
1113 : {
1114 : char *nspname;
1115 :
1116 : /*
1117 : * Would this collation be found by regcollationin? If not,
1118 : * qualify it.
1119 : */
1120 24 : if (CollationIsVisible(collationid))
1121 24 : nspname = NULL;
1122 : else
1123 0 : nspname = get_namespace_name(collationform->collnamespace);
1124 :
1125 24 : result = quote_qualified_identifier(nspname, collationname);
1126 : }
1127 :
1128 24 : ReleaseSysCache(collationtup);
1129 : }
1130 : else
1131 : {
1132 : /* If OID doesn't match any pg_collation entry, return it numerically */
1133 0 : result = (char *) palloc(NAMEDATALEN);
1134 0 : snprintf(result, NAMEDATALEN, "%u", collationid);
1135 : }
1136 :
1137 24 : PG_RETURN_CSTRING(result);
1138 : }
1139 :
1140 : /*
1141 : * regcollationrecv - converts external binary format to regcollation
1142 : */
1143 : Datum
1144 0 : regcollationrecv(PG_FUNCTION_ARGS)
1145 : {
1146 : /* Exactly the same as oidrecv, so share code */
1147 0 : return oidrecv(fcinfo);
1148 : }
1149 :
1150 : /*
1151 : * regcollationsend - converts regcollation to binary format
1152 : */
1153 : Datum
1154 0 : regcollationsend(PG_FUNCTION_ARGS)
1155 : {
1156 : /* Exactly the same as oidsend, so share code */
1157 0 : return oidsend(fcinfo);
1158 : }
1159 :
1160 :
1161 : /*
1162 : * regtypein - converts "typename" to type OID
1163 : *
1164 : * The type name can be specified using the full type syntax recognized by
1165 : * the parser; for example, DOUBLE PRECISION and INTEGER[] will work and be
1166 : * translated to the correct type names. (We ignore any typmod info
1167 : * generated by the parser, however.)
1168 : *
1169 : * We also accept a numeric OID, for symmetry with the output routine,
1170 : * and for possible use in bootstrap mode.
1171 : *
1172 : * '-' signifies unknown (OID 0). In all other cases, the input must
1173 : * match an existing pg_type entry.
1174 : */
1175 : Datum
1176 1058 : regtypein(PG_FUNCTION_ARGS)
1177 : {
1178 1058 : char *typ_name_or_oid = PG_GETARG_CSTRING(0);
1179 1058 : Node *escontext = fcinfo->context;
1180 : Oid result;
1181 : int32 typmod;
1182 :
1183 : /* Handle "-" or numeric OID */
1184 1058 : if (parseDashOrOid(typ_name_or_oid, &result, escontext))
1185 20 : PG_RETURN_OID(result);
1186 :
1187 : /* Else it's a type name, possibly schema-qualified or decorated */
1188 :
1189 : /* The rest of this wouldn't work in bootstrap mode */
1190 1038 : if (IsBootstrapProcessingMode())
1191 0 : elog(ERROR, "regtype values must be OIDs in bootstrap mode");
1192 :
1193 : /*
1194 : * Normal case: invoke the full parser to deal with special cases such as
1195 : * array syntax. We don't need to check for parseTypeString failure,
1196 : * since we'll just return anyway.
1197 : */
1198 1038 : (void) parseTypeString(typ_name_or_oid, &result, &typmod, escontext);
1199 :
1200 1002 : PG_RETURN_OID(result);
1201 : }
1202 :
1203 : /*
1204 : * to_regtype - converts "typename" to type OID
1205 : *
1206 : * If the name is not found, we return NULL.
1207 : */
1208 : Datum
1209 24 : to_regtype(PG_FUNCTION_ARGS)
1210 : {
1211 24 : char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1212 : Datum result;
1213 24 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1214 :
1215 24 : if (!DirectInputFunctionCallSafe(regtypein, typ_name,
1216 : InvalidOid, -1,
1217 : (Node *) &escontext,
1218 : &result))
1219 12 : PG_RETURN_NULL();
1220 12 : PG_RETURN_DATUM(result);
1221 : }
1222 :
1223 : /*
1224 : * regtypeout - converts type OID to "typ_name"
1225 : */
1226 : Datum
1227 9384 : regtypeout(PG_FUNCTION_ARGS)
1228 : {
1229 9384 : Oid typid = PG_GETARG_OID(0);
1230 : char *result;
1231 : HeapTuple typetup;
1232 :
1233 9384 : if (typid == InvalidOid)
1234 : {
1235 1048 : result = pstrdup("-");
1236 1048 : PG_RETURN_CSTRING(result);
1237 : }
1238 :
1239 8336 : typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1240 :
1241 8336 : if (HeapTupleIsValid(typetup))
1242 : {
1243 8336 : Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup);
1244 :
1245 : /*
1246 : * In bootstrap mode, skip the fancy namespace stuff and just return
1247 : * the type name. (This path is only needed for debugging output
1248 : * anyway.)
1249 : */
1250 8336 : if (IsBootstrapProcessingMode())
1251 : {
1252 0 : char *typname = NameStr(typeform->typname);
1253 :
1254 0 : result = pstrdup(typname);
1255 : }
1256 : else
1257 8336 : result = format_type_be(typid);
1258 :
1259 8336 : ReleaseSysCache(typetup);
1260 : }
1261 : else
1262 : {
1263 : /* If OID doesn't match any pg_type entry, return it numerically */
1264 0 : result = (char *) palloc(NAMEDATALEN);
1265 0 : snprintf(result, NAMEDATALEN, "%u", typid);
1266 : }
1267 :
1268 8336 : PG_RETURN_CSTRING(result);
1269 : }
1270 :
1271 : /*
1272 : * regtyperecv - converts external binary format to regtype
1273 : */
1274 : Datum
1275 0 : regtyperecv(PG_FUNCTION_ARGS)
1276 : {
1277 : /* Exactly the same as oidrecv, so share code */
1278 0 : return oidrecv(fcinfo);
1279 : }
1280 :
1281 : /*
1282 : * regtypesend - converts regtype to binary format
1283 : */
1284 : Datum
1285 0 : regtypesend(PG_FUNCTION_ARGS)
1286 : {
1287 : /* Exactly the same as oidsend, so share code */
1288 0 : return oidsend(fcinfo);
1289 : }
1290 :
1291 :
1292 : /*
1293 : * regconfigin - converts "tsconfigname" to tsconfig OID
1294 : *
1295 : * We also accept a numeric OID, for symmetry with the output routine.
1296 : *
1297 : * '-' signifies unknown (OID 0). In all other cases, the input must
1298 : * match an existing pg_ts_config entry.
1299 : */
1300 : Datum
1301 1928 : regconfigin(PG_FUNCTION_ARGS)
1302 : {
1303 1928 : char *cfg_name_or_oid = PG_GETARG_CSTRING(0);
1304 1928 : Node *escontext = fcinfo->context;
1305 : Oid result;
1306 : List *names;
1307 :
1308 : /* Handle "-" or numeric OID */
1309 1928 : if (parseDashOrOid(cfg_name_or_oid, &result, escontext))
1310 0 : PG_RETURN_OID(result);
1311 :
1312 : /* The rest of this wouldn't work in bootstrap mode */
1313 1928 : if (IsBootstrapProcessingMode())
1314 0 : elog(ERROR, "regconfig values must be OIDs in bootstrap mode");
1315 :
1316 : /*
1317 : * Normal case: parse the name into components and see if it matches any
1318 : * pg_ts_config entries in the current search path.
1319 : */
1320 1928 : names = stringToQualifiedNameList(cfg_name_or_oid, escontext);
1321 1928 : if (names == NIL)
1322 0 : PG_RETURN_NULL();
1323 :
1324 1928 : result = get_ts_config_oid(names, true);
1325 :
1326 1928 : if (!OidIsValid(result))
1327 6 : ereturn(escontext, (Datum) 0,
1328 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1329 : errmsg("text search configuration \"%s\" does not exist",
1330 : NameListToString(names))));
1331 :
1332 1922 : PG_RETURN_OID(result);
1333 : }
1334 :
1335 : /*
1336 : * regconfigout - converts tsconfig OID to "tsconfigname"
1337 : */
1338 : Datum
1339 10 : regconfigout(PG_FUNCTION_ARGS)
1340 : {
1341 10 : Oid cfgid = PG_GETARG_OID(0);
1342 : char *result;
1343 : HeapTuple cfgtup;
1344 :
1345 10 : if (cfgid == InvalidOid)
1346 : {
1347 0 : result = pstrdup("-");
1348 0 : PG_RETURN_CSTRING(result);
1349 : }
1350 :
1351 10 : cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
1352 :
1353 10 : if (HeapTupleIsValid(cfgtup))
1354 : {
1355 10 : Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
1356 10 : char *cfgname = NameStr(cfgform->cfgname);
1357 : char *nspname;
1358 :
1359 : /*
1360 : * Would this config be found by regconfigin? If not, qualify it.
1361 : */
1362 10 : if (TSConfigIsVisible(cfgid))
1363 6 : nspname = NULL;
1364 : else
1365 4 : nspname = get_namespace_name(cfgform->cfgnamespace);
1366 :
1367 10 : result = quote_qualified_identifier(nspname, cfgname);
1368 :
1369 10 : ReleaseSysCache(cfgtup);
1370 : }
1371 : else
1372 : {
1373 : /* If OID doesn't match any pg_ts_config row, return it numerically */
1374 0 : result = (char *) palloc(NAMEDATALEN);
1375 0 : snprintf(result, NAMEDATALEN, "%u", cfgid);
1376 : }
1377 :
1378 10 : PG_RETURN_CSTRING(result);
1379 : }
1380 :
1381 : /*
1382 : * regconfigrecv - converts external binary format to regconfig
1383 : */
1384 : Datum
1385 0 : regconfigrecv(PG_FUNCTION_ARGS)
1386 : {
1387 : /* Exactly the same as oidrecv, so share code */
1388 0 : return oidrecv(fcinfo);
1389 : }
1390 :
1391 : /*
1392 : * regconfigsend - converts regconfig to binary format
1393 : */
1394 : Datum
1395 0 : regconfigsend(PG_FUNCTION_ARGS)
1396 : {
1397 : /* Exactly the same as oidsend, so share code */
1398 0 : return oidsend(fcinfo);
1399 : }
1400 :
1401 :
1402 : /*
1403 : * regdictionaryin - converts "tsdictionaryname" to tsdictionary OID
1404 : *
1405 : * We also accept a numeric OID, for symmetry with the output routine.
1406 : *
1407 : * '-' signifies unknown (OID 0). In all other cases, the input must
1408 : * match an existing pg_ts_dict entry.
1409 : */
1410 : Datum
1411 600 : regdictionaryin(PG_FUNCTION_ARGS)
1412 : {
1413 600 : char *dict_name_or_oid = PG_GETARG_CSTRING(0);
1414 600 : Node *escontext = fcinfo->context;
1415 : Oid result;
1416 : List *names;
1417 :
1418 : /* Handle "-" or numeric OID */
1419 600 : if (parseDashOrOid(dict_name_or_oid, &result, escontext))
1420 0 : PG_RETURN_OID(result);
1421 :
1422 : /* The rest of this wouldn't work in bootstrap mode */
1423 600 : if (IsBootstrapProcessingMode())
1424 0 : elog(ERROR, "regdictionary values must be OIDs in bootstrap mode");
1425 :
1426 : /*
1427 : * Normal case: parse the name into components and see if it matches any
1428 : * pg_ts_dict entries in the current search path.
1429 : */
1430 600 : names = stringToQualifiedNameList(dict_name_or_oid, escontext);
1431 600 : if (names == NIL)
1432 0 : PG_RETURN_NULL();
1433 :
1434 600 : result = get_ts_dict_oid(names, true);
1435 :
1436 600 : if (!OidIsValid(result))
1437 6 : ereturn(escontext, (Datum) 0,
1438 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1439 : errmsg("text search dictionary \"%s\" does not exist",
1440 : NameListToString(names))));
1441 :
1442 594 : PG_RETURN_OID(result);
1443 : }
1444 :
1445 : /*
1446 : * regdictionaryout - converts tsdictionary OID to "tsdictionaryname"
1447 : */
1448 : Datum
1449 3590 : regdictionaryout(PG_FUNCTION_ARGS)
1450 : {
1451 3590 : Oid dictid = PG_GETARG_OID(0);
1452 : char *result;
1453 : HeapTuple dicttup;
1454 :
1455 3590 : if (dictid == InvalidOid)
1456 : {
1457 0 : result = pstrdup("-");
1458 0 : PG_RETURN_CSTRING(result);
1459 : }
1460 :
1461 3590 : dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
1462 :
1463 3590 : if (HeapTupleIsValid(dicttup))
1464 : {
1465 3590 : Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
1466 3590 : char *dictname = NameStr(dictform->dictname);
1467 : char *nspname;
1468 :
1469 : /*
1470 : * Would this dictionary be found by regdictionaryin? If not, qualify
1471 : * it.
1472 : */
1473 3590 : if (TSDictionaryIsVisible(dictid))
1474 3320 : nspname = NULL;
1475 : else
1476 270 : nspname = get_namespace_name(dictform->dictnamespace);
1477 :
1478 3590 : result = quote_qualified_identifier(nspname, dictname);
1479 :
1480 3590 : ReleaseSysCache(dicttup);
1481 : }
1482 : else
1483 : {
1484 : /* If OID doesn't match any pg_ts_dict row, return it numerically */
1485 0 : result = (char *) palloc(NAMEDATALEN);
1486 0 : snprintf(result, NAMEDATALEN, "%u", dictid);
1487 : }
1488 :
1489 3590 : PG_RETURN_CSTRING(result);
1490 : }
1491 :
1492 : /*
1493 : * regdictionaryrecv - converts external binary format to regdictionary
1494 : */
1495 : Datum
1496 0 : regdictionaryrecv(PG_FUNCTION_ARGS)
1497 : {
1498 : /* Exactly the same as oidrecv, so share code */
1499 0 : return oidrecv(fcinfo);
1500 : }
1501 :
1502 : /*
1503 : * regdictionarysend - converts regdictionary to binary format
1504 : */
1505 : Datum
1506 0 : regdictionarysend(PG_FUNCTION_ARGS)
1507 : {
1508 : /* Exactly the same as oidsend, so share code */
1509 0 : return oidsend(fcinfo);
1510 : }
1511 :
1512 : /*
1513 : * regrolein - converts "rolename" to role OID
1514 : *
1515 : * We also accept a numeric OID, for symmetry with the output routine.
1516 : *
1517 : * '-' signifies unknown (OID 0). In all other cases, the input must
1518 : * match an existing pg_authid entry.
1519 : */
1520 : Datum
1521 212 : regrolein(PG_FUNCTION_ARGS)
1522 : {
1523 212 : char *role_name_or_oid = PG_GETARG_CSTRING(0);
1524 212 : Node *escontext = fcinfo->context;
1525 : Oid result;
1526 : List *names;
1527 :
1528 : /* Handle "-" or numeric OID */
1529 212 : if (parseDashOrOid(role_name_or_oid, &result, escontext))
1530 0 : PG_RETURN_OID(result);
1531 :
1532 : /* The rest of this wouldn't work in bootstrap mode */
1533 212 : if (IsBootstrapProcessingMode())
1534 0 : elog(ERROR, "regrole values must be OIDs in bootstrap mode");
1535 :
1536 : /* Normal case: see if the name matches any pg_authid entry. */
1537 212 : names = stringToQualifiedNameList(role_name_or_oid, escontext);
1538 212 : if (names == NIL)
1539 0 : PG_RETURN_NULL();
1540 :
1541 212 : if (list_length(names) != 1)
1542 18 : ereturn(escontext, (Datum) 0,
1543 : (errcode(ERRCODE_INVALID_NAME),
1544 : errmsg("invalid name syntax")));
1545 :
1546 194 : result = get_role_oid(strVal(linitial(names)), true);
1547 :
1548 194 : if (!OidIsValid(result))
1549 54 : ereturn(escontext, (Datum) 0,
1550 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1551 : errmsg("role \"%s\" does not exist",
1552 : strVal(linitial(names)))));
1553 :
1554 140 : PG_RETURN_OID(result);
1555 : }
1556 :
1557 : /*
1558 : * to_regrole - converts "rolename" to role OID
1559 : *
1560 : * If the name is not found, we return NULL.
1561 : */
1562 : Datum
1563 48 : to_regrole(PG_FUNCTION_ARGS)
1564 : {
1565 48 : char *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1566 : Datum result;
1567 48 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1568 :
1569 48 : if (!DirectInputFunctionCallSafe(regrolein, role_name,
1570 : InvalidOid, -1,
1571 : (Node *) &escontext,
1572 : &result))
1573 36 : PG_RETURN_NULL();
1574 12 : PG_RETURN_DATUM(result);
1575 : }
1576 :
1577 : /*
1578 : * regroleout - converts role OID to "role_name"
1579 : */
1580 : Datum
1581 92 : regroleout(PG_FUNCTION_ARGS)
1582 : {
1583 92 : Oid roleoid = PG_GETARG_OID(0);
1584 : char *result;
1585 :
1586 92 : if (roleoid == InvalidOid)
1587 : {
1588 0 : result = pstrdup("-");
1589 0 : PG_RETURN_CSTRING(result);
1590 : }
1591 :
1592 92 : result = GetUserNameFromId(roleoid, true);
1593 :
1594 92 : if (result)
1595 : {
1596 : /* pstrdup is not really necessary, but it avoids a compiler warning */
1597 92 : result = pstrdup(quote_identifier(result));
1598 : }
1599 : else
1600 : {
1601 : /* If OID doesn't match any role, return it numerically */
1602 0 : result = (char *) palloc(NAMEDATALEN);
1603 0 : snprintf(result, NAMEDATALEN, "%u", roleoid);
1604 : }
1605 :
1606 92 : PG_RETURN_CSTRING(result);
1607 : }
1608 :
1609 : /*
1610 : * regrolerecv - converts external binary format to regrole
1611 : */
1612 : Datum
1613 0 : regrolerecv(PG_FUNCTION_ARGS)
1614 : {
1615 : /* Exactly the same as oidrecv, so share code */
1616 0 : return oidrecv(fcinfo);
1617 : }
1618 :
1619 : /*
1620 : * regrolesend - converts regrole to binary format
1621 : */
1622 : Datum
1623 0 : regrolesend(PG_FUNCTION_ARGS)
1624 : {
1625 : /* Exactly the same as oidsend, so share code */
1626 0 : return oidsend(fcinfo);
1627 : }
1628 :
1629 : /*
1630 : * regnamespacein - converts "nspname" to namespace OID
1631 : *
1632 : * We also accept a numeric OID, for symmetry with the output routine.
1633 : *
1634 : * '-' signifies unknown (OID 0). In all other cases, the input must
1635 : * match an existing pg_namespace entry.
1636 : */
1637 : Datum
1638 526 : regnamespacein(PG_FUNCTION_ARGS)
1639 : {
1640 526 : char *nsp_name_or_oid = PG_GETARG_CSTRING(0);
1641 526 : Node *escontext = fcinfo->context;
1642 : Oid result;
1643 : List *names;
1644 :
1645 : /* Handle "-" or numeric OID */
1646 526 : if (parseDashOrOid(nsp_name_or_oid, &result, escontext))
1647 0 : PG_RETURN_OID(result);
1648 :
1649 : /* The rest of this wouldn't work in bootstrap mode */
1650 526 : if (IsBootstrapProcessingMode())
1651 0 : elog(ERROR, "regnamespace values must be OIDs in bootstrap mode");
1652 :
1653 : /* Normal case: see if the name matches any pg_namespace entry. */
1654 526 : names = stringToQualifiedNameList(nsp_name_or_oid, escontext);
1655 526 : if (names == NIL)
1656 0 : PG_RETURN_NULL();
1657 :
1658 526 : if (list_length(names) != 1)
1659 12 : ereturn(escontext, (Datum) 0,
1660 : (errcode(ERRCODE_INVALID_NAME),
1661 : errmsg("invalid name syntax")));
1662 :
1663 514 : result = get_namespace_oid(strVal(linitial(names)), true);
1664 :
1665 514 : if (!OidIsValid(result))
1666 30 : ereturn(escontext, (Datum) 0,
1667 : (errcode(ERRCODE_UNDEFINED_SCHEMA),
1668 : errmsg("schema \"%s\" does not exist",
1669 : strVal(linitial(names)))));
1670 :
1671 484 : PG_RETURN_OID(result);
1672 : }
1673 :
1674 : /*
1675 : * to_regnamespace - converts "nspname" to namespace OID
1676 : *
1677 : * If the name is not found, we return NULL.
1678 : */
1679 : Datum
1680 30 : to_regnamespace(PG_FUNCTION_ARGS)
1681 : {
1682 30 : char *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1683 : Datum result;
1684 30 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1685 :
1686 30 : if (!DirectInputFunctionCallSafe(regnamespacein, nsp_name,
1687 : InvalidOid, -1,
1688 : (Node *) &escontext,
1689 : &result))
1690 18 : PG_RETURN_NULL();
1691 12 : PG_RETURN_DATUM(result);
1692 : }
1693 :
1694 : /*
1695 : * regnamespaceout - converts namespace OID to "nsp_name"
1696 : */
1697 : Datum
1698 1078 : regnamespaceout(PG_FUNCTION_ARGS)
1699 : {
1700 1078 : Oid nspid = PG_GETARG_OID(0);
1701 : char *result;
1702 :
1703 1078 : if (nspid == InvalidOid)
1704 : {
1705 0 : result = pstrdup("-");
1706 0 : PG_RETURN_CSTRING(result);
1707 : }
1708 :
1709 1078 : result = get_namespace_name(nspid);
1710 :
1711 1078 : if (result)
1712 : {
1713 : /* pstrdup is not really necessary, but it avoids a compiler warning */
1714 1078 : result = pstrdup(quote_identifier(result));
1715 : }
1716 : else
1717 : {
1718 : /* If OID doesn't match any namespace, return it numerically */
1719 0 : result = (char *) palloc(NAMEDATALEN);
1720 0 : snprintf(result, NAMEDATALEN, "%u", nspid);
1721 : }
1722 :
1723 1078 : PG_RETURN_CSTRING(result);
1724 : }
1725 :
1726 : /*
1727 : * regnamespacerecv - converts external binary format to regnamespace
1728 : */
1729 : Datum
1730 0 : regnamespacerecv(PG_FUNCTION_ARGS)
1731 : {
1732 : /* Exactly the same as oidrecv, so share code */
1733 0 : return oidrecv(fcinfo);
1734 : }
1735 :
1736 : /*
1737 : * regnamespacesend - converts regnamespace to binary format
1738 : */
1739 : Datum
1740 0 : regnamespacesend(PG_FUNCTION_ARGS)
1741 : {
1742 : /* Exactly the same as oidsend, so share code */
1743 0 : return oidsend(fcinfo);
1744 : }
1745 :
1746 : /*
1747 : * text_regclass: convert text to regclass
1748 : *
1749 : * This could be replaced by CoerceViaIO, except that we need to treat
1750 : * text-to-regclass as an implicit cast to support legacy forms of nextval()
1751 : * and related functions.
1752 : */
1753 : Datum
1754 48 : text_regclass(PG_FUNCTION_ARGS)
1755 : {
1756 48 : text *relname = PG_GETARG_TEXT_PP(0);
1757 : Oid result;
1758 : RangeVar *rv;
1759 :
1760 48 : rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
1761 :
1762 : /* We might not even have permissions on this relation; don't lock it. */
1763 48 : result = RangeVarGetRelid(rv, NoLock, false);
1764 :
1765 42 : PG_RETURN_OID(result);
1766 : }
1767 :
1768 :
1769 : /*
1770 : * Given a C string, parse it into a qualified-name list.
1771 : *
1772 : * If escontext is an ErrorSaveContext node, invalid input will be
1773 : * reported there instead of being thrown, and we return NIL.
1774 : * (NIL is not possible as a success return, since empty-input is an error.)
1775 : */
1776 : List *
1777 32064 : stringToQualifiedNameList(const char *string, Node *escontext)
1778 : {
1779 : char *rawname;
1780 32064 : List *result = NIL;
1781 : List *namelist;
1782 : ListCell *l;
1783 :
1784 : /* We need a modifiable copy of the input string. */
1785 32064 : rawname = pstrdup(string);
1786 :
1787 32064 : if (!SplitIdentifierString(rawname, '.', &namelist))
1788 0 : ereturn(escontext, NIL,
1789 : (errcode(ERRCODE_INVALID_NAME),
1790 : errmsg("invalid name syntax")));
1791 :
1792 32064 : if (namelist == NIL)
1793 0 : ereturn(escontext, NIL,
1794 : (errcode(ERRCODE_INVALID_NAME),
1795 : errmsg("invalid name syntax")));
1796 :
1797 80616 : foreach(l, namelist)
1798 : {
1799 48552 : char *curname = (char *) lfirst(l);
1800 :
1801 48552 : result = lappend(result, makeString(pstrdup(curname)));
1802 : }
1803 :
1804 32064 : pfree(rawname);
1805 32064 : list_free(namelist);
1806 :
1807 32064 : return result;
1808 : }
1809 :
1810 : /*****************************************************************************
1811 : * SUPPORT ROUTINES *
1812 : *****************************************************************************/
1813 :
1814 : /*
1815 : * Given a C string, see if it is all-digits (and not empty).
1816 : * If so, convert directly to OID and return true.
1817 : * If it is not all-digits, return false.
1818 : *
1819 : * If escontext is an ErrorSaveContext node, any error in oidin() will be
1820 : * reported there instead of being thrown (but we still return true).
1821 : */
1822 : static bool
1823 523926 : parseNumericOid(char *string, Oid *result, Node *escontext)
1824 : {
1825 523926 : if (string[0] >= '0' && string[0] <= '9' &&
1826 496112 : strspn(string, "0123456789") == strlen(string))
1827 : {
1828 : Datum oid_datum;
1829 :
1830 : /* We need not care here whether oidin() fails or not. */
1831 496112 : (void) DirectInputFunctionCallSafe(oidin, string,
1832 : InvalidOid, -1,
1833 : escontext,
1834 : &oid_datum);
1835 496112 : *result = DatumGetObjectId(oid_datum);
1836 496112 : return true;
1837 : }
1838 :
1839 : /* Prevent uninitialized-variable warnings from stupider compilers. */
1840 27814 : *result = InvalidOid;
1841 27814 : return false;
1842 : }
1843 :
1844 : /*
1845 : * As above, but also accept "-" as meaning 0 (InvalidOid).
1846 : */
1847 : static bool
1848 644678 : parseDashOrOid(char *string, Oid *result, Node *escontext)
1849 : {
1850 : /* '-' ? */
1851 644678 : if (strcmp(string, "-") == 0)
1852 : {
1853 120896 : *result = InvalidOid;
1854 120896 : return true;
1855 : }
1856 :
1857 : /* Numeric OID? */
1858 523782 : return parseNumericOid(string, result, escontext);
1859 : }
1860 :
1861 : /*
1862 : * Given a C string, parse it into a qualified function or operator name
1863 : * followed by a parenthesized list of type names. Reduce the
1864 : * type names to an array of OIDs (returned into *nargs and *argtypes;
1865 : * the argtypes array should be of size FUNC_MAX_ARGS). The function or
1866 : * operator name is returned to *names as a List of Strings.
1867 : *
1868 : * If allowNone is true, accept "NONE" and return it as InvalidOid (this is
1869 : * for unary operators).
1870 : *
1871 : * Returns true on success, false on failure (the latter only possible
1872 : * if escontext is an ErrorSaveContext node).
1873 : */
1874 : static bool
1875 562 : parseNameAndArgTypes(const char *string, bool allowNone, List **names,
1876 : int *nargs, Oid *argtypes,
1877 : Node *escontext)
1878 : {
1879 : char *rawname;
1880 : char *ptr;
1881 : char *ptr2;
1882 : char *typename;
1883 : bool in_quote;
1884 : bool had_comma;
1885 : int paren_count;
1886 : Oid typeid;
1887 : int32 typmod;
1888 :
1889 : /* We need a modifiable copy of the input string. */
1890 562 : rawname = pstrdup(string);
1891 :
1892 : /* Scan to find the expected left paren; mustn't be quoted */
1893 562 : in_quote = false;
1894 9796 : for (ptr = rawname; *ptr; ptr++)
1895 : {
1896 9790 : if (*ptr == '"')
1897 0 : in_quote = !in_quote;
1898 9790 : else if (*ptr == '(' && !in_quote)
1899 556 : break;
1900 : }
1901 562 : if (*ptr == '\0')
1902 6 : ereturn(escontext, false,
1903 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1904 : errmsg("expected a left parenthesis")));
1905 :
1906 : /* Separate the name and parse it into a list */
1907 556 : *ptr++ = '\0';
1908 556 : *names = stringToQualifiedNameList(rawname, escontext);
1909 556 : if (*names == NIL)
1910 0 : return false;
1911 :
1912 : /* Check for the trailing right parenthesis and remove it */
1913 556 : ptr2 = ptr + strlen(ptr);
1914 574 : while (--ptr2 > ptr)
1915 : {
1916 492 : if (!scanner_isspace(*ptr2))
1917 474 : break;
1918 : }
1919 556 : if (*ptr2 != ')')
1920 6 : ereturn(escontext, false,
1921 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1922 : errmsg("expected a right parenthesis")));
1923 :
1924 550 : *ptr2 = '\0';
1925 :
1926 : /* Separate the remaining string into comma-separated type names */
1927 550 : *nargs = 0;
1928 550 : had_comma = false;
1929 :
1930 : for (;;)
1931 : {
1932 : /* allow leading whitespace */
1933 1156 : while (scanner_isspace(*ptr))
1934 30 : ptr++;
1935 1126 : if (*ptr == '\0')
1936 : {
1937 : /* End of string. Okay unless we had a comma before. */
1938 550 : if (had_comma)
1939 0 : ereturn(escontext, false,
1940 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1941 : errmsg("expected a type name")));
1942 550 : break;
1943 : }
1944 576 : typename = ptr;
1945 : /* Find end of type name --- end of string or comma */
1946 : /* ... but not a quoted or parenthesized comma */
1947 576 : in_quote = false;
1948 576 : paren_count = 0;
1949 5232 : for (; *ptr; ptr++)
1950 : {
1951 4764 : if (*ptr == '"')
1952 0 : in_quote = !in_quote;
1953 4764 : else if (*ptr == ',' && !in_quote && paren_count == 0)
1954 : break;
1955 4656 : else if (!in_quote)
1956 : {
1957 4656 : switch (*ptr)
1958 : {
1959 0 : case '(':
1960 : case '[':
1961 0 : paren_count++;
1962 0 : break;
1963 0 : case ')':
1964 : case ']':
1965 0 : paren_count--;
1966 0 : break;
1967 : }
1968 4656 : }
1969 : }
1970 576 : if (in_quote || paren_count != 0)
1971 0 : ereturn(escontext, false,
1972 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1973 : errmsg("improper type name")));
1974 :
1975 576 : ptr2 = ptr;
1976 576 : if (*ptr == ',')
1977 : {
1978 108 : had_comma = true;
1979 108 : *ptr++ = '\0';
1980 : }
1981 : else
1982 : {
1983 468 : had_comma = false;
1984 : Assert(*ptr == '\0');
1985 : }
1986 : /* Lop off trailing whitespace */
1987 576 : while (--ptr2 >= typename)
1988 : {
1989 576 : if (!scanner_isspace(*ptr2))
1990 576 : break;
1991 0 : *ptr2 = '\0';
1992 : }
1993 :
1994 576 : if (allowNone && pg_strcasecmp(typename, "none") == 0)
1995 : {
1996 : /* Special case for NONE */
1997 0 : typeid = InvalidOid;
1998 0 : typmod = -1;
1999 : }
2000 : else
2001 : {
2002 : /* Use full parser to resolve the type name */
2003 576 : if (!parseTypeString(typename, &typeid, &typmod, escontext))
2004 0 : return false;
2005 : }
2006 576 : if (*nargs >= FUNC_MAX_ARGS)
2007 0 : ereturn(escontext, false,
2008 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2009 : errmsg("too many arguments")));
2010 :
2011 576 : argtypes[*nargs] = typeid;
2012 576 : (*nargs)++;
2013 : }
2014 :
2015 550 : pfree(rawname);
2016 :
2017 550 : return true;
2018 : }
|