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