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