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-2024, 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 865950 : regprocin(PG_FUNCTION_ARGS)
67 : {
68 865950 : char *pro_name_or_oid = PG_GETARG_CSTRING(0);
69 865950 : Node *escontext = fcinfo->context;
70 : RegProcedure result;
71 : List *names;
72 : FuncCandidateList clist;
73 :
74 : /* Handle "-" or numeric OID */
75 865950 : if (parseDashOrOid(pro_name_or_oid, &result, escontext))
76 865230 : 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 720 : 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 720 : names = stringToQualifiedNameList(pro_name_or_oid, escontext);
92 720 : if (names == NIL)
93 0 : PG_RETURN_NULL();
94 :
95 720 : clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true);
96 :
97 720 : 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 690 : 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 690 : result = clist->oid;
108 :
109 690 : 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 157960 : regprocout(PG_FUNCTION_ARGS)
137 : {
138 157960 : RegProcedure proid = PG_GETARG_OID(0);
139 : char *result;
140 : HeapTuple proctup;
141 :
142 157960 : if (proid == InvalidOid)
143 : {
144 71340 : result = pstrdup("-");
145 71340 : PG_RETURN_CSTRING(result);
146 : }
147 :
148 86620 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
149 :
150 86620 : if (HeapTupleIsValid(proctup))
151 : {
152 86620 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
153 86620 : 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 86620 : 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 86620 : clist = FuncnameGetCandidates(list_make1(makeString(proname)),
172 : -1, NIL, false, false, false, false);
173 86620 : if (clist != NULL && clist->next == NULL &&
174 83546 : clist->oid == proid)
175 83546 : nspname = NULL;
176 : else
177 3074 : nspname = get_namespace_name(procform->pronamespace);
178 :
179 86620 : result = quote_qualified_identifier(nspname, proname);
180 : }
181 :
182 86620 : 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 86620 : 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 494 : regprocedurein(PG_FUNCTION_ARGS)
225 : {
226 494 : char *pro_name_or_oid = PG_GETARG_CSTRING(0);
227 494 : 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 494 : 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 492 : 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 492 : if (!parseNameAndArgTypes(pro_name_or_oid, false,
249 : &names, &nargs, argtypes,
250 : escontext))
251 6 : PG_RETURN_NULL();
252 :
253 486 : clist = FuncnameGetCandidates(names, nargs, NIL, false, false,
254 : false, true);
255 :
256 486 : for (; clist; clist = clist->next)
257 : {
258 456 : if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
259 456 : break;
260 : }
261 :
262 486 : 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 456 : result = clist->oid;
268 :
269 456 : 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 21894 : format_procedure(Oid procedure_oid)
300 : {
301 21894 : 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 25606 : format_procedure_extended(Oid procedure_oid, bits16 flags)
327 : {
328 : char *result;
329 : HeapTuple proctup;
330 :
331 25606 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
332 :
333 25606 : if (HeapTupleIsValid(proctup))
334 : {
335 25588 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
336 25588 : char *proname = NameStr(procform->proname);
337 25588 : 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 25588 : 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 50896 : if ((flags & FORMAT_PROC_FORCE_QUALIFY) == 0 &&
352 25308 : FunctionIsVisible(procedure_oid))
353 24522 : nspname = NULL;
354 : else
355 1066 : nspname = get_namespace_name(procform->pronamespace);
356 :
357 25588 : appendStringInfo(&buf, "%s(",
358 : quote_qualified_identifier(nspname, proname));
359 77760 : for (i = 0; i < nargs; i++)
360 : {
361 52172 : Oid thisargtype = procform->proargtypes.values[i];
362 :
363 52172 : if (i > 0)
364 32532 : appendStringInfoChar(&buf, ',');
365 52172 : appendStringInfoString(&buf,
366 52172 : (flags & FORMAT_PROC_FORCE_QUALIFY) != 0 ?
367 344 : format_type_be_qualified(thisargtype) :
368 51828 : format_type_be(thisargtype));
369 : }
370 25588 : appendStringInfoChar(&buf, ')');
371 :
372 25588 : result = buf.data;
373 :
374 25588 : 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 25606 : 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 126 : 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 126 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
407 :
408 126 : 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 126 : procform = (Form_pg_proc) GETSTRUCT(proctup);
416 126 : nargs = procform->pronargs;
417 :
418 126 : *objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
419 : pstrdup(NameStr(procform->proname)));
420 126 : *objargs = NIL;
421 244 : for (i = 0; i < nargs; i++)
422 : {
423 118 : Oid thisargtype = procform->proargtypes.values[i];
424 :
425 118 : *objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
426 : }
427 :
428 126 : ReleaseSysCache(proctup);
429 : }
430 :
431 : /*
432 : * regprocedureout - converts proc OID to "pro_name(args)"
433 : */
434 : Datum
435 17486 : regprocedureout(PG_FUNCTION_ARGS)
436 : {
437 17486 : RegProcedure proid = PG_GETARG_OID(0);
438 : char *result;
439 :
440 17486 : if (proid == InvalidOid)
441 3884 : result = pstrdup("-");
442 : else
443 13602 : result = format_procedure(proid);
444 :
445 17486 : 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 37768 : regclassin(PG_FUNCTION_ARGS)
883 : {
884 37768 : char *class_name_or_oid = PG_GETARG_CSTRING(0);
885 37768 : Node *escontext = fcinfo->context;
886 : Oid result;
887 : List *names;
888 :
889 : /* Handle "-" or numeric OID */
890 37768 : if (parseDashOrOid(class_name_or_oid, &result, escontext))
891 8452 : 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 29316 : 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 29316 : names = stringToQualifiedNameList(class_name_or_oid, escontext);
904 29316 : if (names == NIL)
905 0 : PG_RETURN_NULL();
906 :
907 : /* We might not even have permissions on this relation; don't lock it. */
908 29316 : result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
909 :
910 29316 : 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 29276 : 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 185292 : regclassout(PG_FUNCTION_ARGS)
944 : {
945 185292 : Oid classid = PG_GETARG_OID(0);
946 : char *result;
947 : HeapTuple classtup;
948 :
949 185292 : if (classid == InvalidOid)
950 : {
951 354 : result = pstrdup("-");
952 354 : PG_RETURN_CSTRING(result);
953 : }
954 :
955 184938 : classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
956 :
957 184938 : if (HeapTupleIsValid(classtup))
958 : {
959 184622 : Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
960 184622 : 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 184622 : 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 184622 : if (RelationIsVisible(classid))
977 118658 : nspname = NULL;
978 : else
979 65964 : nspname = get_namespace_name(classform->relnamespace);
980 :
981 184622 : result = quote_qualified_identifier(nspname, classname);
982 : }
983 :
984 184622 : ReleaseSysCache(classtup);
985 : }
986 : else
987 : {
988 : /* If OID doesn't match any pg_class entry, return it numerically */
989 316 : result = (char *) palloc(NAMEDATALEN);
990 316 : snprintf(result, NAMEDATALEN, "%u", classid);
991 : }
992 :
993 184938 : 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 1094 : regtypein(PG_FUNCTION_ARGS)
1177 : {
1178 1094 : char *typ_name_or_oid = PG_GETARG_CSTRING(0);
1179 1094 : Node *escontext = fcinfo->context;
1180 : Oid result;
1181 : int32 typmod;
1182 :
1183 : /* Handle "-" or numeric OID */
1184 1094 : 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 1074 : 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 1074 : (void) parseTypeString(typ_name_or_oid, &result, &typmod, escontext);
1199 :
1200 1038 : 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 42 : to_regtype(PG_FUNCTION_ARGS)
1210 : {
1211 42 : char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1212 : Datum result;
1213 42 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1214 :
1215 42 : if (!DirectInputFunctionCallSafe(regtypein, typ_name,
1216 : InvalidOid, -1,
1217 : (Node *) &escontext,
1218 : &result))
1219 12 : PG_RETURN_NULL();
1220 30 : PG_RETURN_DATUM(result);
1221 : }
1222 :
1223 : /*
1224 : * to_regtypemod - converts "typename" to type modifier
1225 : *
1226 : * If the name is not found, we return NULL.
1227 : */
1228 : Datum
1229 36 : to_regtypemod(PG_FUNCTION_ARGS)
1230 : {
1231 36 : char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1232 : Oid typid;
1233 : int32 typmod;
1234 36 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1235 :
1236 : /* We rely on parseTypeString to parse the input. */
1237 36 : if (!parseTypeString(typ_name, &typid, &typmod, (Node *) &escontext))
1238 6 : PG_RETURN_NULL();
1239 :
1240 30 : PG_RETURN_INT32(typmod);
1241 : }
1242 :
1243 : /*
1244 : * regtypeout - converts type OID to "typ_name"
1245 : */
1246 : Datum
1247 17274 : regtypeout(PG_FUNCTION_ARGS)
1248 : {
1249 17274 : Oid typid = PG_GETARG_OID(0);
1250 : char *result;
1251 : HeapTuple typetup;
1252 :
1253 17274 : if (typid == InvalidOid)
1254 : {
1255 1584 : result = pstrdup("-");
1256 1584 : PG_RETURN_CSTRING(result);
1257 : }
1258 :
1259 15690 : typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1260 :
1261 15690 : if (HeapTupleIsValid(typetup))
1262 : {
1263 15690 : Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup);
1264 :
1265 : /*
1266 : * In bootstrap mode, skip the fancy namespace stuff and just return
1267 : * the type name. (This path is only needed for debugging output
1268 : * anyway.)
1269 : */
1270 15690 : if (IsBootstrapProcessingMode())
1271 : {
1272 0 : char *typname = NameStr(typeform->typname);
1273 :
1274 0 : result = pstrdup(typname);
1275 : }
1276 : else
1277 15690 : result = format_type_be(typid);
1278 :
1279 15690 : ReleaseSysCache(typetup);
1280 : }
1281 : else
1282 : {
1283 : /* If OID doesn't match any pg_type entry, return it numerically */
1284 0 : result = (char *) palloc(NAMEDATALEN);
1285 0 : snprintf(result, NAMEDATALEN, "%u", typid);
1286 : }
1287 :
1288 15690 : PG_RETURN_CSTRING(result);
1289 : }
1290 :
1291 : /*
1292 : * regtyperecv - converts external binary format to regtype
1293 : */
1294 : Datum
1295 0 : regtyperecv(PG_FUNCTION_ARGS)
1296 : {
1297 : /* Exactly the same as oidrecv, so share code */
1298 0 : return oidrecv(fcinfo);
1299 : }
1300 :
1301 : /*
1302 : * regtypesend - converts regtype to binary format
1303 : */
1304 : Datum
1305 0 : regtypesend(PG_FUNCTION_ARGS)
1306 : {
1307 : /* Exactly the same as oidsend, so share code */
1308 0 : return oidsend(fcinfo);
1309 : }
1310 :
1311 :
1312 : /*
1313 : * regconfigin - converts "tsconfigname" to tsconfig OID
1314 : *
1315 : * We also accept a numeric OID, for symmetry with the output routine.
1316 : *
1317 : * '-' signifies unknown (OID 0). In all other cases, the input must
1318 : * match an existing pg_ts_config entry.
1319 : */
1320 : Datum
1321 1934 : regconfigin(PG_FUNCTION_ARGS)
1322 : {
1323 1934 : char *cfg_name_or_oid = PG_GETARG_CSTRING(0);
1324 1934 : Node *escontext = fcinfo->context;
1325 : Oid result;
1326 : List *names;
1327 :
1328 : /* Handle "-" or numeric OID */
1329 1934 : if (parseDashOrOid(cfg_name_or_oid, &result, escontext))
1330 0 : PG_RETURN_OID(result);
1331 :
1332 : /* The rest of this wouldn't work in bootstrap mode */
1333 1934 : if (IsBootstrapProcessingMode())
1334 0 : elog(ERROR, "regconfig values must be OIDs in bootstrap mode");
1335 :
1336 : /*
1337 : * Normal case: parse the name into components and see if it matches any
1338 : * pg_ts_config entries in the current search path.
1339 : */
1340 1934 : names = stringToQualifiedNameList(cfg_name_or_oid, escontext);
1341 1934 : if (names == NIL)
1342 0 : PG_RETURN_NULL();
1343 :
1344 1934 : result = get_ts_config_oid(names, true);
1345 :
1346 1934 : if (!OidIsValid(result))
1347 6 : ereturn(escontext, (Datum) 0,
1348 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1349 : errmsg("text search configuration \"%s\" does not exist",
1350 : NameListToString(names))));
1351 :
1352 1928 : PG_RETURN_OID(result);
1353 : }
1354 :
1355 : /*
1356 : * regconfigout - converts tsconfig OID to "tsconfigname"
1357 : */
1358 : Datum
1359 10 : regconfigout(PG_FUNCTION_ARGS)
1360 : {
1361 10 : Oid cfgid = PG_GETARG_OID(0);
1362 : char *result;
1363 : HeapTuple cfgtup;
1364 :
1365 10 : if (cfgid == InvalidOid)
1366 : {
1367 0 : result = pstrdup("-");
1368 0 : PG_RETURN_CSTRING(result);
1369 : }
1370 :
1371 10 : cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
1372 :
1373 10 : if (HeapTupleIsValid(cfgtup))
1374 : {
1375 10 : Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
1376 10 : char *cfgname = NameStr(cfgform->cfgname);
1377 : char *nspname;
1378 :
1379 : /*
1380 : * Would this config be found by regconfigin? If not, qualify it.
1381 : */
1382 10 : if (TSConfigIsVisible(cfgid))
1383 6 : nspname = NULL;
1384 : else
1385 4 : nspname = get_namespace_name(cfgform->cfgnamespace);
1386 :
1387 10 : result = quote_qualified_identifier(nspname, cfgname);
1388 :
1389 10 : ReleaseSysCache(cfgtup);
1390 : }
1391 : else
1392 : {
1393 : /* If OID doesn't match any pg_ts_config row, return it numerically */
1394 0 : result = (char *) palloc(NAMEDATALEN);
1395 0 : snprintf(result, NAMEDATALEN, "%u", cfgid);
1396 : }
1397 :
1398 10 : PG_RETURN_CSTRING(result);
1399 : }
1400 :
1401 : /*
1402 : * regconfigrecv - converts external binary format to regconfig
1403 : */
1404 : Datum
1405 0 : regconfigrecv(PG_FUNCTION_ARGS)
1406 : {
1407 : /* Exactly the same as oidrecv, so share code */
1408 0 : return oidrecv(fcinfo);
1409 : }
1410 :
1411 : /*
1412 : * regconfigsend - converts regconfig to binary format
1413 : */
1414 : Datum
1415 0 : regconfigsend(PG_FUNCTION_ARGS)
1416 : {
1417 : /* Exactly the same as oidsend, so share code */
1418 0 : return oidsend(fcinfo);
1419 : }
1420 :
1421 :
1422 : /*
1423 : * regdictionaryin - converts "tsdictionaryname" to tsdictionary OID
1424 : *
1425 : * We also accept a numeric OID, for symmetry with the output routine.
1426 : *
1427 : * '-' signifies unknown (OID 0). In all other cases, the input must
1428 : * match an existing pg_ts_dict entry.
1429 : */
1430 : Datum
1431 636 : regdictionaryin(PG_FUNCTION_ARGS)
1432 : {
1433 636 : char *dict_name_or_oid = PG_GETARG_CSTRING(0);
1434 636 : Node *escontext = fcinfo->context;
1435 : Oid result;
1436 : List *names;
1437 :
1438 : /* Handle "-" or numeric OID */
1439 636 : if (parseDashOrOid(dict_name_or_oid, &result, escontext))
1440 0 : PG_RETURN_OID(result);
1441 :
1442 : /* The rest of this wouldn't work in bootstrap mode */
1443 636 : if (IsBootstrapProcessingMode())
1444 0 : elog(ERROR, "regdictionary values must be OIDs in bootstrap mode");
1445 :
1446 : /*
1447 : * Normal case: parse the name into components and see if it matches any
1448 : * pg_ts_dict entries in the current search path.
1449 : */
1450 636 : names = stringToQualifiedNameList(dict_name_or_oid, escontext);
1451 636 : if (names == NIL)
1452 0 : PG_RETURN_NULL();
1453 :
1454 636 : result = get_ts_dict_oid(names, true);
1455 :
1456 636 : if (!OidIsValid(result))
1457 6 : ereturn(escontext, (Datum) 0,
1458 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1459 : errmsg("text search dictionary \"%s\" does not exist",
1460 : NameListToString(names))));
1461 :
1462 630 : PG_RETURN_OID(result);
1463 : }
1464 :
1465 : /*
1466 : * regdictionaryout - converts tsdictionary OID to "tsdictionaryname"
1467 : */
1468 : Datum
1469 5794 : regdictionaryout(PG_FUNCTION_ARGS)
1470 : {
1471 5794 : Oid dictid = PG_GETARG_OID(0);
1472 : char *result;
1473 : HeapTuple dicttup;
1474 :
1475 5794 : if (dictid == InvalidOid)
1476 : {
1477 0 : result = pstrdup("-");
1478 0 : PG_RETURN_CSTRING(result);
1479 : }
1480 :
1481 5794 : dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
1482 :
1483 5794 : if (HeapTupleIsValid(dicttup))
1484 : {
1485 5794 : Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
1486 5794 : char *dictname = NameStr(dictform->dictname);
1487 : char *nspname;
1488 :
1489 : /*
1490 : * Would this dictionary be found by regdictionaryin? If not, qualify
1491 : * it.
1492 : */
1493 5794 : if (TSDictionaryIsVisible(dictid))
1494 5524 : nspname = NULL;
1495 : else
1496 270 : nspname = get_namespace_name(dictform->dictnamespace);
1497 :
1498 5794 : result = quote_qualified_identifier(nspname, dictname);
1499 :
1500 5794 : ReleaseSysCache(dicttup);
1501 : }
1502 : else
1503 : {
1504 : /* If OID doesn't match any pg_ts_dict row, return it numerically */
1505 0 : result = (char *) palloc(NAMEDATALEN);
1506 0 : snprintf(result, NAMEDATALEN, "%u", dictid);
1507 : }
1508 :
1509 5794 : PG_RETURN_CSTRING(result);
1510 : }
1511 :
1512 : /*
1513 : * regdictionaryrecv - converts external binary format to regdictionary
1514 : */
1515 : Datum
1516 0 : regdictionaryrecv(PG_FUNCTION_ARGS)
1517 : {
1518 : /* Exactly the same as oidrecv, so share code */
1519 0 : return oidrecv(fcinfo);
1520 : }
1521 :
1522 : /*
1523 : * regdictionarysend - converts regdictionary to binary format
1524 : */
1525 : Datum
1526 0 : regdictionarysend(PG_FUNCTION_ARGS)
1527 : {
1528 : /* Exactly the same as oidsend, so share code */
1529 0 : return oidsend(fcinfo);
1530 : }
1531 :
1532 : /*
1533 : * regrolein - converts "rolename" to role OID
1534 : *
1535 : * We also accept a numeric OID, for symmetry with the output routine.
1536 : *
1537 : * '-' signifies unknown (OID 0). In all other cases, the input must
1538 : * match an existing pg_authid entry.
1539 : */
1540 : Datum
1541 212 : regrolein(PG_FUNCTION_ARGS)
1542 : {
1543 212 : char *role_name_or_oid = PG_GETARG_CSTRING(0);
1544 212 : Node *escontext = fcinfo->context;
1545 : Oid result;
1546 : List *names;
1547 :
1548 : /* Handle "-" or numeric OID */
1549 212 : if (parseDashOrOid(role_name_or_oid, &result, escontext))
1550 0 : PG_RETURN_OID(result);
1551 :
1552 : /* The rest of this wouldn't work in bootstrap mode */
1553 212 : if (IsBootstrapProcessingMode())
1554 0 : elog(ERROR, "regrole values must be OIDs in bootstrap mode");
1555 :
1556 : /* Normal case: see if the name matches any pg_authid entry. */
1557 212 : names = stringToQualifiedNameList(role_name_or_oid, escontext);
1558 212 : if (names == NIL)
1559 0 : PG_RETURN_NULL();
1560 :
1561 212 : if (list_length(names) != 1)
1562 18 : ereturn(escontext, (Datum) 0,
1563 : (errcode(ERRCODE_INVALID_NAME),
1564 : errmsg("invalid name syntax")));
1565 :
1566 194 : result = get_role_oid(strVal(linitial(names)), true);
1567 :
1568 194 : if (!OidIsValid(result))
1569 54 : ereturn(escontext, (Datum) 0,
1570 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1571 : errmsg("role \"%s\" does not exist",
1572 : strVal(linitial(names)))));
1573 :
1574 140 : PG_RETURN_OID(result);
1575 : }
1576 :
1577 : /*
1578 : * to_regrole - converts "rolename" to role OID
1579 : *
1580 : * If the name is not found, we return NULL.
1581 : */
1582 : Datum
1583 48 : to_regrole(PG_FUNCTION_ARGS)
1584 : {
1585 48 : char *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1586 : Datum result;
1587 48 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1588 :
1589 48 : if (!DirectInputFunctionCallSafe(regrolein, role_name,
1590 : InvalidOid, -1,
1591 : (Node *) &escontext,
1592 : &result))
1593 36 : PG_RETURN_NULL();
1594 12 : PG_RETURN_DATUM(result);
1595 : }
1596 :
1597 : /*
1598 : * regroleout - converts role OID to "role_name"
1599 : */
1600 : Datum
1601 1544 : regroleout(PG_FUNCTION_ARGS)
1602 : {
1603 1544 : Oid roleoid = PG_GETARG_OID(0);
1604 : char *result;
1605 :
1606 1544 : if (roleoid == InvalidOid)
1607 : {
1608 140 : result = pstrdup("-");
1609 140 : PG_RETURN_CSTRING(result);
1610 : }
1611 :
1612 1404 : result = GetUserNameFromId(roleoid, true);
1613 :
1614 1404 : if (result)
1615 : {
1616 : /* pstrdup is not really necessary, but it avoids a compiler warning */
1617 1404 : result = pstrdup(quote_identifier(result));
1618 : }
1619 : else
1620 : {
1621 : /* If OID doesn't match any role, return it numerically */
1622 0 : result = (char *) palloc(NAMEDATALEN);
1623 0 : snprintf(result, NAMEDATALEN, "%u", roleoid);
1624 : }
1625 :
1626 1404 : PG_RETURN_CSTRING(result);
1627 : }
1628 :
1629 : /*
1630 : * regrolerecv - converts external binary format to regrole
1631 : */
1632 : Datum
1633 0 : regrolerecv(PG_FUNCTION_ARGS)
1634 : {
1635 : /* Exactly the same as oidrecv, so share code */
1636 0 : return oidrecv(fcinfo);
1637 : }
1638 :
1639 : /*
1640 : * regrolesend - converts regrole to binary format
1641 : */
1642 : Datum
1643 0 : regrolesend(PG_FUNCTION_ARGS)
1644 : {
1645 : /* Exactly the same as oidsend, so share code */
1646 0 : return oidsend(fcinfo);
1647 : }
1648 :
1649 : /*
1650 : * regnamespacein - converts "nspname" to namespace OID
1651 : *
1652 : * We also accept a numeric OID, for symmetry with the output routine.
1653 : *
1654 : * '-' signifies unknown (OID 0). In all other cases, the input must
1655 : * match an existing pg_namespace entry.
1656 : */
1657 : Datum
1658 644 : regnamespacein(PG_FUNCTION_ARGS)
1659 : {
1660 644 : char *nsp_name_or_oid = PG_GETARG_CSTRING(0);
1661 644 : Node *escontext = fcinfo->context;
1662 : Oid result;
1663 : List *names;
1664 :
1665 : /* Handle "-" or numeric OID */
1666 644 : if (parseDashOrOid(nsp_name_or_oid, &result, escontext))
1667 0 : PG_RETURN_OID(result);
1668 :
1669 : /* The rest of this wouldn't work in bootstrap mode */
1670 644 : if (IsBootstrapProcessingMode())
1671 0 : elog(ERROR, "regnamespace values must be OIDs in bootstrap mode");
1672 :
1673 : /* Normal case: see if the name matches any pg_namespace entry. */
1674 644 : names = stringToQualifiedNameList(nsp_name_or_oid, escontext);
1675 644 : if (names == NIL)
1676 0 : PG_RETURN_NULL();
1677 :
1678 644 : if (list_length(names) != 1)
1679 12 : ereturn(escontext, (Datum) 0,
1680 : (errcode(ERRCODE_INVALID_NAME),
1681 : errmsg("invalid name syntax")));
1682 :
1683 632 : result = get_namespace_oid(strVal(linitial(names)), true);
1684 :
1685 632 : if (!OidIsValid(result))
1686 30 : ereturn(escontext, (Datum) 0,
1687 : (errcode(ERRCODE_UNDEFINED_SCHEMA),
1688 : errmsg("schema \"%s\" does not exist",
1689 : strVal(linitial(names)))));
1690 :
1691 602 : PG_RETURN_OID(result);
1692 : }
1693 :
1694 : /*
1695 : * to_regnamespace - converts "nspname" to namespace OID
1696 : *
1697 : * If the name is not found, we return NULL.
1698 : */
1699 : Datum
1700 30 : to_regnamespace(PG_FUNCTION_ARGS)
1701 : {
1702 30 : char *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1703 : Datum result;
1704 30 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1705 :
1706 30 : if (!DirectInputFunctionCallSafe(regnamespacein, nsp_name,
1707 : InvalidOid, -1,
1708 : (Node *) &escontext,
1709 : &result))
1710 18 : PG_RETURN_NULL();
1711 12 : PG_RETURN_DATUM(result);
1712 : }
1713 :
1714 : /*
1715 : * regnamespaceout - converts namespace OID to "nsp_name"
1716 : */
1717 : Datum
1718 3340 : regnamespaceout(PG_FUNCTION_ARGS)
1719 : {
1720 3340 : Oid nspid = PG_GETARG_OID(0);
1721 : char *result;
1722 :
1723 3340 : if (nspid == InvalidOid)
1724 : {
1725 0 : result = pstrdup("-");
1726 0 : PG_RETURN_CSTRING(result);
1727 : }
1728 :
1729 3340 : result = get_namespace_name(nspid);
1730 :
1731 3340 : if (result)
1732 : {
1733 : /* pstrdup is not really necessary, but it avoids a compiler warning */
1734 3340 : result = pstrdup(quote_identifier(result));
1735 : }
1736 : else
1737 : {
1738 : /* If OID doesn't match any namespace, return it numerically */
1739 0 : result = (char *) palloc(NAMEDATALEN);
1740 0 : snprintf(result, NAMEDATALEN, "%u", nspid);
1741 : }
1742 :
1743 3340 : PG_RETURN_CSTRING(result);
1744 : }
1745 :
1746 : /*
1747 : * regnamespacerecv - converts external binary format to regnamespace
1748 : */
1749 : Datum
1750 0 : regnamespacerecv(PG_FUNCTION_ARGS)
1751 : {
1752 : /* Exactly the same as oidrecv, so share code */
1753 0 : return oidrecv(fcinfo);
1754 : }
1755 :
1756 : /*
1757 : * regnamespacesend - converts regnamespace to binary format
1758 : */
1759 : Datum
1760 0 : regnamespacesend(PG_FUNCTION_ARGS)
1761 : {
1762 : /* Exactly the same as oidsend, so share code */
1763 0 : return oidsend(fcinfo);
1764 : }
1765 :
1766 : /*
1767 : * text_regclass: convert text to regclass
1768 : *
1769 : * This could be replaced by CoerceViaIO, except that we need to treat
1770 : * text-to-regclass as an implicit cast to support legacy forms of nextval()
1771 : * and related functions.
1772 : */
1773 : Datum
1774 3082 : text_regclass(PG_FUNCTION_ARGS)
1775 : {
1776 3082 : text *relname = PG_GETARG_TEXT_PP(0);
1777 : Oid result;
1778 : RangeVar *rv;
1779 :
1780 3082 : rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
1781 :
1782 : /* We might not even have permissions on this relation; don't lock it. */
1783 3082 : result = RangeVarGetRelid(rv, NoLock, false);
1784 :
1785 3076 : PG_RETURN_OID(result);
1786 : }
1787 :
1788 :
1789 : /*
1790 : * Given a C string, parse it into a qualified-name list.
1791 : *
1792 : * If escontext is an ErrorSaveContext node, invalid input will be
1793 : * reported there instead of being thrown, and we return NIL.
1794 : * (NIL is not possible as a success return, since empty-input is an error.)
1795 : */
1796 : List *
1797 39680 : stringToQualifiedNameList(const char *string, Node *escontext)
1798 : {
1799 : char *rawname;
1800 39680 : List *result = NIL;
1801 : List *namelist;
1802 : ListCell *l;
1803 :
1804 : /* We need a modifiable copy of the input string. */
1805 39680 : rawname = pstrdup(string);
1806 :
1807 39680 : if (!SplitIdentifierString(rawname, '.', &namelist))
1808 0 : ereturn(escontext, NIL,
1809 : (errcode(ERRCODE_INVALID_NAME),
1810 : errmsg("invalid name syntax")));
1811 :
1812 39680 : if (namelist == NIL)
1813 0 : ereturn(escontext, NIL,
1814 : (errcode(ERRCODE_INVALID_NAME),
1815 : errmsg("invalid name syntax")));
1816 :
1817 102160 : foreach(l, namelist)
1818 : {
1819 62480 : char *curname = (char *) lfirst(l);
1820 :
1821 62480 : result = lappend(result, makeString(pstrdup(curname)));
1822 : }
1823 :
1824 39680 : pfree(rawname);
1825 39680 : list_free(namelist);
1826 :
1827 39680 : return result;
1828 : }
1829 :
1830 : /*****************************************************************************
1831 : * SUPPORT ROUTINES *
1832 : *****************************************************************************/
1833 :
1834 : /*
1835 : * Given a C string, see if it is all-digits (and not empty).
1836 : * If so, convert directly to OID and return true.
1837 : * If it is not all-digits, return false.
1838 : *
1839 : * If escontext is an ErrorSaveContext node, any error in oidin() will be
1840 : * reported there instead of being thrown (but we still return true).
1841 : */
1842 : static bool
1843 736754 : parseNumericOid(char *string, Oid *result, Node *escontext)
1844 : {
1845 736754 : if (string[0] >= '0' && string[0] <= '9' &&
1846 701534 : strspn(string, "0123456789") == strlen(string))
1847 : {
1848 : Datum oid_datum;
1849 :
1850 : /* We need not care here whether oidin() fails or not. */
1851 701534 : (void) DirectInputFunctionCallSafe(oidin, string,
1852 : InvalidOid, -1,
1853 : escontext,
1854 : &oid_datum);
1855 701534 : *result = DatumGetObjectId(oid_datum);
1856 701534 : return true;
1857 : }
1858 :
1859 : /* Prevent uninitialized-variable warnings from stupider compilers. */
1860 35220 : *result = InvalidOid;
1861 35220 : return false;
1862 : }
1863 :
1864 : /*
1865 : * As above, but also accept "-" as meaning 0 (InvalidOid).
1866 : */
1867 : static bool
1868 908780 : parseDashOrOid(char *string, Oid *result, Node *escontext)
1869 : {
1870 : /* '-' ? */
1871 908780 : if (strcmp(string, "-") == 0)
1872 : {
1873 172170 : *result = InvalidOid;
1874 172170 : return true;
1875 : }
1876 :
1877 : /* Numeric OID? */
1878 736610 : return parseNumericOid(string, result, escontext);
1879 : }
1880 :
1881 : /*
1882 : * Given a C string, parse it into a qualified function or operator name
1883 : * followed by a parenthesized list of type names. Reduce the
1884 : * type names to an array of OIDs (returned into *nargs and *argtypes;
1885 : * the argtypes array should be of size FUNC_MAX_ARGS). The function or
1886 : * operator name is returned to *names as a List of Strings.
1887 : *
1888 : * If allowNone is true, accept "NONE" and return it as InvalidOid (this is
1889 : * for unary operators).
1890 : *
1891 : * Returns true on success, false on failure (the latter only possible
1892 : * if escontext is an ErrorSaveContext node).
1893 : */
1894 : static bool
1895 576 : parseNameAndArgTypes(const char *string, bool allowNone, List **names,
1896 : int *nargs, Oid *argtypes,
1897 : Node *escontext)
1898 : {
1899 : char *rawname;
1900 : char *ptr;
1901 : char *ptr2;
1902 : char *typename;
1903 : bool in_quote;
1904 : bool had_comma;
1905 : int paren_count;
1906 : Oid typeid;
1907 : int32 typmod;
1908 :
1909 : /* We need a modifiable copy of the input string. */
1910 576 : rawname = pstrdup(string);
1911 :
1912 : /* Scan to find the expected left paren; mustn't be quoted */
1913 576 : in_quote = false;
1914 10048 : for (ptr = rawname; *ptr; ptr++)
1915 : {
1916 10042 : if (*ptr == '"')
1917 0 : in_quote = !in_quote;
1918 10042 : else if (*ptr == '(' && !in_quote)
1919 570 : break;
1920 : }
1921 576 : if (*ptr == '\0')
1922 6 : ereturn(escontext, false,
1923 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1924 : errmsg("expected a left parenthesis")));
1925 :
1926 : /* Separate the name and parse it into a list */
1927 570 : *ptr++ = '\0';
1928 570 : *names = stringToQualifiedNameList(rawname, escontext);
1929 570 : if (*names == NIL)
1930 0 : return false;
1931 :
1932 : /* Check for the trailing right parenthesis and remove it */
1933 570 : ptr2 = ptr + strlen(ptr);
1934 588 : while (--ptr2 > ptr)
1935 : {
1936 494 : if (!scanner_isspace(*ptr2))
1937 476 : break;
1938 : }
1939 570 : if (*ptr2 != ')')
1940 6 : ereturn(escontext, false,
1941 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1942 : errmsg("expected a right parenthesis")));
1943 :
1944 564 : *ptr2 = '\0';
1945 :
1946 : /* Separate the remaining string into comma-separated type names */
1947 564 : *nargs = 0;
1948 564 : had_comma = false;
1949 :
1950 : for (;;)
1951 : {
1952 : /* allow leading whitespace */
1953 1172 : while (scanner_isspace(*ptr))
1954 30 : ptr++;
1955 1142 : if (*ptr == '\0')
1956 : {
1957 : /* End of string. Okay unless we had a comma before. */
1958 564 : if (had_comma)
1959 0 : ereturn(escontext, false,
1960 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1961 : errmsg("expected a type name")));
1962 564 : break;
1963 : }
1964 578 : typename = ptr;
1965 : /* Find end of type name --- end of string or comma */
1966 : /* ... but not a quoted or parenthesized comma */
1967 578 : in_quote = false;
1968 578 : paren_count = 0;
1969 5240 : for (; *ptr; ptr++)
1970 : {
1971 4770 : if (*ptr == '"')
1972 0 : in_quote = !in_quote;
1973 4770 : else if (*ptr == ',' && !in_quote && paren_count == 0)
1974 : break;
1975 4662 : else if (!in_quote)
1976 : {
1977 4662 : switch (*ptr)
1978 : {
1979 0 : case '(':
1980 : case '[':
1981 0 : paren_count++;
1982 0 : break;
1983 0 : case ')':
1984 : case ']':
1985 0 : paren_count--;
1986 0 : break;
1987 : }
1988 4662 : }
1989 : }
1990 578 : if (in_quote || paren_count != 0)
1991 0 : ereturn(escontext, false,
1992 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1993 : errmsg("improper type name")));
1994 :
1995 578 : ptr2 = ptr;
1996 578 : if (*ptr == ',')
1997 : {
1998 108 : had_comma = true;
1999 108 : *ptr++ = '\0';
2000 : }
2001 : else
2002 : {
2003 470 : had_comma = false;
2004 : Assert(*ptr == '\0');
2005 : }
2006 : /* Lop off trailing whitespace */
2007 578 : while (--ptr2 >= typename)
2008 : {
2009 578 : if (!scanner_isspace(*ptr2))
2010 578 : break;
2011 0 : *ptr2 = '\0';
2012 : }
2013 :
2014 578 : if (allowNone && pg_strcasecmp(typename, "none") == 0)
2015 : {
2016 : /* Special case for NONE */
2017 0 : typeid = InvalidOid;
2018 0 : typmod = -1;
2019 : }
2020 : else
2021 : {
2022 : /* Use full parser to resolve the type name */
2023 578 : if (!parseTypeString(typename, &typeid, &typmod, escontext))
2024 0 : return false;
2025 : }
2026 578 : if (*nargs >= FUNC_MAX_ARGS)
2027 0 : ereturn(escontext, false,
2028 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2029 : errmsg("too many arguments")));
2030 :
2031 578 : argtypes[*nargs] = typeid;
2032 578 : (*nargs)++;
2033 : }
2034 :
2035 564 : pfree(rawname);
2036 :
2037 564 : return true;
2038 : }
|