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