Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * regproc.c
4 : * Functions for the built-in types regproc, regclass, regtype, etc.
5 : *
6 : * These types are all binary-compatible with type Oid, and rely on Oid
7 : * for comparison and so forth. Their only interesting behavior is in
8 : * special I/O conversion routines.
9 : *
10 : *
11 : * Portions Copyright (c) 1996-2017, 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 :
43 : static char *format_operator_internal(Oid operator_oid, bool force_qualify);
44 : static char *format_procedure_internal(Oid procedure_oid, bool force_qualify);
45 : static 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 : */
61 : Datum
62 8106 : regprocin(PG_FUNCTION_ARGS)
63 : {
64 8106 : char *pro_name_or_oid = PG_GETARG_CSTRING(0);
65 8106 : RegProcedure result = InvalidOid;
66 : List *names;
67 : FuncCandidateList clist;
68 :
69 : /* '-' ? */
70 8106 : if (strcmp(pro_name_or_oid, "-") == 0)
71 1657 : PG_RETURN_OID(InvalidOid);
72 :
73 : /* Numeric OID? */
74 12898 : if (pro_name_or_oid[0] >= '0' &&
75 12856 : pro_name_or_oid[0] <= '9' &&
76 6407 : strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
77 : {
78 6407 : result = DatumGetObjectId(DirectFunctionCall1(oidin,
79 : CStringGetDatum(pro_name_or_oid)));
80 6407 : 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 42 : if (IsBootstrapProcessingMode())
90 0 : 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 42 : names = stringToQualifiedNameList(pro_name_or_oid);
97 42 : clist = FuncnameGetCandidates(names, -1, NIL, false, false, false);
98 :
99 41 : if (clist == NULL)
100 1 : ereport(ERROR,
101 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
102 : errmsg("function \"%s\" does not exist", pro_name_or_oid)));
103 40 : else if (clist->next != NULL)
104 0 : ereport(ERROR,
105 : (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
106 : errmsg("more than one function named \"%s\"",
107 : pro_name_or_oid)));
108 :
109 40 : result = clist->oid;
110 :
111 40 : 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 : */
119 : Datum
120 4 : to_regproc(PG_FUNCTION_ARGS)
121 : {
122 4 : 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 4 : names = stringToQualifiedNameList(pro_name);
131 4 : clist = FuncnameGetCandidates(names, -1, NIL, false, false, true);
132 :
133 4 : if (clist == NULL || clist->next != NULL)
134 2 : PG_RETURN_NULL();
135 :
136 2 : PG_RETURN_OID(clist->oid);
137 : }
138 :
139 : /*
140 : * regprocout - converts proc OID to "pro_name"
141 : */
142 : Datum
143 150 : regprocout(PG_FUNCTION_ARGS)
144 : {
145 150 : RegProcedure proid = PG_GETARG_OID(0);
146 : char *result;
147 : HeapTuple proctup;
148 :
149 150 : if (proid == InvalidOid)
150 : {
151 79 : result = pstrdup("-");
152 79 : PG_RETURN_CSTRING(result);
153 : }
154 :
155 71 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
156 :
157 71 : if (HeapTupleIsValid(proctup))
158 : {
159 71 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
160 71 : 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 71 : if (IsBootstrapProcessingMode())
168 0 : 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 71 : clist = FuncnameGetCandidates(list_make1(makeString(proname)),
179 : -1, NIL, false, false, false);
180 142 : if (clist != NULL && clist->next == NULL &&
181 71 : clist->oid == proid)
182 71 : nspname = NULL;
183 : else
184 0 : nspname = get_namespace_name(procform->pronamespace);
185 :
186 71 : result = quote_qualified_identifier(nspname, proname);
187 : }
188 :
189 71 : ReleaseSysCache(proctup);
190 : }
191 : else
192 : {
193 : /* If OID doesn't match any pg_proc entry, return it numerically */
194 0 : result = (char *) palloc(NAMEDATALEN);
195 0 : snprintf(result, NAMEDATALEN, "%u", proid);
196 : }
197 :
198 71 : PG_RETURN_CSTRING(result);
199 : }
200 :
201 : /*
202 : * regprocrecv - converts external binary format to regproc
203 : */
204 : Datum
205 0 : regprocrecv(PG_FUNCTION_ARGS)
206 : {
207 : /* Exactly the same as oidrecv, so share code */
208 0 : return oidrecv(fcinfo);
209 : }
210 :
211 : /*
212 : * regprocsend - converts regproc to binary format
213 : */
214 : Datum
215 0 : regprocsend(PG_FUNCTION_ARGS)
216 : {
217 : /* Exactly the same as oidsend, so share code */
218 0 : 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 : */
230 : Datum
231 10 : regprocedurein(PG_FUNCTION_ARGS)
232 : {
233 10 : char *pro_name_or_oid = PG_GETARG_CSTRING(0);
234 10 : RegProcedure result = InvalidOid;
235 : List *names;
236 : int nargs;
237 : Oid argtypes[FUNC_MAX_ARGS];
238 : FuncCandidateList clist;
239 :
240 : /* '-' ? */
241 10 : if (strcmp(pro_name_or_oid, "-") == 0)
242 0 : PG_RETURN_OID(InvalidOid);
243 :
244 : /* Numeric OID? */
245 20 : if (pro_name_or_oid[0] >= '0' &&
246 10 : pro_name_or_oid[0] <= '9' &&
247 0 : strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
248 : {
249 0 : result = DatumGetObjectId(DirectFunctionCall1(oidin,
250 : CStringGetDatum(pro_name_or_oid)));
251 0 : PG_RETURN_OID(result);
252 : }
253 :
254 : /* The rest of this wouldn't work in bootstrap mode */
255 10 : if (IsBootstrapProcessingMode())
256 0 : 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 10 : parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
265 :
266 10 : clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false);
267 :
268 9 : for (; clist; clist = clist->next)
269 : {
270 8 : if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
271 8 : break;
272 : }
273 :
274 9 : if (clist == NULL)
275 1 : ereport(ERROR,
276 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
277 : errmsg("function \"%s\" does not exist", pro_name_or_oid)));
278 :
279 8 : result = clist->oid;
280 :
281 8 : 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
290 4 : to_regprocedure(PG_FUNCTION_ARGS)
291 : {
292 4 : 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 4 : parseNameAndArgTypes(pro_name, false, &names, &nargs, argtypes);
304 :
305 4 : clist = FuncnameGetCandidates(names, nargs, NIL, false, false, true);
306 :
307 4 : for (; clist; clist = clist->next)
308 : {
309 2 : if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
310 2 : PG_RETURN_OID(clist->oid);
311 : }
312 :
313 2 : 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 *
323 864 : format_procedure(Oid procedure_oid)
324 : {
325 864 : return format_procedure_internal(procedure_oid, false);
326 : }
327 :
328 : char *
329 20 : format_procedure_qualified(Oid procedure_oid)
330 : {
331 20 : 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 : */
341 : static char *
342 884 : format_procedure_internal(Oid procedure_oid, bool force_qualify)
343 : {
344 : char *result;
345 : HeapTuple proctup;
346 :
347 884 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
348 :
349 884 : if (HeapTupleIsValid(proctup))
350 : {
351 884 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
352 884 : char *proname = NameStr(procform->proname);
353 884 : int nargs = procform->pronargs;
354 : int i;
355 : char *nspname;
356 : StringInfoData buf;
357 :
358 : /* XXX no support here for bootstrap mode */
359 884 : Assert(!IsBootstrapProcessingMode());
360 :
361 884 : 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 884 : if (!force_qualify && FunctionIsVisible(procedure_oid))
368 852 : nspname = NULL;
369 : else
370 32 : nspname = get_namespace_name(procform->pronamespace);
371 :
372 884 : appendStringInfo(&buf, "%s(",
373 : quote_qualified_identifier(nspname, proname));
374 1740 : for (i = 0; i < nargs; i++)
375 : {
376 856 : Oid thisargtype = procform->proargtypes.values[i];
377 :
378 856 : if (i > 0)
379 353 : appendStringInfoChar(&buf, ',');
380 856 : appendStringInfoString(&buf,
381 : force_qualify ?
382 : format_type_be_qualified(thisargtype) :
383 : format_type_be(thisargtype));
384 : }
385 884 : appendStringInfoChar(&buf, ')');
386 :
387 884 : result = buf.data;
388 :
389 884 : ReleaseSysCache(proctup);
390 : }
391 : else
392 : {
393 : /* If OID doesn't match any pg_proc entry, return it numerically */
394 0 : result = (char *) palloc(NAMEDATALEN);
395 0 : snprintf(result, NAMEDATALEN, "%u", procedure_oid);
396 : }
397 :
398 884 : 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 : */
407 : void
408 8 : format_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 8 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
416 :
417 8 : if (!HeapTupleIsValid(proctup))
418 0 : elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
419 :
420 8 : procform = (Form_pg_proc) GETSTRUCT(proctup);
421 8 : nargs = procform->pronargs;
422 :
423 8 : *objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
424 : pstrdup(NameStr(procform->proname)));
425 8 : *objargs = NIL;
426 21 : for (i = 0; i < nargs; i++)
427 : {
428 13 : Oid thisargtype = procform->proargtypes.values[i];
429 :
430 13 : *objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
431 : }
432 :
433 8 : ReleaseSysCache(proctup);
434 8 : }
435 :
436 : /*
437 : * regprocedureout - converts proc OID to "pro_name(args)"
438 : */
439 : Datum
440 243 : regprocedureout(PG_FUNCTION_ARGS)
441 : {
442 243 : RegProcedure proid = PG_GETARG_OID(0);
443 : char *result;
444 :
445 243 : if (proid == InvalidOid)
446 0 : result = pstrdup("-");
447 : else
448 243 : result = format_procedure(proid);
449 :
450 243 : PG_RETURN_CSTRING(result);
451 : }
452 :
453 : /*
454 : * regprocedurerecv - converts external binary format to regprocedure
455 : */
456 : Datum
457 0 : regprocedurerecv(PG_FUNCTION_ARGS)
458 : {
459 : /* Exactly the same as oidrecv, so share code */
460 0 : return oidrecv(fcinfo);
461 : }
462 :
463 : /*
464 : * regproceduresend - converts regprocedure to binary format
465 : */
466 : Datum
467 0 : regproceduresend(PG_FUNCTION_ARGS)
468 : {
469 : /* Exactly the same as oidsend, so share code */
470 0 : 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 : */
482 : Datum
483 4 : regoperin(PG_FUNCTION_ARGS)
484 : {
485 4 : char *opr_name_or_oid = PG_GETARG_CSTRING(0);
486 4 : Oid result = InvalidOid;
487 : List *names;
488 : FuncCandidateList clist;
489 :
490 : /* '0' ? */
491 4 : if (strcmp(opr_name_or_oid, "0") == 0)
492 0 : PG_RETURN_OID(InvalidOid);
493 :
494 : /* Numeric OID? */
495 8 : if (opr_name_or_oid[0] >= '0' &&
496 4 : opr_name_or_oid[0] <= '9' &&
497 0 : strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
498 : {
499 0 : result = DatumGetObjectId(DirectFunctionCall1(oidin,
500 : CStringGetDatum(opr_name_or_oid)));
501 0 : 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 4 : if (IsBootstrapProcessingMode())
508 0 : 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 4 : names = stringToQualifiedNameList(opr_name_or_oid);
515 4 : clist = OpernameGetCandidates(names, '\0', false);
516 :
517 3 : if (clist == NULL)
518 1 : ereport(ERROR,
519 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
520 : errmsg("operator does not exist: %s", opr_name_or_oid)));
521 2 : else if (clist->next != NULL)
522 0 : ereport(ERROR,
523 : (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
524 : errmsg("more than one operator named %s",
525 : opr_name_or_oid)));
526 :
527 2 : result = clist->oid;
528 :
529 2 : 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 : */
537 : Datum
538 4 : to_regoper(PG_FUNCTION_ARGS)
539 : {
540 4 : 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 4 : names = stringToQualifiedNameList(opr_name);
549 4 : clist = OpernameGetCandidates(names, '\0', true);
550 :
551 4 : if (clist == NULL || clist->next != NULL)
552 2 : PG_RETURN_NULL();
553 :
554 2 : PG_RETURN_OID(clist->oid);
555 : }
556 :
557 : /*
558 : * regoperout - converts operator OID to "opr_name"
559 : */
560 : Datum
561 4 : regoperout(PG_FUNCTION_ARGS)
562 : {
563 4 : Oid oprid = PG_GETARG_OID(0);
564 : char *result;
565 : HeapTuple opertup;
566 :
567 4 : if (oprid == InvalidOid)
568 : {
569 0 : result = pstrdup("0");
570 0 : PG_RETURN_CSTRING(result);
571 : }
572 :
573 4 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
574 :
575 4 : if (HeapTupleIsValid(opertup))
576 : {
577 4 : Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
578 4 : 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 4 : if (IsBootstrapProcessingMode())
586 0 : 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 4 : clist = OpernameGetCandidates(list_make1(makeString(oprname)),
596 : '\0', false);
597 8 : if (clist != NULL && clist->next == NULL &&
598 4 : clist->oid == oprid)
599 4 : result = pstrdup(oprname);
600 : else
601 : {
602 : const char *nspname;
603 :
604 0 : nspname = get_namespace_name(operform->oprnamespace);
605 0 : nspname = quote_identifier(nspname);
606 0 : result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2);
607 0 : sprintf(result, "%s.%s", nspname, oprname);
608 : }
609 : }
610 :
611 4 : ReleaseSysCache(opertup);
612 : }
613 : else
614 : {
615 : /*
616 : * If OID doesn't match any pg_operator entry, return it numerically
617 : */
618 0 : result = (char *) palloc(NAMEDATALEN);
619 0 : snprintf(result, NAMEDATALEN, "%u", oprid);
620 : }
621 :
622 4 : PG_RETURN_CSTRING(result);
623 : }
624 :
625 : /*
626 : * regoperrecv - converts external binary format to regoper
627 : */
628 : Datum
629 0 : regoperrecv(PG_FUNCTION_ARGS)
630 : {
631 : /* Exactly the same as oidrecv, so share code */
632 0 : return oidrecv(fcinfo);
633 : }
634 :
635 : /*
636 : * regopersend - converts regoper to binary format
637 : */
638 : Datum
639 0 : regopersend(PG_FUNCTION_ARGS)
640 : {
641 : /* Exactly the same as oidsend, so share code */
642 0 : 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 : */
654 : Datum
655 9 : regoperatorin(PG_FUNCTION_ARGS)
656 : {
657 9 : 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 9 : if (strcmp(opr_name_or_oid, "0") == 0)
665 0 : PG_RETURN_OID(InvalidOid);
666 :
667 : /* Numeric OID? */
668 16 : if (opr_name_or_oid[0] >= '0' &&
669 7 : opr_name_or_oid[0] <= '9' &&
670 0 : strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
671 : {
672 0 : result = DatumGetObjectId(DirectFunctionCall1(oidin,
673 : CStringGetDatum(opr_name_or_oid)));
674 0 : PG_RETURN_OID(result);
675 : }
676 :
677 : /* The rest of this wouldn't work in bootstrap mode */
678 9 : if (IsBootstrapProcessingMode())
679 0 : 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 9 : parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes);
688 9 : if (nargs == 1)
689 0 : 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 9 : if (nargs != 2)
694 0 : ereport(ERROR,
695 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
696 : errmsg("too many arguments"),
697 : errhint("Provide two argument types for operator.")));
698 :
699 9 : result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
700 :
701 9 : if (!OidIsValid(result))
702 2 : ereport(ERROR,
703 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
704 : errmsg("operator does not exist: %s", opr_name_or_oid)));
705 :
706 7 : 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 : */
714 : Datum
715 3 : to_regoperator(PG_FUNCTION_ARGS)
716 : {
717 3 : 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 3 : parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes);
729 3 : if (nargs == 1)
730 0 : 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 3 : if (nargs != 2)
735 0 : ereport(ERROR,
736 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
737 : errmsg("too many arguments"),
738 : errhint("Provide two argument types for operator.")));
739 :
740 3 : result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
741 :
742 3 : if (!OidIsValid(result))
743 2 : PG_RETURN_NULL();
744 :
745 1 : 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 : */
754 : static char *
755 58 : format_operator_internal(Oid operator_oid, bool force_qualify)
756 : {
757 : char *result;
758 : HeapTuple opertup;
759 :
760 58 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
761 :
762 58 : if (HeapTupleIsValid(opertup))
763 : {
764 58 : Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
765 58 : char *oprname = NameStr(operform->oprname);
766 : char *nspname;
767 : StringInfoData buf;
768 :
769 : /* XXX no support here for bootstrap mode */
770 58 : Assert(!IsBootstrapProcessingMode());
771 :
772 58 : 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 58 : if (force_qualify || !OperatorIsVisible(operator_oid))
779 : {
780 10 : nspname = get_namespace_name(operform->oprnamespace);
781 10 : appendStringInfo(&buf, "%s.",
782 : quote_identifier(nspname));
783 : }
784 :
785 58 : appendStringInfo(&buf, "%s(", oprname);
786 :
787 58 : if (operform->oprleft)
788 116 : appendStringInfo(&buf, "%s,",
789 : force_qualify ?
790 7 : format_type_be_qualified(operform->oprleft) :
791 51 : format_type_be(operform->oprleft));
792 : else
793 0 : appendStringInfoString(&buf, "NONE,");
794 :
795 58 : if (operform->oprright)
796 116 : appendStringInfo(&buf, "%s)",
797 : force_qualify ?
798 7 : format_type_be_qualified(operform->oprright) :
799 51 : format_type_be(operform->oprright));
800 : else
801 0 : appendStringInfoString(&buf, "NONE)");
802 :
803 58 : result = buf.data;
804 :
805 58 : ReleaseSysCache(opertup);
806 : }
807 : else
808 : {
809 : /*
810 : * If OID doesn't match any pg_operator entry, return it numerically
811 : */
812 0 : result = (char *) palloc(NAMEDATALEN);
813 0 : snprintf(result, NAMEDATALEN, "%u", operator_oid);
814 : }
815 :
816 58 : return result;
817 : }
818 :
819 : char *
820 51 : format_operator(Oid operator_oid)
821 : {
822 51 : return format_operator_internal(operator_oid, false);
823 : }
824 :
825 : char *
826 7 : format_operator_qualified(Oid operator_oid)
827 : {
828 7 : return format_operator_internal(operator_oid, true);
829 : }
830 :
831 : void
832 1 : format_operator_parts(Oid operator_oid, List **objnames, List **objargs)
833 : {
834 : HeapTuple opertup;
835 : Form_pg_operator oprForm;
836 :
837 1 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
838 1 : if (!HeapTupleIsValid(opertup))
839 0 : elog(ERROR, "cache lookup failed for operator with OID %u",
840 : operator_oid);
841 :
842 1 : oprForm = (Form_pg_operator) GETSTRUCT(opertup);
843 1 : *objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
844 : pstrdup(NameStr(oprForm->oprname)));
845 1 : *objargs = NIL;
846 1 : if (oprForm->oprleft)
847 1 : *objargs = lappend(*objargs,
848 1 : format_type_be_qualified(oprForm->oprleft));
849 1 : if (oprForm->oprright)
850 1 : *objargs = lappend(*objargs,
851 1 : format_type_be_qualified(oprForm->oprright));
852 :
853 1 : ReleaseSysCache(opertup);
854 1 : }
855 :
856 : /*
857 : * regoperatorout - converts operator OID to "opr_name(args)"
858 : */
859 : Datum
860 3 : regoperatorout(PG_FUNCTION_ARGS)
861 : {
862 3 : Oid oprid = PG_GETARG_OID(0);
863 : char *result;
864 :
865 3 : if (oprid == InvalidOid)
866 0 : result = pstrdup("0");
867 : else
868 3 : result = format_operator(oprid);
869 :
870 3 : PG_RETURN_CSTRING(result);
871 : }
872 :
873 : /*
874 : * regoperatorrecv - converts external binary format to regoperator
875 : */
876 : Datum
877 0 : regoperatorrecv(PG_FUNCTION_ARGS)
878 : {
879 : /* Exactly the same as oidrecv, so share code */
880 0 : return oidrecv(fcinfo);
881 : }
882 :
883 : /*
884 : * regoperatorsend - converts regoperator to binary format
885 : */
886 : Datum
887 0 : regoperatorsend(PG_FUNCTION_ARGS)
888 : {
889 : /* Exactly the same as oidsend, so share code */
890 0 : 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 : */
902 : Datum
903 870 : regclassin(PG_FUNCTION_ARGS)
904 : {
905 870 : char *class_name_or_oid = PG_GETARG_CSTRING(0);
906 870 : Oid result = InvalidOid;
907 : List *names;
908 :
909 : /* '-' ? */
910 870 : if (strcmp(class_name_or_oid, "-") == 0)
911 0 : PG_RETURN_OID(InvalidOid);
912 :
913 : /* Numeric OID? */
914 1740 : if (class_name_or_oid[0] >= '0' &&
915 1039 : class_name_or_oid[0] <= '9' &&
916 169 : strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
917 : {
918 169 : result = DatumGetObjectId(DirectFunctionCall1(oidin,
919 : CStringGetDatum(class_name_or_oid)));
920 169 : 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 701 : if (IsBootstrapProcessingMode())
927 0 : 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 701 : names = stringToQualifiedNameList(class_name_or_oid);
934 :
935 : /* We might not even have permissions on this relation; don't lock it. */
936 701 : result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false);
937 :
938 698 : 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 : */
946 : Datum
947 4 : to_regclass(PG_FUNCTION_ARGS)
948 : {
949 4 : 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 4 : names = stringToQualifiedNameList(class_name);
958 :
959 : /* We might not even have permissions on this relation; don't lock it. */
960 4 : result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
961 :
962 4 : if (OidIsValid(result))
963 2 : PG_RETURN_OID(result);
964 : else
965 2 : PG_RETURN_NULL();
966 : }
967 :
968 : /*
969 : * regclassout - converts class OID to "class_name"
970 : */
971 : Datum
972 490 : regclassout(PG_FUNCTION_ARGS)
973 : {
974 490 : Oid classid = PG_GETARG_OID(0);
975 : char *result;
976 : HeapTuple classtup;
977 :
978 490 : if (classid == InvalidOid)
979 : {
980 0 : result = pstrdup("-");
981 0 : PG_RETURN_CSTRING(result);
982 : }
983 :
984 490 : classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
985 :
986 490 : if (HeapTupleIsValid(classtup))
987 : {
988 490 : Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
989 490 : 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 490 : if (IsBootstrapProcessingMode())
997 0 : 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 490 : if (RelationIsVisible(classid))
1006 482 : nspname = NULL;
1007 : else
1008 8 : nspname = get_namespace_name(classform->relnamespace);
1009 :
1010 490 : result = quote_qualified_identifier(nspname, classname);
1011 : }
1012 :
1013 490 : ReleaseSysCache(classtup);
1014 : }
1015 : else
1016 : {
1017 : /* If OID doesn't match any pg_class entry, return it numerically */
1018 0 : result = (char *) palloc(NAMEDATALEN);
1019 0 : snprintf(result, NAMEDATALEN, "%u", classid);
1020 : }
1021 :
1022 490 : PG_RETURN_CSTRING(result);
1023 : }
1024 :
1025 : /*
1026 : * regclassrecv - converts external binary format to regclass
1027 : */
1028 : Datum
1029 0 : regclassrecv(PG_FUNCTION_ARGS)
1030 : {
1031 : /* Exactly the same as oidrecv, so share code */
1032 0 : return oidrecv(fcinfo);
1033 : }
1034 :
1035 : /*
1036 : * regclasssend - converts regclass to binary format
1037 : */
1038 : Datum
1039 0 : regclasssend(PG_FUNCTION_ARGS)
1040 : {
1041 : /* Exactly the same as oidsend, so share code */
1042 0 : 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 : */
1060 : Datum
1061 108 : regtypein(PG_FUNCTION_ARGS)
1062 : {
1063 108 : char *typ_name_or_oid = PG_GETARG_CSTRING(0);
1064 108 : Oid result = InvalidOid;
1065 : int32 typmod;
1066 :
1067 : /* '-' ? */
1068 108 : if (strcmp(typ_name_or_oid, "-") == 0)
1069 0 : PG_RETURN_OID(InvalidOid);
1070 :
1071 : /* Numeric OID? */
1072 216 : if (typ_name_or_oid[0] >= '0' &&
1073 108 : typ_name_or_oid[0] <= '9' &&
1074 0 : strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
1075 : {
1076 0 : result = DatumGetObjectId(DirectFunctionCall1(oidin,
1077 : CStringGetDatum(typ_name_or_oid)));
1078 0 : 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 108 : if (IsBootstrapProcessingMode())
1085 0 : 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 108 : parseTypeString(typ_name_or_oid, &result, &typmod, false);
1092 :
1093 106 : 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 : */
1101 : Datum
1102 4 : to_regtype(PG_FUNCTION_ARGS)
1103 : {
1104 4 : 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 4 : parseTypeString(typ_name, &result, &typmod, true);
1112 :
1113 4 : if (OidIsValid(result))
1114 2 : PG_RETURN_OID(result);
1115 : else
1116 2 : PG_RETURN_NULL();
1117 : }
1118 :
1119 : /*
1120 : * regtypeout - converts type OID to "typ_name"
1121 : */
1122 : Datum
1123 80 : regtypeout(PG_FUNCTION_ARGS)
1124 : {
1125 80 : Oid typid = PG_GETARG_OID(0);
1126 : char *result;
1127 : HeapTuple typetup;
1128 :
1129 80 : if (typid == InvalidOid)
1130 : {
1131 0 : result = pstrdup("-");
1132 0 : PG_RETURN_CSTRING(result);
1133 : }
1134 :
1135 80 : typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1136 :
1137 80 : if (HeapTupleIsValid(typetup))
1138 : {
1139 80 : 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 80 : if (IsBootstrapProcessingMode())
1147 : {
1148 0 : char *typname = NameStr(typeform->typname);
1149 :
1150 0 : result = pstrdup(typname);
1151 : }
1152 : else
1153 80 : result = format_type_be(typid);
1154 :
1155 80 : ReleaseSysCache(typetup);
1156 : }
1157 : else
1158 : {
1159 : /* If OID doesn't match any pg_type entry, return it numerically */
1160 0 : result = (char *) palloc(NAMEDATALEN);
1161 0 : snprintf(result, NAMEDATALEN, "%u", typid);
1162 : }
1163 :
1164 80 : PG_RETURN_CSTRING(result);
1165 : }
1166 :
1167 : /*
1168 : * regtyperecv - converts external binary format to regtype
1169 : */
1170 : Datum
1171 0 : regtyperecv(PG_FUNCTION_ARGS)
1172 : {
1173 : /* Exactly the same as oidrecv, so share code */
1174 0 : return oidrecv(fcinfo);
1175 : }
1176 :
1177 : /*
1178 : * regtypesend - converts regtype to binary format
1179 : */
1180 : Datum
1181 0 : regtypesend(PG_FUNCTION_ARGS)
1182 : {
1183 : /* Exactly the same as oidsend, so share code */
1184 0 : 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 : */
1196 : Datum
1197 175 : regconfigin(PG_FUNCTION_ARGS)
1198 : {
1199 175 : char *cfg_name_or_oid = PG_GETARG_CSTRING(0);
1200 : Oid result;
1201 : List *names;
1202 :
1203 : /* '-' ? */
1204 175 : if (strcmp(cfg_name_or_oid, "-") == 0)
1205 0 : PG_RETURN_OID(InvalidOid);
1206 :
1207 : /* Numeric OID? */
1208 350 : if (cfg_name_or_oid[0] >= '0' &&
1209 175 : cfg_name_or_oid[0] <= '9' &&
1210 0 : strspn(cfg_name_or_oid, "0123456789") == strlen(cfg_name_or_oid))
1211 : {
1212 0 : result = DatumGetObjectId(DirectFunctionCall1(oidin,
1213 : CStringGetDatum(cfg_name_or_oid)));
1214 0 : PG_RETURN_OID(result);
1215 : }
1216 :
1217 : /* The rest of this wouldn't work in bootstrap mode */
1218 175 : if (IsBootstrapProcessingMode())
1219 0 : 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 175 : names = stringToQualifiedNameList(cfg_name_or_oid);
1226 :
1227 175 : result = get_ts_config_oid(names, false);
1228 :
1229 175 : PG_RETURN_OID(result);
1230 : }
1231 :
1232 : /*
1233 : * regconfigout - converts tsconfig OID to "tsconfigname"
1234 : */
1235 : Datum
1236 0 : regconfigout(PG_FUNCTION_ARGS)
1237 : {
1238 0 : Oid cfgid = PG_GETARG_OID(0);
1239 : char *result;
1240 : HeapTuple cfgtup;
1241 :
1242 0 : if (cfgid == InvalidOid)
1243 : {
1244 0 : result = pstrdup("-");
1245 0 : PG_RETURN_CSTRING(result);
1246 : }
1247 :
1248 0 : cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
1249 :
1250 0 : if (HeapTupleIsValid(cfgtup))
1251 : {
1252 0 : Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
1253 0 : char *cfgname = NameStr(cfgform->cfgname);
1254 : char *nspname;
1255 :
1256 : /*
1257 : * Would this config be found by regconfigin? If not, qualify it.
1258 : */
1259 0 : if (TSConfigIsVisible(cfgid))
1260 0 : nspname = NULL;
1261 : else
1262 0 : nspname = get_namespace_name(cfgform->cfgnamespace);
1263 :
1264 0 : result = quote_qualified_identifier(nspname, cfgname);
1265 :
1266 0 : ReleaseSysCache(cfgtup);
1267 : }
1268 : else
1269 : {
1270 : /* If OID doesn't match any pg_ts_config row, return it numerically */
1271 0 : result = (char *) palloc(NAMEDATALEN);
1272 0 : snprintf(result, NAMEDATALEN, "%u", cfgid);
1273 : }
1274 :
1275 0 : PG_RETURN_CSTRING(result);
1276 : }
1277 :
1278 : /*
1279 : * regconfigrecv - converts external binary format to regconfig
1280 : */
1281 : Datum
1282 0 : regconfigrecv(PG_FUNCTION_ARGS)
1283 : {
1284 : /* Exactly the same as oidrecv, so share code */
1285 0 : return oidrecv(fcinfo);
1286 : }
1287 :
1288 : /*
1289 : * regconfigsend - converts regconfig to binary format
1290 : */
1291 : Datum
1292 0 : regconfigsend(PG_FUNCTION_ARGS)
1293 : {
1294 : /* Exactly the same as oidsend, so share code */
1295 0 : 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 : */
1307 : Datum
1308 66 : regdictionaryin(PG_FUNCTION_ARGS)
1309 : {
1310 66 : char *dict_name_or_oid = PG_GETARG_CSTRING(0);
1311 : Oid result;
1312 : List *names;
1313 :
1314 : /* '-' ? */
1315 66 : if (strcmp(dict_name_or_oid, "-") == 0)
1316 0 : PG_RETURN_OID(InvalidOid);
1317 :
1318 : /* Numeric OID? */
1319 132 : if (dict_name_or_oid[0] >= '0' &&
1320 66 : dict_name_or_oid[0] <= '9' &&
1321 0 : strspn(dict_name_or_oid, "0123456789") == strlen(dict_name_or_oid))
1322 : {
1323 0 : result = DatumGetObjectId(DirectFunctionCall1(oidin,
1324 : CStringGetDatum(dict_name_or_oid)));
1325 0 : PG_RETURN_OID(result);
1326 : }
1327 :
1328 : /* The rest of this wouldn't work in bootstrap mode */
1329 66 : if (IsBootstrapProcessingMode())
1330 0 : 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 66 : names = stringToQualifiedNameList(dict_name_or_oid);
1337 :
1338 66 : result = get_ts_dict_oid(names, false);
1339 :
1340 66 : PG_RETURN_OID(result);
1341 : }
1342 :
1343 : /*
1344 : * regdictionaryout - converts tsdictionary OID to "tsdictionaryname"
1345 : */
1346 : Datum
1347 32 : regdictionaryout(PG_FUNCTION_ARGS)
1348 : {
1349 32 : Oid dictid = PG_GETARG_OID(0);
1350 : char *result;
1351 : HeapTuple dicttup;
1352 :
1353 32 : if (dictid == InvalidOid)
1354 : {
1355 0 : result = pstrdup("-");
1356 0 : PG_RETURN_CSTRING(result);
1357 : }
1358 :
1359 32 : dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
1360 :
1361 32 : if (HeapTupleIsValid(dicttup))
1362 : {
1363 32 : Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
1364 32 : 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 32 : if (TSDictionaryIsVisible(dictid))
1372 32 : nspname = NULL;
1373 : else
1374 0 : nspname = get_namespace_name(dictform->dictnamespace);
1375 :
1376 32 : result = quote_qualified_identifier(nspname, dictname);
1377 :
1378 32 : ReleaseSysCache(dicttup);
1379 : }
1380 : else
1381 : {
1382 : /* If OID doesn't match any pg_ts_dict row, return it numerically */
1383 0 : result = (char *) palloc(NAMEDATALEN);
1384 0 : snprintf(result, NAMEDATALEN, "%u", dictid);
1385 : }
1386 :
1387 32 : PG_RETURN_CSTRING(result);
1388 : }
1389 :
1390 : /*
1391 : * regdictionaryrecv - converts external binary format to regdictionary
1392 : */
1393 : Datum
1394 0 : regdictionaryrecv(PG_FUNCTION_ARGS)
1395 : {
1396 : /* Exactly the same as oidrecv, so share code */
1397 0 : return oidrecv(fcinfo);
1398 : }
1399 :
1400 : /*
1401 : * regdictionarysend - converts regdictionary to binary format
1402 : */
1403 : Datum
1404 0 : regdictionarysend(PG_FUNCTION_ARGS)
1405 : {
1406 : /* Exactly the same as oidsend, so share code */
1407 0 : 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 : */
1418 : Datum
1419 9 : regrolein(PG_FUNCTION_ARGS)
1420 : {
1421 9 : char *role_name_or_oid = PG_GETARG_CSTRING(0);
1422 : Oid result;
1423 : List *names;
1424 :
1425 : /* '-' ? */
1426 9 : if (strcmp(role_name_or_oid, "-") == 0)
1427 0 : PG_RETURN_OID(InvalidOid);
1428 :
1429 : /* Numeric OID? */
1430 15 : if (role_name_or_oid[0] >= '0' &&
1431 6 : role_name_or_oid[0] <= '9' &&
1432 0 : strspn(role_name_or_oid, "0123456789") == strlen(role_name_or_oid))
1433 : {
1434 0 : result = DatumGetObjectId(DirectFunctionCall1(oidin,
1435 : CStringGetDatum(role_name_or_oid)));
1436 0 : PG_RETURN_OID(result);
1437 : }
1438 :
1439 : /* The rest of this wouldn't work in bootstrap mode */
1440 9 : if (IsBootstrapProcessingMode())
1441 0 : elog(ERROR, "regrole values must be OIDs in bootstrap mode");
1442 :
1443 : /* Normal case: see if the name matches any pg_authid entry. */
1444 9 : names = stringToQualifiedNameList(role_name_or_oid);
1445 :
1446 9 : if (list_length(names) != 1)
1447 1 : ereport(ERROR,
1448 : (errcode(ERRCODE_INVALID_NAME),
1449 : errmsg("invalid name syntax")));
1450 :
1451 8 : result = get_role_oid(strVal(linitial(names)), false);
1452 :
1453 4 : 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 : */
1461 : Datum
1462 8 : to_regrole(PG_FUNCTION_ARGS)
1463 : {
1464 8 : char *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1465 : Oid result;
1466 : List *names;
1467 :
1468 8 : names = stringToQualifiedNameList(role_name);
1469 :
1470 8 : if (list_length(names) != 1)
1471 2 : ereport(ERROR,
1472 : (errcode(ERRCODE_INVALID_NAME),
1473 : errmsg("invalid name syntax")));
1474 :
1475 6 : result = get_role_oid(strVal(linitial(names)), true);
1476 :
1477 6 : if (OidIsValid(result))
1478 2 : PG_RETURN_OID(result);
1479 : else
1480 4 : PG_RETURN_NULL();
1481 : }
1482 :
1483 : /*
1484 : * regroleout - converts role OID to "role_name"
1485 : */
1486 : Datum
1487 4 : regroleout(PG_FUNCTION_ARGS)
1488 : {
1489 4 : Oid roleoid = PG_GETARG_OID(0);
1490 : char *result;
1491 :
1492 4 : if (roleoid == InvalidOid)
1493 : {
1494 0 : result = pstrdup("-");
1495 0 : PG_RETURN_CSTRING(result);
1496 : }
1497 :
1498 4 : result = GetUserNameFromId(roleoid, true);
1499 :
1500 4 : if (result)
1501 : {
1502 : /* pstrdup is not really necessary, but it avoids a compiler warning */
1503 4 : result = pstrdup(quote_identifier(result));
1504 : }
1505 : else
1506 : {
1507 : /* If OID doesn't match any role, return it numerically */
1508 0 : result = (char *) palloc(NAMEDATALEN);
1509 0 : snprintf(result, NAMEDATALEN, "%u", roleoid);
1510 : }
1511 :
1512 4 : PG_RETURN_CSTRING(result);
1513 : }
1514 :
1515 : /*
1516 : * regrolerecv - converts external binary format to regrole
1517 : */
1518 : Datum
1519 0 : regrolerecv(PG_FUNCTION_ARGS)
1520 : {
1521 : /* Exactly the same as oidrecv, so share code */
1522 0 : return oidrecv(fcinfo);
1523 : }
1524 :
1525 : /*
1526 : * regrolesend - converts regrole to binary format
1527 : */
1528 : Datum
1529 0 : regrolesend(PG_FUNCTION_ARGS)
1530 : {
1531 : /* Exactly the same as oidsend, so share code */
1532 0 : 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 : */
1543 : Datum
1544 7 : regnamespacein(PG_FUNCTION_ARGS)
1545 : {
1546 7 : char *nsp_name_or_oid = PG_GETARG_CSTRING(0);
1547 : Oid result;
1548 : List *names;
1549 :
1550 : /* '-' ? */
1551 7 : if (strcmp(nsp_name_or_oid, "-") == 0)
1552 0 : PG_RETURN_OID(InvalidOid);
1553 :
1554 : /* Numeric OID? */
1555 12 : if (nsp_name_or_oid[0] >= '0' &&
1556 5 : nsp_name_or_oid[0] <= '9' &&
1557 0 : strspn(nsp_name_or_oid, "0123456789") == strlen(nsp_name_or_oid))
1558 : {
1559 0 : result = DatumGetObjectId(DirectFunctionCall1(oidin,
1560 : CStringGetDatum(nsp_name_or_oid)));
1561 0 : PG_RETURN_OID(result);
1562 : }
1563 :
1564 : /* The rest of this wouldn't work in bootstrap mode */
1565 7 : if (IsBootstrapProcessingMode())
1566 0 : elog(ERROR, "regnamespace values must be OIDs in bootstrap mode");
1567 :
1568 : /* Normal case: see if the name matches any pg_namespace entry. */
1569 7 : names = stringToQualifiedNameList(nsp_name_or_oid);
1570 :
1571 7 : if (list_length(names) != 1)
1572 1 : ereport(ERROR,
1573 : (errcode(ERRCODE_INVALID_NAME),
1574 : errmsg("invalid name syntax")));
1575 :
1576 6 : result = get_namespace_oid(strVal(linitial(names)), false);
1577 :
1578 4 : 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 : */
1586 : Datum
1587 5 : to_regnamespace(PG_FUNCTION_ARGS)
1588 : {
1589 5 : char *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1590 : Oid result;
1591 : List *names;
1592 :
1593 5 : names = stringToQualifiedNameList(nsp_name);
1594 :
1595 5 : if (list_length(names) != 1)
1596 1 : ereport(ERROR,
1597 : (errcode(ERRCODE_INVALID_NAME),
1598 : errmsg("invalid name syntax")));
1599 :
1600 4 : result = get_namespace_oid(strVal(linitial(names)), true);
1601 :
1602 4 : if (OidIsValid(result))
1603 2 : PG_RETURN_OID(result);
1604 : else
1605 2 : PG_RETURN_NULL();
1606 : }
1607 :
1608 : /*
1609 : * regnamespaceout - converts namespace OID to "nsp_name"
1610 : */
1611 : Datum
1612 5 : regnamespaceout(PG_FUNCTION_ARGS)
1613 : {
1614 5 : Oid nspid = PG_GETARG_OID(0);
1615 : char *result;
1616 :
1617 5 : if (nspid == InvalidOid)
1618 : {
1619 0 : result = pstrdup("-");
1620 0 : PG_RETURN_CSTRING(result);
1621 : }
1622 :
1623 5 : result = get_namespace_name(nspid);
1624 :
1625 5 : if (result)
1626 : {
1627 : /* pstrdup is not really necessary, but it avoids a compiler warning */
1628 5 : result = pstrdup(quote_identifier(result));
1629 : }
1630 : else
1631 : {
1632 : /* If OID doesn't match any namespace, return it numerically */
1633 0 : result = (char *) palloc(NAMEDATALEN);
1634 0 : snprintf(result, NAMEDATALEN, "%u", nspid);
1635 : }
1636 :
1637 5 : PG_RETURN_CSTRING(result);
1638 : }
1639 :
1640 : /*
1641 : * regnamespacerecv - converts external binary format to regnamespace
1642 : */
1643 : Datum
1644 0 : regnamespacerecv(PG_FUNCTION_ARGS)
1645 : {
1646 : /* Exactly the same as oidrecv, so share code */
1647 0 : return oidrecv(fcinfo);
1648 : }
1649 :
1650 : /*
1651 : * regnamespacesend - converts regnamespace to binary format
1652 : */
1653 : Datum
1654 0 : regnamespacesend(PG_FUNCTION_ARGS)
1655 : {
1656 : /* Exactly the same as oidsend, so share code */
1657 0 : 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 : */
1667 : Datum
1668 8 : text_regclass(PG_FUNCTION_ARGS)
1669 : {
1670 8 : text *relname = PG_GETARG_TEXT_PP(0);
1671 : Oid result;
1672 : RangeVar *rv;
1673 :
1674 8 : rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
1675 :
1676 : /* We might not even have permissions on this relation; don't lock it. */
1677 8 : result = RangeVarGetRelid(rv, NoLock, false);
1678 :
1679 7 : PG_RETURN_OID(result);
1680 : }
1681 :
1682 :
1683 : /*
1684 : * Given a C string, parse it into a qualified-name list.
1685 : */
1686 : List *
1687 1304 : stringToQualifiedNameList(const char *string)
1688 : {
1689 : char *rawname;
1690 1304 : List *result = NIL;
1691 : List *namelist;
1692 : ListCell *l;
1693 :
1694 : /* We need a modifiable copy of the input string. */
1695 1304 : rawname = pstrdup(string);
1696 :
1697 1304 : if (!SplitIdentifierString(rawname, '.', &namelist))
1698 0 : ereport(ERROR,
1699 : (errcode(ERRCODE_INVALID_NAME),
1700 : errmsg("invalid name syntax")));
1701 :
1702 1304 : if (namelist == NIL)
1703 0 : ereport(ERROR,
1704 : (errcode(ERRCODE_INVALID_NAME),
1705 : errmsg("invalid name syntax")));
1706 :
1707 3263 : foreach(l, namelist)
1708 : {
1709 1959 : char *curname = (char *) lfirst(l);
1710 :
1711 1959 : result = lappend(result, makeString(pstrdup(curname)));
1712 : }
1713 :
1714 1304 : pfree(rawname);
1715 1304 : list_free(namelist);
1716 :
1717 1304 : 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 : */
1734 : static void
1735 26 : parseNameAndArgTypes(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 26 : rawname = pstrdup(string);
1750 :
1751 : /* Scan to find the expected left paren; mustn't be quoted */
1752 26 : in_quote = false;
1753 228 : for (ptr = rawname; *ptr; ptr++)
1754 : {
1755 228 : if (*ptr == '"')
1756 0 : in_quote = !in_quote;
1757 228 : else if (*ptr == '(' && !in_quote)
1758 26 : break;
1759 : }
1760 26 : if (*ptr == '\0')
1761 0 : 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 26 : *ptr++ = '\0';
1767 26 : *names = stringToQualifiedNameList(rawname);
1768 :
1769 : /* Check for the trailing right parenthesis and remove it */
1770 26 : ptr2 = ptr + strlen(ptr);
1771 52 : while (--ptr2 > ptr)
1772 : {
1773 24 : if (!scanner_isspace(*ptr2))
1774 24 : break;
1775 : }
1776 26 : if (*ptr2 != ')')
1777 0 : ereport(ERROR,
1778 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1779 : errmsg("expected a right parenthesis")));
1780 :
1781 26 : *ptr2 = '\0';
1782 :
1783 : /* Separate the remaining string into comma-separated type names */
1784 26 : *nargs = 0;
1785 26 : had_comma = false;
1786 :
1787 : for (;;)
1788 : {
1789 : /* allow leading whitespace */
1790 124 : while (scanner_isspace(*ptr))
1791 0 : ptr++;
1792 62 : if (*ptr == '\0')
1793 : {
1794 : /* End of string. Okay unless we had a comma before. */
1795 26 : if (had_comma)
1796 0 : ereport(ERROR,
1797 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1798 : errmsg("expected a type name")));
1799 26 : break;
1800 : }
1801 36 : typename = ptr;
1802 : /* Find end of type name --- end of string or comma */
1803 : /* ... but not a quoted or parenthesized comma */
1804 36 : in_quote = false;
1805 36 : paren_count = 0;
1806 207 : for (; *ptr; ptr++)
1807 : {
1808 183 : if (*ptr == '"')
1809 0 : in_quote = !in_quote;
1810 183 : else if (*ptr == ',' && !in_quote && paren_count == 0)
1811 : break;
1812 171 : else if (!in_quote)
1813 : {
1814 171 : switch (*ptr)
1815 : {
1816 : case '(':
1817 : case '[':
1818 0 : paren_count++;
1819 0 : break;
1820 : case ')':
1821 : case ']':
1822 0 : paren_count--;
1823 0 : break;
1824 : }
1825 : }
1826 : }
1827 36 : if (in_quote || paren_count != 0)
1828 0 : ereport(ERROR,
1829 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1830 : errmsg("improper type name")));
1831 :
1832 36 : ptr2 = ptr;
1833 36 : if (*ptr == ',')
1834 : {
1835 12 : had_comma = true;
1836 12 : *ptr++ = '\0';
1837 : }
1838 : else
1839 : {
1840 24 : had_comma = false;
1841 24 : Assert(*ptr == '\0');
1842 : }
1843 : /* Lop off trailing whitespace */
1844 72 : while (--ptr2 >= typename)
1845 : {
1846 36 : if (!scanner_isspace(*ptr2))
1847 36 : break;
1848 0 : *ptr2 = '\0';
1849 : }
1850 :
1851 36 : if (allowNone && pg_strcasecmp(typename, "none") == 0)
1852 : {
1853 : /* Special case for NONE */
1854 0 : typeid = InvalidOid;
1855 0 : typmod = -1;
1856 : }
1857 : else
1858 : {
1859 : /* Use full parser to resolve the type name */
1860 36 : parseTypeString(typename, &typeid, &typmod, false);
1861 : }
1862 36 : if (*nargs >= FUNC_MAX_ARGS)
1863 0 : ereport(ERROR,
1864 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
1865 : errmsg("too many arguments")));
1866 :
1867 36 : argtypes[*nargs] = typeid;
1868 36 : (*nargs)++;
1869 36 : }
1870 :
1871 26 : pfree(rawname);
1872 26 : }
|