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