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