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-2025, 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 970212 : regprocin(PG_FUNCTION_ARGS)
68 : {
69 970212 : char *pro_name_or_oid = PG_GETARG_CSTRING(0);
70 970212 : Node *escontext = fcinfo->context;
71 : RegProcedure result;
72 : List *names;
73 : FuncCandidateList clist;
74 : int fgc_flags;
75 :
76 : /* Handle "-" or numeric OID */
77 970212 : if (parseDashOrOid(pro_name_or_oid, &result, escontext))
78 969482 : 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 730 : 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 730 : names = stringToQualifiedNameList(pro_name_or_oid, escontext);
94 730 : if (names == NIL)
95 0 : PG_RETURN_NULL();
96 :
97 730 : clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true,
98 : &fgc_flags);
99 :
100 730 : if (clist == NULL)
101 30 : ereturn(escontext, (Datum) 0,
102 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
103 : errmsg("function \"%s\" does not exist", pro_name_or_oid)));
104 700 : 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 700 : result = clist->oid;
111 :
112 700 : 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 30 : to_regproc(PG_FUNCTION_ARGS)
122 : {
123 30 : char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
124 : Datum result;
125 30 : ErrorSaveContext escontext = {T_ErrorSaveContext};
126 :
127 30 : if (!DirectInputFunctionCallSafe(regprocin, pro_name,
128 : InvalidOid, -1,
129 : (Node *) &escontext,
130 : &result))
131 12 : PG_RETURN_NULL();
132 18 : PG_RETURN_DATUM(result);
133 : }
134 :
135 : /*
136 : * regprocout - converts proc OID to "pro_name"
137 : */
138 : Datum
139 165774 : regprocout(PG_FUNCTION_ARGS)
140 : {
141 165774 : RegProcedure proid = PG_GETARG_OID(0);
142 : char *result;
143 : HeapTuple proctup;
144 :
145 165774 : if (proid == InvalidOid)
146 : {
147 74390 : result = pstrdup("-");
148 74390 : PG_RETURN_CSTRING(result);
149 : }
150 :
151 91384 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
152 :
153 91384 : if (HeapTupleIsValid(proctup))
154 : {
155 91384 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
156 91384 : 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 91384 : 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 91384 : clist = FuncnameGetCandidates(list_make1(makeString(proname)),
176 : -1, NIL, false, false, false, false,
177 : &fgc_flags);
178 91384 : if (clist != NULL && clist->next == NULL &&
179 88206 : clist->oid == proid)
180 88206 : nspname = NULL;
181 : else
182 3178 : nspname = get_namespace_name(procform->pronamespace);
183 :
184 91384 : result = quote_qualified_identifier(nspname, proname);
185 : }
186 :
187 91384 : 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 91384 : 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 514 : regprocedurein(PG_FUNCTION_ARGS)
230 : {
231 514 : char *pro_name_or_oid = PG_GETARG_CSTRING(0);
232 514 : 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 514 : if (parseDashOrOid(pro_name_or_oid, &result, escontext))
242 14 : PG_RETURN_OID(result);
243 :
244 : /* The rest of this wouldn't work in bootstrap mode */
245 500 : 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 500 : if (!parseNameAndArgTypes(pro_name_or_oid, false,
255 : &names, &nargs, argtypes,
256 : escontext))
257 6 : PG_RETURN_NULL();
258 :
259 494 : clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false, true,
260 : &fgc_flags);
261 :
262 494 : for (; clist; clist = clist->next)
263 : {
264 464 : if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
265 464 : break;
266 : }
267 :
268 494 : if (clist == NULL)
269 30 : ereturn(escontext, (Datum) 0,
270 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
271 : errmsg("function \"%s\" does not exist", pro_name_or_oid)));
272 :
273 464 : result = clist->oid;
274 :
275 464 : 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 30 : to_regprocedure(PG_FUNCTION_ARGS)
285 : {
286 30 : char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
287 : Datum result;
288 30 : ErrorSaveContext escontext = {T_ErrorSaveContext};
289 :
290 30 : if (!DirectInputFunctionCallSafe(regprocedurein, pro_name,
291 : InvalidOid, -1,
292 : (Node *) &escontext,
293 : &result))
294 12 : PG_RETURN_NULL();
295 18 : 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 23648 : format_procedure(Oid procedure_oid)
306 : {
307 23648 : 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 28778 : format_procedure_extended(Oid procedure_oid, bits16 flags)
333 : {
334 : char *result;
335 : HeapTuple proctup;
336 :
337 28778 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
338 :
339 28778 : if (HeapTupleIsValid(proctup))
340 : {
341 28760 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
342 28760 : char *proname = NameStr(procform->proname);
343 28760 : 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 28760 : 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 57216 : if ((flags & FORMAT_PROC_FORCE_QUALIFY) == 0 &&
358 28456 : FunctionIsVisible(procedure_oid))
359 27636 : nspname = NULL;
360 : else
361 1124 : nspname = get_namespace_name(procform->pronamespace);
362 :
363 28760 : appendStringInfo(&buf, "%s(",
364 : quote_qualified_identifier(nspname, proname));
365 87650 : for (i = 0; i < nargs; i++)
366 : {
367 58890 : Oid thisargtype = procform->proargtypes.values[i];
368 :
369 58890 : if (i > 0)
370 36470 : appendStringInfoChar(&buf, ',');
371 58890 : appendStringInfoString(&buf,
372 58890 : (flags & FORMAT_PROC_FORCE_QUALIFY) != 0 ?
373 348 : format_type_be_qualified(thisargtype) :
374 58542 : format_type_be(thisargtype));
375 : }
376 28760 : appendStringInfoChar(&buf, ')');
377 :
378 28760 : result = buf.data;
379 :
380 28760 : ReleaseSysCache(proctup);
381 : }
382 18 : else if ((flags & FORMAT_PROC_INVALID_AS_NULL) != 0)
383 : {
384 : /* If object is undefined, return NULL as wanted by caller */
385 18 : 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 28778 : 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 136 : 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 136 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
413 :
414 136 : 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 136 : procform = (Form_pg_proc) GETSTRUCT(proctup);
422 136 : nargs = procform->pronargs;
423 :
424 136 : *objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
425 : pstrdup(NameStr(procform->proname)));
426 136 : *objargs = NIL;
427 256 : for (i = 0; i < nargs; i++)
428 : {
429 120 : Oid thisargtype = procform->proargtypes.values[i];
430 :
431 120 : *objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
432 : }
433 :
434 136 : ReleaseSysCache(proctup);
435 : }
436 :
437 : /*
438 : * regprocedureout - converts proc OID to "pro_name(args)"
439 : */
440 : Datum
441 17606 : regprocedureout(PG_FUNCTION_ARGS)
442 : {
443 17606 : RegProcedure proid = PG_GETARG_OID(0);
444 : char *result;
445 :
446 17606 : if (proid == InvalidOid)
447 3904 : result = pstrdup("-");
448 : else
449 13702 : result = format_procedure(proid);
450 :
451 17606 : 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 60 : regoperin(PG_FUNCTION_ARGS)
485 : {
486 60 : char *opr_name_or_oid = PG_GETARG_CSTRING(0);
487 60 : 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 60 : 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 60 : 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 60 : names = stringToQualifiedNameList(opr_name_or_oid, escontext);
508 60 : if (names == NIL)
509 0 : PG_RETURN_NULL();
510 :
511 60 : clist = OpernameGetCandidates(names, '\0', true, &fgc_flags);
512 :
513 60 : if (clist == NULL)
514 30 : ereturn(escontext, (Datum) 0,
515 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
516 : errmsg("operator does not exist: %s", opr_name_or_oid)));
517 30 : else if (clist->next != NULL)
518 6 : ereturn(escontext, (Datum) 0,
519 : (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
520 : errmsg("more than one operator named %s",
521 : opr_name_or_oid)));
522 :
523 24 : result = clist->oid;
524 :
525 24 : 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 24 : to_regoper(PG_FUNCTION_ARGS)
535 : {
536 24 : char *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
537 : Datum result;
538 24 : ErrorSaveContext escontext = {T_ErrorSaveContext};
539 :
540 24 : if (!DirectInputFunctionCallSafe(regoperin, opr_name,
541 : InvalidOid, -1,
542 : (Node *) &escontext,
543 : &result))
544 12 : PG_RETURN_NULL();
545 12 : PG_RETURN_DATUM(result);
546 : }
547 :
548 : /*
549 : * regoperout - converts operator OID to "opr_name"
550 : */
551 : Datum
552 24 : regoperout(PG_FUNCTION_ARGS)
553 : {
554 24 : Oid oprid = PG_GETARG_OID(0);
555 : char *result;
556 : HeapTuple opertup;
557 :
558 24 : if (oprid == InvalidOid)
559 : {
560 0 : result = pstrdup("0");
561 0 : PG_RETURN_CSTRING(result);
562 : }
563 :
564 24 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
565 :
566 24 : if (HeapTupleIsValid(opertup))
567 : {
568 24 : Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
569 24 : 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 24 : 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 24 : clist = OpernameGetCandidates(list_make1(makeString(oprname)),
588 : '\0', false, &fgc_flags);
589 24 : if (clist != NULL && clist->next == NULL &&
590 24 : clist->oid == oprid)
591 24 : 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 24 : 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 24 : 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 84 : regoperatorin(PG_FUNCTION_ARGS)
648 : {
649 84 : char *opr_name_or_oid = PG_GETARG_CSTRING(0);
650 84 : 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 84 : 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 84 : 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 84 : if (!parseNameAndArgTypes(opr_name_or_oid, true,
671 : &names, &nargs, argtypes,
672 : escontext))
673 6 : PG_RETURN_NULL();
674 :
675 78 : 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 78 : 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 78 : result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
687 :
688 78 : if (!OidIsValid(result))
689 30 : ereturn(escontext, (Datum) 0,
690 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
691 : errmsg("operator does not exist: %s", opr_name_or_oid)));
692 :
693 48 : 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 18 : to_regoperator(PG_FUNCTION_ARGS)
703 : {
704 18 : char *opr_name_or_oid = text_to_cstring(PG_GETARG_TEXT_PP(0));
705 : Datum result;
706 18 : ErrorSaveContext escontext = {T_ErrorSaveContext};
707 :
708 18 : if (!DirectInputFunctionCallSafe(regoperatorin, opr_name_or_oid,
709 : InvalidOid, -1,
710 : (Node *) &escontext,
711 : &result))
712 12 : PG_RETURN_NULL();
713 6 : 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 3950 : format_operator_extended(Oid operator_oid, bits16 flags)
731 : {
732 : char *result;
733 : HeapTuple opertup;
734 :
735 3950 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
736 :
737 3950 : if (HeapTupleIsValid(opertup))
738 : {
739 3932 : Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
740 3932 : 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 3932 : 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 3932 : if ((flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ||
754 3886 : !OperatorIsVisible(operator_oid))
755 : {
756 364 : nspname = get_namespace_name(operform->oprnamespace);
757 364 : appendStringInfo(&buf, "%s.",
758 : quote_identifier(nspname));
759 : }
760 :
761 3932 : appendStringInfo(&buf, "%s(", oprname);
762 :
763 3932 : if (operform->oprleft)
764 3920 : appendStringInfo(&buf, "%s,",
765 3920 : (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
766 46 : format_type_be_qualified(operform->oprleft) :
767 3874 : format_type_be(operform->oprleft));
768 : else
769 12 : appendStringInfoString(&buf, "NONE,");
770 :
771 3932 : if (operform->oprright)
772 3932 : appendStringInfo(&buf, "%s)",
773 3932 : (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
774 46 : format_type_be_qualified(operform->oprright) :
775 3886 : format_type_be(operform->oprright));
776 : else
777 0 : appendStringInfoString(&buf, "NONE)");
778 :
779 3932 : result = buf.data;
780 :
781 3932 : ReleaseSysCache(opertup);
782 : }
783 18 : else if ((flags & FORMAT_OPERATOR_INVALID_AS_NULL) != 0)
784 : {
785 : /* If object is undefined, return NULL as wanted by caller */
786 18 : 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 3950 : return result;
798 : }
799 :
800 : char *
801 3120 : format_operator(Oid operator_oid)
802 : {
803 3120 : 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 6 : 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 6 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
821 6 : 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 6 : oprForm = (Form_pg_operator) GETSTRUCT(opertup);
830 6 : *objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
831 : pstrdup(NameStr(oprForm->oprname)));
832 6 : *objargs = NIL;
833 6 : if (oprForm->oprleft)
834 6 : *objargs = lappend(*objargs,
835 6 : format_type_be_qualified(oprForm->oprleft));
836 6 : if (oprForm->oprright)
837 6 : *objargs = lappend(*objargs,
838 6 : format_type_be_qualified(oprForm->oprright));
839 :
840 6 : ReleaseSysCache(opertup);
841 : }
842 :
843 : /*
844 : * regoperatorout - converts operator OID to "opr_name(args)"
845 : */
846 : Datum
847 1042 : regoperatorout(PG_FUNCTION_ARGS)
848 : {
849 1042 : Oid oprid = PG_GETARG_OID(0);
850 : char *result;
851 :
852 1042 : if (oprid == InvalidOid)
853 0 : result = pstrdup("0");
854 : else
855 1042 : result = format_operator(oprid);
856 :
857 1042 : 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 47244 : regclassin(PG_FUNCTION_ARGS)
891 : {
892 47244 : char *class_name_or_oid = PG_GETARG_CSTRING(0);
893 47244 : Node *escontext = fcinfo->context;
894 : Oid result;
895 : List *names;
896 :
897 : /* Handle "-" or numeric OID */
898 47244 : if (parseDashOrOid(class_name_or_oid, &result, escontext))
899 15110 : 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 32134 : 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 32134 : names = stringToQualifiedNameList(class_name_or_oid, escontext);
912 32134 : if (names == NIL)
913 0 : PG_RETURN_NULL();
914 :
915 : /* We might not even have permissions on this relation; don't lock it. */
916 32134 : result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
917 :
918 32134 : if (!OidIsValid(result))
919 40 : ereturn(escontext, (Datum) 0,
920 : (errcode(ERRCODE_UNDEFINED_TABLE),
921 : errmsg("relation \"%s\" does not exist",
922 : NameListToString(names))));
923 :
924 32094 : 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 30 : to_regclass(PG_FUNCTION_ARGS)
934 : {
935 30 : char *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
936 : Datum result;
937 30 : ErrorSaveContext escontext = {T_ErrorSaveContext};
938 :
939 30 : if (!DirectInputFunctionCallSafe(regclassin, class_name,
940 : InvalidOid, -1,
941 : (Node *) &escontext,
942 : &result))
943 12 : PG_RETURN_NULL();
944 18 : PG_RETURN_DATUM(result);
945 : }
946 :
947 : /*
948 : * regclassout - converts class OID to "class_name"
949 : */
950 : Datum
951 209990 : regclassout(PG_FUNCTION_ARGS)
952 : {
953 209990 : Oid classid = PG_GETARG_OID(0);
954 : char *result;
955 : HeapTuple classtup;
956 :
957 209990 : if (classid == InvalidOid)
958 : {
959 534 : result = pstrdup("-");
960 534 : PG_RETURN_CSTRING(result);
961 : }
962 :
963 209456 : classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
964 :
965 209456 : if (HeapTupleIsValid(classtup))
966 : {
967 209038 : Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
968 209038 : 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 209038 : 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 209038 : if (RelationIsVisible(classid))
985 135932 : nspname = NULL;
986 : else
987 73106 : nspname = get_namespace_name(classform->relnamespace);
988 :
989 209038 : result = quote_qualified_identifier(nspname, classname);
990 : }
991 :
992 209038 : ReleaseSysCache(classtup);
993 : }
994 : else
995 : {
996 : /* If OID doesn't match any pg_class entry, return it numerically */
997 418 : result = (char *) palloc(NAMEDATALEN);
998 418 : snprintf(result, NAMEDATALEN, "%u", classid);
999 : }
1000 :
1001 209456 : 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 60 : regcollationin(PG_FUNCTION_ARGS)
1035 : {
1036 60 : char *collation_name_or_oid = PG_GETARG_CSTRING(0);
1037 60 : Node *escontext = fcinfo->context;
1038 : Oid result;
1039 : List *names;
1040 :
1041 : /* Handle "-" or numeric OID */
1042 60 : if (parseDashOrOid(collation_name_or_oid, &result, escontext))
1043 12 : 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 48 : 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 48 : names = stringToQualifiedNameList(collation_name_or_oid, escontext);
1056 48 : if (names == NIL)
1057 0 : PG_RETURN_NULL();
1058 :
1059 48 : result = get_collation_oid(names, true);
1060 :
1061 48 : if (!OidIsValid(result))
1062 24 : 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 24 : 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 30 : to_regcollation(PG_FUNCTION_ARGS)
1077 : {
1078 30 : char *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1079 : Datum result;
1080 30 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1081 :
1082 30 : if (!DirectInputFunctionCallSafe(regcollationin, collation_name,
1083 : InvalidOid, -1,
1084 : (Node *) &escontext,
1085 : &result))
1086 12 : PG_RETURN_NULL();
1087 18 : PG_RETURN_DATUM(result);
1088 : }
1089 :
1090 : /*
1091 : * regcollationout - converts collation OID to "collation_name"
1092 : */
1093 : Datum
1094 24 : regcollationout(PG_FUNCTION_ARGS)
1095 : {
1096 24 : Oid collationid = PG_GETARG_OID(0);
1097 : char *result;
1098 : HeapTuple collationtup;
1099 :
1100 24 : if (collationid == InvalidOid)
1101 : {
1102 0 : result = pstrdup("-");
1103 0 : PG_RETURN_CSTRING(result);
1104 : }
1105 :
1106 24 : collationtup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationid));
1107 :
1108 24 : if (HeapTupleIsValid(collationtup))
1109 : {
1110 24 : Form_pg_collation collationform = (Form_pg_collation) GETSTRUCT(collationtup);
1111 24 : 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 24 : 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 24 : if (CollationIsVisible(collationid))
1129 24 : nspname = NULL;
1130 : else
1131 0 : nspname = get_namespace_name(collationform->collnamespace);
1132 :
1133 24 : result = quote_qualified_identifier(nspname, collationname);
1134 : }
1135 :
1136 24 : 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 24 : 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 1118 : regtypein(PG_FUNCTION_ARGS)
1185 : {
1186 1118 : char *typ_name_or_oid = PG_GETARG_CSTRING(0);
1187 1118 : Node *escontext = fcinfo->context;
1188 : Oid result;
1189 : int32 typmod;
1190 :
1191 : /* Handle "-" or numeric OID */
1192 1118 : if (parseDashOrOid(typ_name_or_oid, &result, escontext))
1193 32 : 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 1086 : 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 1086 : (void) parseTypeString(typ_name_or_oid, &result, &typmod, escontext);
1207 :
1208 1050 : 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 48 : to_regtype(PG_FUNCTION_ARGS)
1218 : {
1219 48 : char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1220 : Datum result;
1221 48 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1222 :
1223 48 : if (!DirectInputFunctionCallSafe(regtypein, typ_name,
1224 : InvalidOid, -1,
1225 : (Node *) &escontext,
1226 : &result))
1227 12 : PG_RETURN_NULL();
1228 36 : 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 36 : to_regtypemod(PG_FUNCTION_ARGS)
1238 : {
1239 36 : char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1240 : Oid typid;
1241 : int32 typmod;
1242 36 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1243 :
1244 : /* We rely on parseTypeString to parse the input. */
1245 36 : if (!parseTypeString(typ_name, &typid, &typmod, (Node *) &escontext))
1246 6 : PG_RETURN_NULL();
1247 :
1248 30 : PG_RETURN_INT32(typmod);
1249 : }
1250 :
1251 : /*
1252 : * regtypeout - converts type OID to "typ_name"
1253 : */
1254 : Datum
1255 17572 : regtypeout(PG_FUNCTION_ARGS)
1256 : {
1257 17572 : Oid typid = PG_GETARG_OID(0);
1258 : char *result;
1259 : HeapTuple typetup;
1260 :
1261 17572 : if (typid == InvalidOid)
1262 : {
1263 1624 : result = pstrdup("-");
1264 1624 : PG_RETURN_CSTRING(result);
1265 : }
1266 :
1267 15948 : typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1268 :
1269 15948 : if (HeapTupleIsValid(typetup))
1270 : {
1271 15948 : 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 15948 : if (IsBootstrapProcessingMode())
1279 : {
1280 0 : char *typname = NameStr(typeform->typname);
1281 :
1282 0 : result = pstrdup(typname);
1283 : }
1284 : else
1285 15948 : result = format_type_be(typid);
1286 :
1287 15948 : 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 15948 : 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 1940 : regconfigin(PG_FUNCTION_ARGS)
1330 : {
1331 1940 : char *cfg_name_or_oid = PG_GETARG_CSTRING(0);
1332 1940 : Node *escontext = fcinfo->context;
1333 : Oid result;
1334 : List *names;
1335 :
1336 : /* Handle "-" or numeric OID */
1337 1940 : if (parseDashOrOid(cfg_name_or_oid, &result, escontext))
1338 6 : PG_RETURN_OID(result);
1339 :
1340 : /* The rest of this wouldn't work in bootstrap mode */
1341 1934 : 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 1934 : names = stringToQualifiedNameList(cfg_name_or_oid, escontext);
1349 1934 : if (names == NIL)
1350 0 : PG_RETURN_NULL();
1351 :
1352 1934 : result = get_ts_config_oid(names, true);
1353 :
1354 1934 : if (!OidIsValid(result))
1355 6 : ereturn(escontext, (Datum) 0,
1356 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1357 : errmsg("text search configuration \"%s\" does not exist",
1358 : NameListToString(names))));
1359 :
1360 1928 : PG_RETURN_OID(result);
1361 : }
1362 :
1363 : /*
1364 : * regconfigout - converts tsconfig OID to "tsconfigname"
1365 : */
1366 : Datum
1367 10 : regconfigout(PG_FUNCTION_ARGS)
1368 : {
1369 10 : Oid cfgid = PG_GETARG_OID(0);
1370 : char *result;
1371 : HeapTuple cfgtup;
1372 :
1373 10 : if (cfgid == InvalidOid)
1374 : {
1375 0 : result = pstrdup("-");
1376 0 : PG_RETURN_CSTRING(result);
1377 : }
1378 :
1379 10 : cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
1380 :
1381 10 : if (HeapTupleIsValid(cfgtup))
1382 : {
1383 10 : Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
1384 10 : char *cfgname = NameStr(cfgform->cfgname);
1385 : char *nspname;
1386 :
1387 : /*
1388 : * Would this config be found by regconfigin? If not, qualify it.
1389 : */
1390 10 : if (TSConfigIsVisible(cfgid))
1391 6 : nspname = NULL;
1392 : else
1393 4 : nspname = get_namespace_name(cfgform->cfgnamespace);
1394 :
1395 10 : result = quote_qualified_identifier(nspname, cfgname);
1396 :
1397 10 : 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 10 : 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 642 : regdictionaryin(PG_FUNCTION_ARGS)
1440 : {
1441 642 : char *dict_name_or_oid = PG_GETARG_CSTRING(0);
1442 642 : Node *escontext = fcinfo->context;
1443 : Oid result;
1444 : List *names;
1445 :
1446 : /* Handle "-" or numeric OID */
1447 642 : if (parseDashOrOid(dict_name_or_oid, &result, escontext))
1448 6 : PG_RETURN_OID(result);
1449 :
1450 : /* The rest of this wouldn't work in bootstrap mode */
1451 636 : 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 636 : names = stringToQualifiedNameList(dict_name_or_oid, escontext);
1459 636 : if (names == NIL)
1460 0 : PG_RETURN_NULL();
1461 :
1462 636 : result = get_ts_dict_oid(names, true);
1463 :
1464 636 : if (!OidIsValid(result))
1465 6 : ereturn(escontext, (Datum) 0,
1466 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1467 : errmsg("text search dictionary \"%s\" does not exist",
1468 : NameListToString(names))));
1469 :
1470 630 : PG_RETURN_OID(result);
1471 : }
1472 :
1473 : /*
1474 : * regdictionaryout - converts tsdictionary OID to "tsdictionaryname"
1475 : */
1476 : Datum
1477 6098 : regdictionaryout(PG_FUNCTION_ARGS)
1478 : {
1479 6098 : Oid dictid = PG_GETARG_OID(0);
1480 : char *result;
1481 : HeapTuple dicttup;
1482 :
1483 6098 : if (dictid == InvalidOid)
1484 : {
1485 0 : result = pstrdup("-");
1486 0 : PG_RETURN_CSTRING(result);
1487 : }
1488 :
1489 6098 : dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
1490 :
1491 6098 : if (HeapTupleIsValid(dicttup))
1492 : {
1493 6098 : Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
1494 6098 : 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 6098 : if (TSDictionaryIsVisible(dictid))
1502 5828 : nspname = NULL;
1503 : else
1504 270 : nspname = get_namespace_name(dictform->dictnamespace);
1505 :
1506 6098 : result = quote_qualified_identifier(nspname, dictname);
1507 :
1508 6098 : 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 6098 : 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 242 : regrolein(PG_FUNCTION_ARGS)
1550 : {
1551 242 : char *role_name_or_oid = PG_GETARG_CSTRING(0);
1552 242 : Node *escontext = fcinfo->context;
1553 : Oid result;
1554 : List *names;
1555 :
1556 : /* Handle "-" or numeric OID */
1557 242 : if (parseDashOrOid(role_name_or_oid, &result, escontext))
1558 12 : PG_RETURN_OID(result);
1559 :
1560 : /* The rest of this wouldn't work in bootstrap mode */
1561 230 : 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 230 : names = stringToQualifiedNameList(role_name_or_oid, escontext);
1566 230 : if (names == NIL)
1567 0 : PG_RETURN_NULL();
1568 :
1569 230 : if (list_length(names) != 1)
1570 18 : ereturn(escontext, (Datum) 0,
1571 : (errcode(ERRCODE_INVALID_NAME),
1572 : errmsg("invalid name syntax")));
1573 :
1574 212 : result = get_role_oid(strVal(linitial(names)), true);
1575 :
1576 212 : if (!OidIsValid(result))
1577 54 : ereturn(escontext, (Datum) 0,
1578 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1579 : errmsg("role \"%s\" does not exist",
1580 : strVal(linitial(names)))));
1581 :
1582 158 : 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 54 : to_regrole(PG_FUNCTION_ARGS)
1592 : {
1593 54 : char *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1594 : Datum result;
1595 54 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1596 :
1597 54 : if (!DirectInputFunctionCallSafe(regrolein, role_name,
1598 : InvalidOid, -1,
1599 : (Node *) &escontext,
1600 : &result))
1601 36 : PG_RETURN_NULL();
1602 18 : PG_RETURN_DATUM(result);
1603 : }
1604 :
1605 : /*
1606 : * regroleout - converts role OID to "role_name"
1607 : */
1608 : Datum
1609 1552 : regroleout(PG_FUNCTION_ARGS)
1610 : {
1611 1552 : Oid roleoid = PG_GETARG_OID(0);
1612 : char *result;
1613 :
1614 1552 : if (roleoid == InvalidOid)
1615 : {
1616 140 : result = pstrdup("-");
1617 140 : PG_RETURN_CSTRING(result);
1618 : }
1619 :
1620 1412 : result = GetUserNameFromId(roleoid, true);
1621 :
1622 1412 : if (result)
1623 : {
1624 : /* pstrdup is not really necessary, but it avoids a compiler warning */
1625 1412 : 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 1412 : 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 692 : regnamespacein(PG_FUNCTION_ARGS)
1667 : {
1668 692 : char *nsp_name_or_oid = PG_GETARG_CSTRING(0);
1669 692 : Node *escontext = fcinfo->context;
1670 : Oid result;
1671 : List *names;
1672 :
1673 : /* Handle "-" or numeric OID */
1674 692 : if (parseDashOrOid(nsp_name_or_oid, &result, escontext))
1675 12 : PG_RETURN_OID(result);
1676 :
1677 : /* The rest of this wouldn't work in bootstrap mode */
1678 680 : 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 680 : names = stringToQualifiedNameList(nsp_name_or_oid, escontext);
1683 680 : if (names == NIL)
1684 0 : PG_RETURN_NULL();
1685 :
1686 680 : if (list_length(names) != 1)
1687 12 : ereturn(escontext, (Datum) 0,
1688 : (errcode(ERRCODE_INVALID_NAME),
1689 : errmsg("invalid name syntax")));
1690 :
1691 668 : result = get_namespace_oid(strVal(linitial(names)), true);
1692 :
1693 668 : if (!OidIsValid(result))
1694 30 : ereturn(escontext, (Datum) 0,
1695 : (errcode(ERRCODE_UNDEFINED_SCHEMA),
1696 : errmsg("schema \"%s\" does not exist",
1697 : strVal(linitial(names)))));
1698 :
1699 638 : 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 36 : to_regnamespace(PG_FUNCTION_ARGS)
1709 : {
1710 36 : char *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1711 : Datum result;
1712 36 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1713 :
1714 36 : if (!DirectInputFunctionCallSafe(regnamespacein, nsp_name,
1715 : InvalidOid, -1,
1716 : (Node *) &escontext,
1717 : &result))
1718 18 : PG_RETURN_NULL();
1719 18 : PG_RETURN_DATUM(result);
1720 : }
1721 :
1722 : /*
1723 : * regnamespaceout - converts namespace OID to "nsp_name"
1724 : */
1725 : Datum
1726 1212 : regnamespaceout(PG_FUNCTION_ARGS)
1727 : {
1728 1212 : Oid nspid = PG_GETARG_OID(0);
1729 : char *result;
1730 :
1731 1212 : if (nspid == InvalidOid)
1732 : {
1733 0 : result = pstrdup("-");
1734 0 : PG_RETURN_CSTRING(result);
1735 : }
1736 :
1737 1212 : result = get_namespace_name(nspid);
1738 :
1739 1212 : if (result)
1740 : {
1741 : /* pstrdup is not really necessary, but it avoids a compiler warning */
1742 1212 : 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 1212 : 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 90 : regdatabasein(PG_FUNCTION_ARGS)
1784 : {
1785 90 : char *db_name_or_oid = PG_GETARG_CSTRING(0);
1786 90 : Node *escontext = fcinfo->context;
1787 : Oid result;
1788 : List *names;
1789 :
1790 : /* Handle "-" or numeric OID */
1791 90 : if (parseDashOrOid(db_name_or_oid, &result, escontext))
1792 12 : PG_RETURN_OID(result);
1793 :
1794 : /* The rest of this wouldn't work in bootstrap mode */
1795 78 : 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 78 : names = stringToQualifiedNameList(db_name_or_oid, escontext);
1800 78 : if (names == NIL)
1801 0 : PG_RETURN_NULL();
1802 :
1803 78 : if (list_length(names) != 1)
1804 12 : ereturn(escontext, (Datum) 0,
1805 : (errcode(ERRCODE_INVALID_NAME),
1806 : errmsg("invalid name syntax")));
1807 :
1808 66 : result = get_database_oid(strVal(linitial(names)), true);
1809 :
1810 66 : if (!OidIsValid(result))
1811 30 : ereturn(escontext, (Datum) 0,
1812 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1813 : errmsg("database \"%s\" does not exist",
1814 : strVal(linitial(names)))));
1815 :
1816 36 : 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 36 : to_regdatabase(PG_FUNCTION_ARGS)
1826 : {
1827 36 : char *db_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1828 : Datum result;
1829 36 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1830 :
1831 36 : if (!DirectInputFunctionCallSafe(regdatabasein, db_name,
1832 : InvalidOid, -1,
1833 : (Node *) &escontext,
1834 : &result))
1835 18 : PG_RETURN_NULL();
1836 18 : PG_RETURN_DATUM(result);
1837 : }
1838 :
1839 : /*
1840 : * regdatabaseout - converts database OID to database name
1841 : */
1842 : Datum
1843 32 : regdatabaseout(PG_FUNCTION_ARGS)
1844 : {
1845 32 : Oid dboid = PG_GETARG_OID(0);
1846 : char *result;
1847 :
1848 32 : if (dboid == InvalidOid)
1849 : {
1850 0 : result = pstrdup("-");
1851 0 : PG_RETURN_CSTRING(result);
1852 : }
1853 :
1854 32 : result = get_database_name(dboid);
1855 :
1856 32 : if (result)
1857 : {
1858 : /* pstrdup is not really necessary, but it avoids a compiler warning */
1859 32 : 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 32 : 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 4024 : text_regclass(PG_FUNCTION_ARGS)
1900 : {
1901 4024 : text *relname = PG_GETARG_TEXT_PP(0);
1902 : Oid result;
1903 : RangeVar *rv;
1904 :
1905 4024 : rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
1906 :
1907 : /* We might not even have permissions on this relation; don't lock it. */
1908 4024 : result = RangeVarGetRelid(rv, NoLock, false);
1909 :
1910 4018 : 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 42716 : stringToQualifiedNameList(const char *string, Node *escontext)
1923 : {
1924 : char *rawname;
1925 42716 : List *result = NIL;
1926 : List *namelist;
1927 : ListCell *l;
1928 :
1929 : /* We need a modifiable copy of the input string. */
1930 42716 : rawname = pstrdup(string);
1931 :
1932 42716 : if (!SplitIdentifierString(rawname, '.', &namelist))
1933 0 : ereturn(escontext, NIL,
1934 : (errcode(ERRCODE_INVALID_NAME),
1935 : errmsg("invalid name syntax")));
1936 :
1937 42716 : if (namelist == NIL)
1938 0 : ereturn(escontext, NIL,
1939 : (errcode(ERRCODE_INVALID_NAME),
1940 : errmsg("invalid name syntax")));
1941 :
1942 108914 : foreach(l, namelist)
1943 : {
1944 66198 : char *curname = (char *) lfirst(l);
1945 :
1946 66198 : result = lappend(result, makeString(pstrdup(curname)));
1947 : }
1948 :
1949 42716 : pfree(rawname);
1950 42716 : list_free(namelist);
1951 :
1952 42716 : 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 830890 : parseNumericOid(char *string, Oid *result, Node *escontext)
1969 : {
1970 830890 : if (string[0] >= '0' && string[0] <= '9' &&
1971 792690 : strspn(string, "0123456789") == strlen(string))
1972 : {
1973 : Datum oid_datum;
1974 :
1975 : /* We need not care here whether oidin() fails or not. */
1976 792690 : (void) DirectInputFunctionCallSafe(oidin, string,
1977 : InvalidOid, -1,
1978 : escontext,
1979 : &oid_datum);
1980 792690 : *result = DatumGetObjectId(oid_datum);
1981 792690 : return true;
1982 : }
1983 :
1984 : /* Prevent uninitialized-variable warnings from stupider compilers. */
1985 38200 : *result = InvalidOid;
1986 38200 : return false;
1987 : }
1988 :
1989 : /*
1990 : * As above, but also accept "-" as meaning 0 (InvalidOid).
1991 : */
1992 : static bool
1993 1022754 : parseDashOrOid(char *string, Oid *result, Node *escontext)
1994 : {
1995 : /* '-' ? */
1996 1022754 : if (strcmp(string, "-") == 0)
1997 : {
1998 192008 : *result = InvalidOid;
1999 192008 : return true;
2000 : }
2001 :
2002 : /* Numeric OID? */
2003 830746 : 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 584 : 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 584 : rawname = pstrdup(string);
2036 :
2037 : /* Scan to find the expected left paren; mustn't be quoted */
2038 584 : in_quote = false;
2039 10280 : for (ptr = rawname; *ptr; ptr++)
2040 : {
2041 10274 : if (*ptr == '"')
2042 0 : in_quote = !in_quote;
2043 10274 : else if (*ptr == '(' && !in_quote)
2044 578 : break;
2045 : }
2046 584 : if (*ptr == '\0')
2047 6 : 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 578 : *ptr++ = '\0';
2053 578 : *names = stringToQualifiedNameList(rawname, escontext);
2054 578 : if (*names == NIL)
2055 0 : return false;
2056 :
2057 : /* Check for the trailing right parenthesis and remove it */
2058 578 : ptr2 = ptr + strlen(ptr);
2059 596 : while (--ptr2 > ptr)
2060 : {
2061 502 : if (!scanner_isspace(*ptr2))
2062 484 : break;
2063 : }
2064 578 : if (*ptr2 != ')')
2065 6 : ereturn(escontext, false,
2066 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2067 : errmsg("expected a right parenthesis")));
2068 :
2069 572 : *ptr2 = '\0';
2070 :
2071 : /* Separate the remaining string into comma-separated type names */
2072 572 : *nargs = 0;
2073 572 : had_comma = false;
2074 :
2075 : for (;;)
2076 : {
2077 : /* allow leading whitespace */
2078 1188 : while (scanner_isspace(*ptr))
2079 30 : ptr++;
2080 1158 : if (*ptr == '\0')
2081 : {
2082 : /* End of string. Okay unless we had a comma before. */
2083 572 : if (had_comma)
2084 0 : ereturn(escontext, false,
2085 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2086 : errmsg("expected a type name")));
2087 572 : break;
2088 : }
2089 586 : typename = ptr;
2090 : /* Find end of type name --- end of string or comma */
2091 : /* ... but not a quoted or parenthesized comma */
2092 586 : in_quote = false;
2093 586 : paren_count = 0;
2094 5280 : for (; *ptr; ptr++)
2095 : {
2096 4802 : if (*ptr == '"')
2097 0 : in_quote = !in_quote;
2098 4802 : else if (*ptr == ',' && !in_quote && paren_count == 0)
2099 : break;
2100 4694 : else if (!in_quote)
2101 : {
2102 4694 : 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 586 : if (in_quote || paren_count != 0)
2116 0 : ereturn(escontext, false,
2117 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2118 : errmsg("improper type name")));
2119 :
2120 586 : ptr2 = ptr;
2121 586 : if (*ptr == ',')
2122 : {
2123 108 : had_comma = true;
2124 108 : *ptr++ = '\0';
2125 : }
2126 : else
2127 : {
2128 478 : had_comma = false;
2129 : Assert(*ptr == '\0');
2130 : }
2131 : /* Lop off trailing whitespace */
2132 586 : while (--ptr2 >= typename)
2133 : {
2134 586 : if (!scanner_isspace(*ptr2))
2135 586 : break;
2136 0 : *ptr2 = '\0';
2137 : }
2138 :
2139 586 : 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 586 : if (!parseTypeString(typename, &typeid, &typmod, escontext))
2149 0 : return false;
2150 : }
2151 586 : if (*nargs >= FUNC_MAX_ARGS)
2152 0 : ereturn(escontext, false,
2153 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2154 : errmsg("too many arguments")));
2155 :
2156 586 : argtypes[*nargs] = typeid;
2157 586 : (*nargs)++;
2158 : }
2159 :
2160 572 : pfree(rawname);
2161 :
2162 572 : return true;
2163 : }
|