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
regprocin(PG_FUNCTION_ARGS)61 regprocin(PG_FUNCTION_ARGS)
62 {
63 	char	   *pro_name_or_oid = PG_GETARG_CSTRING(0);
64 	RegProcedure result = InvalidOid;
65 	List	   *names;
66 	FuncCandidateList clist;
67 
68 	/* '-' ? */
69 	if (strcmp(pro_name_or_oid, "-") == 0)
70 		PG_RETURN_OID(InvalidOid);
71 
72 	/* Numeric OID? */
73 	if (pro_name_or_oid[0] >= '0' &&
74 		pro_name_or_oid[0] <= '9' &&
75 		strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
76 	{
77 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
78 													  CStringGetDatum(pro_name_or_oid)));
79 		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 	if (IsBootstrapProcessingMode())
89 		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 	names = stringToQualifiedNameList(pro_name_or_oid);
96 	clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, false);
97 
98 	if (clist == NULL)
99 		ereport(ERROR,
100 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
101 				 errmsg("function \"%s\" does not exist", pro_name_or_oid)));
102 	else if (clist->next != NULL)
103 		ereport(ERROR,
104 				(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
105 				 errmsg("more than one function named \"%s\"",
106 						pro_name_or_oid)));
107 
108 	result = clist->oid;
109 
110 	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
to_regproc(PG_FUNCTION_ARGS)119 to_regproc(PG_FUNCTION_ARGS)
120 {
121 	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 	names = stringToQualifiedNameList(pro_name);
130 	clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true);
131 
132 	if (clist == NULL || clist->next != NULL)
133 		PG_RETURN_NULL();
134 
135 	PG_RETURN_OID(clist->oid);
136 }
137 
138 /*
139  * regprocout		- converts proc OID to "pro_name"
140  */
141 Datum
regprocout(PG_FUNCTION_ARGS)142 regprocout(PG_FUNCTION_ARGS)
143 {
144 	RegProcedure proid = PG_GETARG_OID(0);
145 	char	   *result;
146 	HeapTuple	proctup;
147 
148 	if (proid == InvalidOid)
149 	{
150 		result = pstrdup("-");
151 		PG_RETURN_CSTRING(result);
152 	}
153 
154 	proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
155 
156 	if (HeapTupleIsValid(proctup))
157 	{
158 		Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
159 		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 		if (IsBootstrapProcessingMode())
167 			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 			clist = FuncnameGetCandidates(list_make1(makeString(proname)),
178 										  -1, NIL, false, false, false, false);
179 			if (clist != NULL && clist->next == NULL &&
180 				clist->oid == proid)
181 				nspname = NULL;
182 			else
183 				nspname = get_namespace_name(procform->pronamespace);
184 
185 			result = quote_qualified_identifier(nspname, proname);
186 		}
187 
188 		ReleaseSysCache(proctup);
189 	}
190 	else
191 	{
192 		/* If OID doesn't match any pg_proc entry, return it numerically */
193 		result = (char *) palloc(NAMEDATALEN);
194 		snprintf(result, NAMEDATALEN, "%u", proid);
195 	}
196 
197 	PG_RETURN_CSTRING(result);
198 }
199 
200 /*
201  *		regprocrecv			- converts external binary format to regproc
202  */
203 Datum
regprocrecv(PG_FUNCTION_ARGS)204 regprocrecv(PG_FUNCTION_ARGS)
205 {
206 	/* Exactly the same as oidrecv, so share code */
207 	return oidrecv(fcinfo);
208 }
209 
210 /*
211  *		regprocsend			- converts regproc to binary format
212  */
213 Datum
regprocsend(PG_FUNCTION_ARGS)214 regprocsend(PG_FUNCTION_ARGS)
215 {
216 	/* Exactly the same as oidsend, so share code */
217 	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
regprocedurein(PG_FUNCTION_ARGS)230 regprocedurein(PG_FUNCTION_ARGS)
231 {
232 	char	   *pro_name_or_oid = PG_GETARG_CSTRING(0);
233 	RegProcedure result = InvalidOid;
234 	List	   *names;
235 	int			nargs;
236 	Oid			argtypes[FUNC_MAX_ARGS];
237 	FuncCandidateList clist;
238 
239 	/* '-' ? */
240 	if (strcmp(pro_name_or_oid, "-") == 0)
241 		PG_RETURN_OID(InvalidOid);
242 
243 	/* Numeric OID? */
244 	if (pro_name_or_oid[0] >= '0' &&
245 		pro_name_or_oid[0] <= '9' &&
246 		strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
247 	{
248 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
249 													  CStringGetDatum(pro_name_or_oid)));
250 		PG_RETURN_OID(result);
251 	}
252 
253 	/* The rest of this wouldn't work in bootstrap mode */
254 	if (IsBootstrapProcessingMode())
255 		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 	parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
264 
265 	clist = FuncnameGetCandidates(names, nargs, NIL, false, false,
266 								  false, false);
267 
268 	for (; clist; clist = clist->next)
269 	{
270 		if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
271 			break;
272 	}
273 
274 	if (clist == NULL)
275 		ereport(ERROR,
276 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
277 				 errmsg("function \"%s\" does not exist", pro_name_or_oid)));
278 
279 	result = clist->oid;
280 
281 	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
to_regprocedure(PG_FUNCTION_ARGS)290 to_regprocedure(PG_FUNCTION_ARGS)
291 {
292 	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 	parseNameAndArgTypes(pro_name, false, &names, &nargs, argtypes);
304 
305 	clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false, true);
306 
307 	for (; clist; clist = clist->next)
308 	{
309 		if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
310 			PG_RETURN_OID(clist->oid);
311 	}
312 
313 	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 *
format_procedure(Oid procedure_oid)323 format_procedure(Oid procedure_oid)
324 {
325 	return format_procedure_extended(procedure_oid, 0);
326 }
327 
328 char *
format_procedure_qualified(Oid procedure_oid)329 format_procedure_qualified(Oid procedure_oid)
330 {
331 	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 *
format_procedure_extended(Oid procedure_oid,bits16 flags)350 format_procedure_extended(Oid procedure_oid, bits16 flags)
351 {
352 	char	   *result;
353 	HeapTuple	proctup;
354 
355 	proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
356 
357 	if (HeapTupleIsValid(proctup))
358 	{
359 		Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
360 		char	   *proname = NameStr(procform->proname);
361 		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 		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 		if ((flags & FORMAT_PROC_FORCE_QUALIFY) == 0 &&
376 			FunctionIsVisible(procedure_oid))
377 			nspname = NULL;
378 		else
379 			nspname = get_namespace_name(procform->pronamespace);
380 
381 		appendStringInfo(&buf, "%s(",
382 						 quote_qualified_identifier(nspname, proname));
383 		for (i = 0; i < nargs; i++)
384 		{
385 			Oid			thisargtype = procform->proargtypes.values[i];
386 
387 			if (i > 0)
388 				appendStringInfoChar(&buf, ',');
389 			appendStringInfoString(&buf,
390 								   (flags & FORMAT_PROC_FORCE_QUALIFY) != 0 ?
391 								   format_type_be_qualified(thisargtype) :
392 								   format_type_be(thisargtype));
393 		}
394 		appendStringInfoChar(&buf, ')');
395 
396 		result = buf.data;
397 
398 		ReleaseSysCache(proctup);
399 	}
400 	else if ((flags & FORMAT_PROC_INVALID_AS_NULL) != 0)
401 	{
402 		/* If object is undefined, return NULL as wanted by caller */
403 		result = NULL;
404 	}
405 	else
406 	{
407 		/* If OID doesn't match any pg_proc entry, return it numerically */
408 		result = (char *) palloc(NAMEDATALEN);
409 		snprintf(result, NAMEDATALEN, "%u", procedure_oid);
410 	}
411 
412 	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
format_procedure_parts(Oid procedure_oid,List ** objnames,List ** objargs,bool missing_ok)422 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 	proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
431 
432 	if (!HeapTupleIsValid(proctup))
433 	{
434 		if (!missing_ok)
435 			elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
436 		return;
437 	}
438 
439 	procform = (Form_pg_proc) GETSTRUCT(proctup);
440 	nargs = procform->pronargs;
441 
442 	*objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
443 						   pstrdup(NameStr(procform->proname)));
444 	*objargs = NIL;
445 	for (i = 0; i < nargs; i++)
446 	{
447 		Oid			thisargtype = procform->proargtypes.values[i];
448 
449 		*objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
450 	}
451 
452 	ReleaseSysCache(proctup);
453 }
454 
455 /*
456  * regprocedureout		- converts proc OID to "pro_name(args)"
457  */
458 Datum
regprocedureout(PG_FUNCTION_ARGS)459 regprocedureout(PG_FUNCTION_ARGS)
460 {
461 	RegProcedure proid = PG_GETARG_OID(0);
462 	char	   *result;
463 
464 	if (proid == InvalidOid)
465 		result = pstrdup("-");
466 	else
467 		result = format_procedure(proid);
468 
469 	PG_RETURN_CSTRING(result);
470 }
471 
472 /*
473  *		regprocedurerecv			- converts external binary format to regprocedure
474  */
475 Datum
regprocedurerecv(PG_FUNCTION_ARGS)476 regprocedurerecv(PG_FUNCTION_ARGS)
477 {
478 	/* Exactly the same as oidrecv, so share code */
479 	return oidrecv(fcinfo);
480 }
481 
482 /*
483  *		regproceduresend			- converts regprocedure to binary format
484  */
485 Datum
regproceduresend(PG_FUNCTION_ARGS)486 regproceduresend(PG_FUNCTION_ARGS)
487 {
488 	/* Exactly the same as oidsend, so share code */
489 	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
regoperin(PG_FUNCTION_ARGS)502 regoperin(PG_FUNCTION_ARGS)
503 {
504 	char	   *opr_name_or_oid = PG_GETARG_CSTRING(0);
505 	Oid			result = InvalidOid;
506 	List	   *names;
507 	FuncCandidateList clist;
508 
509 	/* '0' ? */
510 	if (strcmp(opr_name_or_oid, "0") == 0)
511 		PG_RETURN_OID(InvalidOid);
512 
513 	/* Numeric OID? */
514 	if (opr_name_or_oid[0] >= '0' &&
515 		opr_name_or_oid[0] <= '9' &&
516 		strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
517 	{
518 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
519 													  CStringGetDatum(opr_name_or_oid)));
520 		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 	if (IsBootstrapProcessingMode())
527 		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 	names = stringToQualifiedNameList(opr_name_or_oid);
534 	clist = OpernameGetCandidates(names, '\0', false);
535 
536 	if (clist == NULL)
537 		ereport(ERROR,
538 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
539 				 errmsg("operator does not exist: %s", opr_name_or_oid)));
540 	else if (clist->next != NULL)
541 		ereport(ERROR,
542 				(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
543 				 errmsg("more than one operator named %s",
544 						opr_name_or_oid)));
545 
546 	result = clist->oid;
547 
548 	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
to_regoper(PG_FUNCTION_ARGS)557 to_regoper(PG_FUNCTION_ARGS)
558 {
559 	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 	names = stringToQualifiedNameList(opr_name);
568 	clist = OpernameGetCandidates(names, '\0', true);
569 
570 	if (clist == NULL || clist->next != NULL)
571 		PG_RETURN_NULL();
572 
573 	PG_RETURN_OID(clist->oid);
574 }
575 
576 /*
577  * regoperout		- converts operator OID to "opr_name"
578  */
579 Datum
regoperout(PG_FUNCTION_ARGS)580 regoperout(PG_FUNCTION_ARGS)
581 {
582 	Oid			oprid = PG_GETARG_OID(0);
583 	char	   *result;
584 	HeapTuple	opertup;
585 
586 	if (oprid == InvalidOid)
587 	{
588 		result = pstrdup("0");
589 		PG_RETURN_CSTRING(result);
590 	}
591 
592 	opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
593 
594 	if (HeapTupleIsValid(opertup))
595 	{
596 		Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
597 		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 		if (IsBootstrapProcessingMode())
605 			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 			clist = OpernameGetCandidates(list_make1(makeString(oprname)),
615 										  '\0', false);
616 			if (clist != NULL && clist->next == NULL &&
617 				clist->oid == oprid)
618 				result = pstrdup(oprname);
619 			else
620 			{
621 				const char *nspname;
622 
623 				nspname = get_namespace_name(operform->oprnamespace);
624 				nspname = quote_identifier(nspname);
625 				result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2);
626 				sprintf(result, "%s.%s", nspname, oprname);
627 			}
628 		}
629 
630 		ReleaseSysCache(opertup);
631 	}
632 	else
633 	{
634 		/*
635 		 * If OID doesn't match any pg_operator entry, return it numerically
636 		 */
637 		result = (char *) palloc(NAMEDATALEN);
638 		snprintf(result, NAMEDATALEN, "%u", oprid);
639 	}
640 
641 	PG_RETURN_CSTRING(result);
642 }
643 
644 /*
645  *		regoperrecv			- converts external binary format to regoper
646  */
647 Datum
regoperrecv(PG_FUNCTION_ARGS)648 regoperrecv(PG_FUNCTION_ARGS)
649 {
650 	/* Exactly the same as oidrecv, so share code */
651 	return oidrecv(fcinfo);
652 }
653 
654 /*
655  *		regopersend			- converts regoper to binary format
656  */
657 Datum
regopersend(PG_FUNCTION_ARGS)658 regopersend(PG_FUNCTION_ARGS)
659 {
660 	/* Exactly the same as oidsend, so share code */
661 	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
regoperatorin(PG_FUNCTION_ARGS)674 regoperatorin(PG_FUNCTION_ARGS)
675 {
676 	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 	if (strcmp(opr_name_or_oid, "0") == 0)
684 		PG_RETURN_OID(InvalidOid);
685 
686 	/* Numeric OID? */
687 	if (opr_name_or_oid[0] >= '0' &&
688 		opr_name_or_oid[0] <= '9' &&
689 		strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
690 	{
691 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
692 													  CStringGetDatum(opr_name_or_oid)));
693 		PG_RETURN_OID(result);
694 	}
695 
696 	/* The rest of this wouldn't work in bootstrap mode */
697 	if (IsBootstrapProcessingMode())
698 		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 	parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes);
707 	if (nargs == 1)
708 		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 	if (nargs != 2)
713 		ereport(ERROR,
714 				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
715 				 errmsg("too many arguments"),
716 				 errhint("Provide two argument types for operator.")));
717 
718 	result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
719 
720 	if (!OidIsValid(result))
721 		ereport(ERROR,
722 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
723 				 errmsg("operator does not exist: %s", opr_name_or_oid)));
724 
725 	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
to_regoperator(PG_FUNCTION_ARGS)734 to_regoperator(PG_FUNCTION_ARGS)
735 {
736 	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 	parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes);
748 	if (nargs == 1)
749 		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 	if (nargs != 2)
754 		ereport(ERROR,
755 				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
756 				 errmsg("too many arguments"),
757 				 errhint("Provide two argument types for operator.")));
758 
759 	result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
760 
761 	if (!OidIsValid(result))
762 		PG_RETURN_NULL();
763 
764 	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 *
format_operator_extended(Oid operator_oid,bits16 flags)781 format_operator_extended(Oid operator_oid, bits16 flags)
782 {
783 	char	   *result;
784 	HeapTuple	opertup;
785 
786 	opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
787 
788 	if (HeapTupleIsValid(opertup))
789 	{
790 		Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
791 		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 		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 		if ((flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ||
805 			!OperatorIsVisible(operator_oid))
806 		{
807 			nspname = get_namespace_name(operform->oprnamespace);
808 			appendStringInfo(&buf, "%s.",
809 							 quote_identifier(nspname));
810 		}
811 
812 		appendStringInfo(&buf, "%s(", oprname);
813 
814 		if (operform->oprleft)
815 			appendStringInfo(&buf, "%s,",
816 							 (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
817 							 format_type_be_qualified(operform->oprleft) :
818 							 format_type_be(operform->oprleft));
819 		else
820 			appendStringInfoString(&buf, "NONE,");
821 
822 		if (operform->oprright)
823 			appendStringInfo(&buf, "%s)",
824 							 (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
825 							 format_type_be_qualified(operform->oprright) :
826 							 format_type_be(operform->oprright));
827 		else
828 			appendStringInfoString(&buf, "NONE)");
829 
830 		result = buf.data;
831 
832 		ReleaseSysCache(opertup);
833 	}
834 	else if ((flags & FORMAT_OPERATOR_INVALID_AS_NULL) != 0)
835 	{
836 		/* If object is undefined, return NULL as wanted by caller */
837 		result = NULL;
838 	}
839 	else
840 	{
841 		/*
842 		 * If OID doesn't match any pg_operator entry, return it numerically
843 		 */
844 		result = (char *) palloc(NAMEDATALEN);
845 		snprintf(result, NAMEDATALEN, "%u", operator_oid);
846 	}
847 
848 	return result;
849 }
850 
851 char *
format_operator(Oid operator_oid)852 format_operator(Oid operator_oid)
853 {
854 	return format_operator_extended(operator_oid, 0);
855 }
856 
857 char *
format_operator_qualified(Oid operator_oid)858 format_operator_qualified(Oid operator_oid)
859 {
860 	return format_operator_extended(operator_oid,
861 									FORMAT_OPERATOR_FORCE_QUALIFY);
862 }
863 
864 void
format_operator_parts(Oid operator_oid,List ** objnames,List ** objargs,bool missing_ok)865 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 	opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
872 	if (!HeapTupleIsValid(opertup))
873 	{
874 		if (!missing_ok)
875 			elog(ERROR, "cache lookup failed for operator with OID %u",
876 				 operator_oid);
877 		return;
878 	}
879 
880 	oprForm = (Form_pg_operator) GETSTRUCT(opertup);
881 	*objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
882 						   pstrdup(NameStr(oprForm->oprname)));
883 	*objargs = NIL;
884 	if (oprForm->oprleft)
885 		*objargs = lappend(*objargs,
886 						   format_type_be_qualified(oprForm->oprleft));
887 	if (oprForm->oprright)
888 		*objargs = lappend(*objargs,
889 						   format_type_be_qualified(oprForm->oprright));
890 
891 	ReleaseSysCache(opertup);
892 }
893 
894 /*
895  * regoperatorout		- converts operator OID to "opr_name(args)"
896  */
897 Datum
regoperatorout(PG_FUNCTION_ARGS)898 regoperatorout(PG_FUNCTION_ARGS)
899 {
900 	Oid			oprid = PG_GETARG_OID(0);
901 	char	   *result;
902 
903 	if (oprid == InvalidOid)
904 		result = pstrdup("0");
905 	else
906 		result = format_operator(oprid);
907 
908 	PG_RETURN_CSTRING(result);
909 }
910 
911 /*
912  *		regoperatorrecv			- converts external binary format to regoperator
913  */
914 Datum
regoperatorrecv(PG_FUNCTION_ARGS)915 regoperatorrecv(PG_FUNCTION_ARGS)
916 {
917 	/* Exactly the same as oidrecv, so share code */
918 	return oidrecv(fcinfo);
919 }
920 
921 /*
922  *		regoperatorsend			- converts regoperator to binary format
923  */
924 Datum
regoperatorsend(PG_FUNCTION_ARGS)925 regoperatorsend(PG_FUNCTION_ARGS)
926 {
927 	/* Exactly the same as oidsend, so share code */
928 	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
regclassin(PG_FUNCTION_ARGS)941 regclassin(PG_FUNCTION_ARGS)
942 {
943 	char	   *class_name_or_oid = PG_GETARG_CSTRING(0);
944 	Oid			result = InvalidOid;
945 	List	   *names;
946 
947 	/* '-' ? */
948 	if (strcmp(class_name_or_oid, "-") == 0)
949 		PG_RETURN_OID(InvalidOid);
950 
951 	/* Numeric OID? */
952 	if (class_name_or_oid[0] >= '0' &&
953 		class_name_or_oid[0] <= '9' &&
954 		strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
955 	{
956 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
957 													  CStringGetDatum(class_name_or_oid)));
958 		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 	if (IsBootstrapProcessingMode())
965 		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 	names = stringToQualifiedNameList(class_name_or_oid);
972 
973 	/* We might not even have permissions on this relation; don't lock it. */
974 	result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false);
975 
976 	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
to_regclass(PG_FUNCTION_ARGS)985 to_regclass(PG_FUNCTION_ARGS)
986 {
987 	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 	names = stringToQualifiedNameList(class_name);
996 
997 	/* We might not even have permissions on this relation; don't lock it. */
998 	result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
999 
1000 	if (OidIsValid(result))
1001 		PG_RETURN_OID(result);
1002 	else
1003 		PG_RETURN_NULL();
1004 }
1005 
1006 /*
1007  * regclassout		- converts class OID to "class_name"
1008  */
1009 Datum
regclassout(PG_FUNCTION_ARGS)1010 regclassout(PG_FUNCTION_ARGS)
1011 {
1012 	Oid			classid = PG_GETARG_OID(0);
1013 	char	   *result;
1014 	HeapTuple	classtup;
1015 
1016 	if (classid == InvalidOid)
1017 	{
1018 		result = pstrdup("-");
1019 		PG_RETURN_CSTRING(result);
1020 	}
1021 
1022 	classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
1023 
1024 	if (HeapTupleIsValid(classtup))
1025 	{
1026 		Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
1027 		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 		if (IsBootstrapProcessingMode())
1035 			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 			if (RelationIsVisible(classid))
1044 				nspname = NULL;
1045 			else
1046 				nspname = get_namespace_name(classform->relnamespace);
1047 
1048 			result = quote_qualified_identifier(nspname, classname);
1049 		}
1050 
1051 		ReleaseSysCache(classtup);
1052 	}
1053 	else
1054 	{
1055 		/* If OID doesn't match any pg_class entry, return it numerically */
1056 		result = (char *) palloc(NAMEDATALEN);
1057 		snprintf(result, NAMEDATALEN, "%u", classid);
1058 	}
1059 
1060 	PG_RETURN_CSTRING(result);
1061 }
1062 
1063 /*
1064  *		regclassrecv			- converts external binary format to regclass
1065  */
1066 Datum
regclassrecv(PG_FUNCTION_ARGS)1067 regclassrecv(PG_FUNCTION_ARGS)
1068 {
1069 	/* Exactly the same as oidrecv, so share code */
1070 	return oidrecv(fcinfo);
1071 }
1072 
1073 /*
1074  *		regclasssend			- converts regclass to binary format
1075  */
1076 Datum
regclasssend(PG_FUNCTION_ARGS)1077 regclasssend(PG_FUNCTION_ARGS)
1078 {
1079 	/* Exactly the same as oidsend, so share code */
1080 	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
regcollationin(PG_FUNCTION_ARGS)1093 regcollationin(PG_FUNCTION_ARGS)
1094 {
1095 	char	   *collation_name_or_oid = PG_GETARG_CSTRING(0);
1096 	Oid			result = InvalidOid;
1097 	List	   *names;
1098 
1099 	/* '-' ? */
1100 	if (strcmp(collation_name_or_oid, "-") == 0)
1101 		PG_RETURN_OID(InvalidOid);
1102 
1103 	/* Numeric OID? */
1104 	if (collation_name_or_oid[0] >= '0' &&
1105 		collation_name_or_oid[0] <= '9' &&
1106 		strspn(collation_name_or_oid, "0123456789") == strlen(collation_name_or_oid))
1107 	{
1108 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
1109 													  CStringGetDatum(collation_name_or_oid)));
1110 		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 	if (IsBootstrapProcessingMode())
1117 		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 	names = stringToQualifiedNameList(collation_name_or_oid);
1124 
1125 	result = get_collation_oid(names, false);
1126 
1127 	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
to_regcollation(PG_FUNCTION_ARGS)1136 to_regcollation(PG_FUNCTION_ARGS)
1137 {
1138 	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 	names = stringToQualifiedNameList(collation_name);
1147 
1148 	/* We might not even have permissions on this relation; don't lock it. */
1149 	result = get_collation_oid(names, true);
1150 
1151 	if (OidIsValid(result))
1152 		PG_RETURN_OID(result);
1153 	else
1154 		PG_RETURN_NULL();
1155 }
1156 
1157 /*
1158  * regcollationout		- converts collation OID to "collation_name"
1159  */
1160 Datum
regcollationout(PG_FUNCTION_ARGS)1161 regcollationout(PG_FUNCTION_ARGS)
1162 {
1163 	Oid			collationid = PG_GETARG_OID(0);
1164 	char	   *result;
1165 	HeapTuple	collationtup;
1166 
1167 	if (collationid == InvalidOid)
1168 	{
1169 		result = pstrdup("-");
1170 		PG_RETURN_CSTRING(result);
1171 	}
1172 
1173 	collationtup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationid));
1174 
1175 	if (HeapTupleIsValid(collationtup))
1176 	{
1177 		Form_pg_collation collationform = (Form_pg_collation) GETSTRUCT(collationtup);
1178 		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 		if (IsBootstrapProcessingMode())
1186 			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 			if (CollationIsVisible(collationid))
1196 				nspname = NULL;
1197 			else
1198 				nspname = get_namespace_name(collationform->collnamespace);
1199 
1200 			result = quote_qualified_identifier(nspname, collationname);
1201 		}
1202 
1203 		ReleaseSysCache(collationtup);
1204 	}
1205 	else
1206 	{
1207 		/* If OID doesn't match any pg_collation entry, return it numerically */
1208 		result = (char *) palloc(NAMEDATALEN);
1209 		snprintf(result, NAMEDATALEN, "%u", collationid);
1210 	}
1211 
1212 	PG_RETURN_CSTRING(result);
1213 }
1214 
1215 /*
1216  *		regcollationrecv			- converts external binary format to regcollation
1217  */
1218 Datum
regcollationrecv(PG_FUNCTION_ARGS)1219 regcollationrecv(PG_FUNCTION_ARGS)
1220 {
1221 	/* Exactly the same as oidrecv, so share code */
1222 	return oidrecv(fcinfo);
1223 }
1224 
1225 /*
1226  *		regcollationsend			- converts regcollation to binary format
1227  */
1228 Datum
regcollationsend(PG_FUNCTION_ARGS)1229 regcollationsend(PG_FUNCTION_ARGS)
1230 {
1231 	/* Exactly the same as oidsend, so share code */
1232 	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
regtypein(PG_FUNCTION_ARGS)1251 regtypein(PG_FUNCTION_ARGS)
1252 {
1253 	char	   *typ_name_or_oid = PG_GETARG_CSTRING(0);
1254 	Oid			result = InvalidOid;
1255 	int32		typmod;
1256 
1257 	/* '-' ? */
1258 	if (strcmp(typ_name_or_oid, "-") == 0)
1259 		PG_RETURN_OID(InvalidOid);
1260 
1261 	/* Numeric OID? */
1262 	if (typ_name_or_oid[0] >= '0' &&
1263 		typ_name_or_oid[0] <= '9' &&
1264 		strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
1265 	{
1266 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
1267 													  CStringGetDatum(typ_name_or_oid)));
1268 		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 	if (IsBootstrapProcessingMode())
1275 		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 	parseTypeString(typ_name_or_oid, &result, &typmod, false);
1282 
1283 	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
to_regtype(PG_FUNCTION_ARGS)1292 to_regtype(PG_FUNCTION_ARGS)
1293 {
1294 	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 	parseTypeString(typ_name, &result, &typmod, true);
1302 
1303 	if (OidIsValid(result))
1304 		PG_RETURN_OID(result);
1305 	else
1306 		PG_RETURN_NULL();
1307 }
1308 
1309 /*
1310  * regtypeout		- converts type OID to "typ_name"
1311  */
1312 Datum
regtypeout(PG_FUNCTION_ARGS)1313 regtypeout(PG_FUNCTION_ARGS)
1314 {
1315 	Oid			typid = PG_GETARG_OID(0);
1316 	char	   *result;
1317 	HeapTuple	typetup;
1318 
1319 	if (typid == InvalidOid)
1320 	{
1321 		result = pstrdup("-");
1322 		PG_RETURN_CSTRING(result);
1323 	}
1324 
1325 	typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1326 
1327 	if (HeapTupleIsValid(typetup))
1328 	{
1329 		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 		if (IsBootstrapProcessingMode())
1337 		{
1338 			char	   *typname = NameStr(typeform->typname);
1339 
1340 			result = pstrdup(typname);
1341 		}
1342 		else
1343 			result = format_type_be(typid);
1344 
1345 		ReleaseSysCache(typetup);
1346 	}
1347 	else
1348 	{
1349 		/* If OID doesn't match any pg_type entry, return it numerically */
1350 		result = (char *) palloc(NAMEDATALEN);
1351 		snprintf(result, NAMEDATALEN, "%u", typid);
1352 	}
1353 
1354 	PG_RETURN_CSTRING(result);
1355 }
1356 
1357 /*
1358  *		regtyperecv			- converts external binary format to regtype
1359  */
1360 Datum
regtyperecv(PG_FUNCTION_ARGS)1361 regtyperecv(PG_FUNCTION_ARGS)
1362 {
1363 	/* Exactly the same as oidrecv, so share code */
1364 	return oidrecv(fcinfo);
1365 }
1366 
1367 /*
1368  *		regtypesend			- converts regtype to binary format
1369  */
1370 Datum
regtypesend(PG_FUNCTION_ARGS)1371 regtypesend(PG_FUNCTION_ARGS)
1372 {
1373 	/* Exactly the same as oidsend, so share code */
1374 	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
regconfigin(PG_FUNCTION_ARGS)1387 regconfigin(PG_FUNCTION_ARGS)
1388 {
1389 	char	   *cfg_name_or_oid = PG_GETARG_CSTRING(0);
1390 	Oid			result;
1391 	List	   *names;
1392 
1393 	/* '-' ? */
1394 	if (strcmp(cfg_name_or_oid, "-") == 0)
1395 		PG_RETURN_OID(InvalidOid);
1396 
1397 	/* Numeric OID? */
1398 	if (cfg_name_or_oid[0] >= '0' &&
1399 		cfg_name_or_oid[0] <= '9' &&
1400 		strspn(cfg_name_or_oid, "0123456789") == strlen(cfg_name_or_oid))
1401 	{
1402 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
1403 													  CStringGetDatum(cfg_name_or_oid)));
1404 		PG_RETURN_OID(result);
1405 	}
1406 
1407 	/* The rest of this wouldn't work in bootstrap mode */
1408 	if (IsBootstrapProcessingMode())
1409 		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 	names = stringToQualifiedNameList(cfg_name_or_oid);
1416 
1417 	result = get_ts_config_oid(names, false);
1418 
1419 	PG_RETURN_OID(result);
1420 }
1421 
1422 /*
1423  * regconfigout		- converts tsconfig OID to "tsconfigname"
1424  */
1425 Datum
regconfigout(PG_FUNCTION_ARGS)1426 regconfigout(PG_FUNCTION_ARGS)
1427 {
1428 	Oid			cfgid = PG_GETARG_OID(0);
1429 	char	   *result;
1430 	HeapTuple	cfgtup;
1431 
1432 	if (cfgid == InvalidOid)
1433 	{
1434 		result = pstrdup("-");
1435 		PG_RETURN_CSTRING(result);
1436 	}
1437 
1438 	cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
1439 
1440 	if (HeapTupleIsValid(cfgtup))
1441 	{
1442 		Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
1443 		char	   *cfgname = NameStr(cfgform->cfgname);
1444 		char	   *nspname;
1445 
1446 		/*
1447 		 * Would this config be found by regconfigin? If not, qualify it.
1448 		 */
1449 		if (TSConfigIsVisible(cfgid))
1450 			nspname = NULL;
1451 		else
1452 			nspname = get_namespace_name(cfgform->cfgnamespace);
1453 
1454 		result = quote_qualified_identifier(nspname, cfgname);
1455 
1456 		ReleaseSysCache(cfgtup);
1457 	}
1458 	else
1459 	{
1460 		/* If OID doesn't match any pg_ts_config row, return it numerically */
1461 		result = (char *) palloc(NAMEDATALEN);
1462 		snprintf(result, NAMEDATALEN, "%u", cfgid);
1463 	}
1464 
1465 	PG_RETURN_CSTRING(result);
1466 }
1467 
1468 /*
1469  *		regconfigrecv			- converts external binary format to regconfig
1470  */
1471 Datum
regconfigrecv(PG_FUNCTION_ARGS)1472 regconfigrecv(PG_FUNCTION_ARGS)
1473 {
1474 	/* Exactly the same as oidrecv, so share code */
1475 	return oidrecv(fcinfo);
1476 }
1477 
1478 /*
1479  *		regconfigsend			- converts regconfig to binary format
1480  */
1481 Datum
regconfigsend(PG_FUNCTION_ARGS)1482 regconfigsend(PG_FUNCTION_ARGS)
1483 {
1484 	/* Exactly the same as oidsend, so share code */
1485 	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
regdictionaryin(PG_FUNCTION_ARGS)1498 regdictionaryin(PG_FUNCTION_ARGS)
1499 {
1500 	char	   *dict_name_or_oid = PG_GETARG_CSTRING(0);
1501 	Oid			result;
1502 	List	   *names;
1503 
1504 	/* '-' ? */
1505 	if (strcmp(dict_name_or_oid, "-") == 0)
1506 		PG_RETURN_OID(InvalidOid);
1507 
1508 	/* Numeric OID? */
1509 	if (dict_name_or_oid[0] >= '0' &&
1510 		dict_name_or_oid[0] <= '9' &&
1511 		strspn(dict_name_or_oid, "0123456789") == strlen(dict_name_or_oid))
1512 	{
1513 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
1514 													  CStringGetDatum(dict_name_or_oid)));
1515 		PG_RETURN_OID(result);
1516 	}
1517 
1518 	/* The rest of this wouldn't work in bootstrap mode */
1519 	if (IsBootstrapProcessingMode())
1520 		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 	names = stringToQualifiedNameList(dict_name_or_oid);
1527 
1528 	result = get_ts_dict_oid(names, false);
1529 
1530 	PG_RETURN_OID(result);
1531 }
1532 
1533 /*
1534  * regdictionaryout		- converts tsdictionary OID to "tsdictionaryname"
1535  */
1536 Datum
regdictionaryout(PG_FUNCTION_ARGS)1537 regdictionaryout(PG_FUNCTION_ARGS)
1538 {
1539 	Oid			dictid = PG_GETARG_OID(0);
1540 	char	   *result;
1541 	HeapTuple	dicttup;
1542 
1543 	if (dictid == InvalidOid)
1544 	{
1545 		result = pstrdup("-");
1546 		PG_RETURN_CSTRING(result);
1547 	}
1548 
1549 	dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
1550 
1551 	if (HeapTupleIsValid(dicttup))
1552 	{
1553 		Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
1554 		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 		if (TSDictionaryIsVisible(dictid))
1562 			nspname = NULL;
1563 		else
1564 			nspname = get_namespace_name(dictform->dictnamespace);
1565 
1566 		result = quote_qualified_identifier(nspname, dictname);
1567 
1568 		ReleaseSysCache(dicttup);
1569 	}
1570 	else
1571 	{
1572 		/* If OID doesn't match any pg_ts_dict row, return it numerically */
1573 		result = (char *) palloc(NAMEDATALEN);
1574 		snprintf(result, NAMEDATALEN, "%u", dictid);
1575 	}
1576 
1577 	PG_RETURN_CSTRING(result);
1578 }
1579 
1580 /*
1581  *		regdictionaryrecv	- converts external binary format to regdictionary
1582  */
1583 Datum
regdictionaryrecv(PG_FUNCTION_ARGS)1584 regdictionaryrecv(PG_FUNCTION_ARGS)
1585 {
1586 	/* Exactly the same as oidrecv, so share code */
1587 	return oidrecv(fcinfo);
1588 }
1589 
1590 /*
1591  *		regdictionarysend	- converts regdictionary to binary format
1592  */
1593 Datum
regdictionarysend(PG_FUNCTION_ARGS)1594 regdictionarysend(PG_FUNCTION_ARGS)
1595 {
1596 	/* Exactly the same as oidsend, so share code */
1597 	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
regrolein(PG_FUNCTION_ARGS)1609 regrolein(PG_FUNCTION_ARGS)
1610 {
1611 	char	   *role_name_or_oid = PG_GETARG_CSTRING(0);
1612 	Oid			result;
1613 	List	   *names;
1614 
1615 	/* '-' ? */
1616 	if (strcmp(role_name_or_oid, "-") == 0)
1617 		PG_RETURN_OID(InvalidOid);
1618 
1619 	/* Numeric OID? */
1620 	if (role_name_or_oid[0] >= '0' &&
1621 		role_name_or_oid[0] <= '9' &&
1622 		strspn(role_name_or_oid, "0123456789") == strlen(role_name_or_oid))
1623 	{
1624 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
1625 													  CStringGetDatum(role_name_or_oid)));
1626 		PG_RETURN_OID(result);
1627 	}
1628 
1629 	/* The rest of this wouldn't work in bootstrap mode */
1630 	if (IsBootstrapProcessingMode())
1631 		elog(ERROR, "regrole values must be OIDs in bootstrap mode");
1632 
1633 	/* Normal case: see if the name matches any pg_authid entry. */
1634 	names = stringToQualifiedNameList(role_name_or_oid);
1635 
1636 	if (list_length(names) != 1)
1637 		ereport(ERROR,
1638 				(errcode(ERRCODE_INVALID_NAME),
1639 				 errmsg("invalid name syntax")));
1640 
1641 	result = get_role_oid(strVal(linitial(names)), false);
1642 
1643 	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
to_regrole(PG_FUNCTION_ARGS)1652 to_regrole(PG_FUNCTION_ARGS)
1653 {
1654 	char	   *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1655 	Oid			result;
1656 	List	   *names;
1657 
1658 	names = stringToQualifiedNameList(role_name);
1659 
1660 	if (list_length(names) != 1)
1661 		ereport(ERROR,
1662 				(errcode(ERRCODE_INVALID_NAME),
1663 				 errmsg("invalid name syntax")));
1664 
1665 	result = get_role_oid(strVal(linitial(names)), true);
1666 
1667 	if (OidIsValid(result))
1668 		PG_RETURN_OID(result);
1669 	else
1670 		PG_RETURN_NULL();
1671 }
1672 
1673 /*
1674  * regroleout		- converts role OID to "role_name"
1675  */
1676 Datum
regroleout(PG_FUNCTION_ARGS)1677 regroleout(PG_FUNCTION_ARGS)
1678 {
1679 	Oid			roleoid = PG_GETARG_OID(0);
1680 	char	   *result;
1681 
1682 	if (roleoid == InvalidOid)
1683 	{
1684 		result = pstrdup("-");
1685 		PG_RETURN_CSTRING(result);
1686 	}
1687 
1688 	result = GetUserNameFromId(roleoid, true);
1689 
1690 	if (result)
1691 	{
1692 		/* pstrdup is not really necessary, but it avoids a compiler warning */
1693 		result = pstrdup(quote_identifier(result));
1694 	}
1695 	else
1696 	{
1697 		/* If OID doesn't match any role, return it numerically */
1698 		result = (char *) palloc(NAMEDATALEN);
1699 		snprintf(result, NAMEDATALEN, "%u", roleoid);
1700 	}
1701 
1702 	PG_RETURN_CSTRING(result);
1703 }
1704 
1705 /*
1706  *		regrolerecv - converts external binary format to regrole
1707  */
1708 Datum
regrolerecv(PG_FUNCTION_ARGS)1709 regrolerecv(PG_FUNCTION_ARGS)
1710 {
1711 	/* Exactly the same as oidrecv, so share code */
1712 	return oidrecv(fcinfo);
1713 }
1714 
1715 /*
1716  *		regrolesend - converts regrole to binary format
1717  */
1718 Datum
regrolesend(PG_FUNCTION_ARGS)1719 regrolesend(PG_FUNCTION_ARGS)
1720 {
1721 	/* Exactly the same as oidsend, so share code */
1722 	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
regnamespacein(PG_FUNCTION_ARGS)1734 regnamespacein(PG_FUNCTION_ARGS)
1735 {
1736 	char	   *nsp_name_or_oid = PG_GETARG_CSTRING(0);
1737 	Oid			result;
1738 	List	   *names;
1739 
1740 	/* '-' ? */
1741 	if (strcmp(nsp_name_or_oid, "-") == 0)
1742 		PG_RETURN_OID(InvalidOid);
1743 
1744 	/* Numeric OID? */
1745 	if (nsp_name_or_oid[0] >= '0' &&
1746 		nsp_name_or_oid[0] <= '9' &&
1747 		strspn(nsp_name_or_oid, "0123456789") == strlen(nsp_name_or_oid))
1748 	{
1749 		result = DatumGetObjectId(DirectFunctionCall1(oidin,
1750 													  CStringGetDatum(nsp_name_or_oid)));
1751 		PG_RETURN_OID(result);
1752 	}
1753 
1754 	/* The rest of this wouldn't work in bootstrap mode */
1755 	if (IsBootstrapProcessingMode())
1756 		elog(ERROR, "regnamespace values must be OIDs in bootstrap mode");
1757 
1758 	/* Normal case: see if the name matches any pg_namespace entry. */
1759 	names = stringToQualifiedNameList(nsp_name_or_oid);
1760 
1761 	if (list_length(names) != 1)
1762 		ereport(ERROR,
1763 				(errcode(ERRCODE_INVALID_NAME),
1764 				 errmsg("invalid name syntax")));
1765 
1766 	result = get_namespace_oid(strVal(linitial(names)), false);
1767 
1768 	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
to_regnamespace(PG_FUNCTION_ARGS)1777 to_regnamespace(PG_FUNCTION_ARGS)
1778 {
1779 	char	   *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1780 	Oid			result;
1781 	List	   *names;
1782 
1783 	names = stringToQualifiedNameList(nsp_name);
1784 
1785 	if (list_length(names) != 1)
1786 		ereport(ERROR,
1787 				(errcode(ERRCODE_INVALID_NAME),
1788 				 errmsg("invalid name syntax")));
1789 
1790 	result = get_namespace_oid(strVal(linitial(names)), true);
1791 
1792 	if (OidIsValid(result))
1793 		PG_RETURN_OID(result);
1794 	else
1795 		PG_RETURN_NULL();
1796 }
1797 
1798 /*
1799  * regnamespaceout		- converts namespace OID to "nsp_name"
1800  */
1801 Datum
regnamespaceout(PG_FUNCTION_ARGS)1802 regnamespaceout(PG_FUNCTION_ARGS)
1803 {
1804 	Oid			nspid = PG_GETARG_OID(0);
1805 	char	   *result;
1806 
1807 	if (nspid == InvalidOid)
1808 	{
1809 		result = pstrdup("-");
1810 		PG_RETURN_CSTRING(result);
1811 	}
1812 
1813 	result = get_namespace_name(nspid);
1814 
1815 	if (result)
1816 	{
1817 		/* pstrdup is not really necessary, but it avoids a compiler warning */
1818 		result = pstrdup(quote_identifier(result));
1819 	}
1820 	else
1821 	{
1822 		/* If OID doesn't match any namespace, return it numerically */
1823 		result = (char *) palloc(NAMEDATALEN);
1824 		snprintf(result, NAMEDATALEN, "%u", nspid);
1825 	}
1826 
1827 	PG_RETURN_CSTRING(result);
1828 }
1829 
1830 /*
1831  *		regnamespacerecv	- converts external binary format to regnamespace
1832  */
1833 Datum
regnamespacerecv(PG_FUNCTION_ARGS)1834 regnamespacerecv(PG_FUNCTION_ARGS)
1835 {
1836 	/* Exactly the same as oidrecv, so share code */
1837 	return oidrecv(fcinfo);
1838 }
1839 
1840 /*
1841  *		regnamespacesend		- converts regnamespace to binary format
1842  */
1843 Datum
regnamespacesend(PG_FUNCTION_ARGS)1844 regnamespacesend(PG_FUNCTION_ARGS)
1845 {
1846 	/* Exactly the same as oidsend, so share code */
1847 	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
text_regclass(PG_FUNCTION_ARGS)1858 text_regclass(PG_FUNCTION_ARGS)
1859 {
1860 	text	   *relname = PG_GETARG_TEXT_PP(0);
1861 	Oid			result;
1862 	RangeVar   *rv;
1863 
1864 	rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
1865 
1866 	/* We might not even have permissions on this relation; don't lock it. */
1867 	result = RangeVarGetRelid(rv, NoLock, false);
1868 
1869 	PG_RETURN_OID(result);
1870 }
1871 
1872 
1873 /*
1874  * Given a C string, parse it into a qualified-name list.
1875  */
1876 List *
stringToQualifiedNameList(const char * string)1877 stringToQualifiedNameList(const char *string)
1878 {
1879 	char	   *rawname;
1880 	List	   *result = NIL;
1881 	List	   *namelist;
1882 	ListCell   *l;
1883 
1884 	/* We need a modifiable copy of the input string. */
1885 	rawname = pstrdup(string);
1886 
1887 	if (!SplitIdentifierString(rawname, '.', &namelist))
1888 		ereport(ERROR,
1889 				(errcode(ERRCODE_INVALID_NAME),
1890 				 errmsg("invalid name syntax")));
1891 
1892 	if (namelist == NIL)
1893 		ereport(ERROR,
1894 				(errcode(ERRCODE_INVALID_NAME),
1895 				 errmsg("invalid name syntax")));
1896 
1897 	foreach(l, namelist)
1898 	{
1899 		char	   *curname = (char *) lfirst(l);
1900 
1901 		result = lappend(result, makeString(pstrdup(curname)));
1902 	}
1903 
1904 	pfree(rawname);
1905 	list_free(namelist);
1906 
1907 	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
parseNameAndArgTypes(const char * string,bool allowNone,List ** names,int * nargs,Oid * argtypes)1925 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 	rawname = pstrdup(string);
1940 
1941 	/* Scan to find the expected left paren; mustn't be quoted */
1942 	in_quote = false;
1943 	for (ptr = rawname; *ptr; ptr++)
1944 	{
1945 		if (*ptr == '"')
1946 			in_quote = !in_quote;
1947 		else if (*ptr == '(' && !in_quote)
1948 			break;
1949 	}
1950 	if (*ptr == '\0')
1951 		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 	*ptr++ = '\0';
1957 	*names = stringToQualifiedNameList(rawname);
1958 
1959 	/* Check for the trailing right parenthesis and remove it */
1960 	ptr2 = ptr + strlen(ptr);
1961 	while (--ptr2 > ptr)
1962 	{
1963 		if (!scanner_isspace(*ptr2))
1964 			break;
1965 	}
1966 	if (*ptr2 != ')')
1967 		ereport(ERROR,
1968 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1969 				 errmsg("expected a right parenthesis")));
1970 
1971 	*ptr2 = '\0';
1972 
1973 	/* Separate the remaining string into comma-separated type names */
1974 	*nargs = 0;
1975 	had_comma = false;
1976 
1977 	for (;;)
1978 	{
1979 		/* allow leading whitespace */
1980 		while (scanner_isspace(*ptr))
1981 			ptr++;
1982 		if (*ptr == '\0')
1983 		{
1984 			/* End of string.  Okay unless we had a comma before. */
1985 			if (had_comma)
1986 				ereport(ERROR,
1987 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1988 						 errmsg("expected a type name")));
1989 			break;
1990 		}
1991 		typename = ptr;
1992 		/* Find end of type name --- end of string or comma */
1993 		/* ... but not a quoted or parenthesized comma */
1994 		in_quote = false;
1995 		paren_count = 0;
1996 		for (; *ptr; ptr++)
1997 		{
1998 			if (*ptr == '"')
1999 				in_quote = !in_quote;
2000 			else if (*ptr == ',' && !in_quote && paren_count == 0)
2001 				break;
2002 			else if (!in_quote)
2003 			{
2004 				switch (*ptr)
2005 				{
2006 					case '(':
2007 					case '[':
2008 						paren_count++;
2009 						break;
2010 					case ')':
2011 					case ']':
2012 						paren_count--;
2013 						break;
2014 				}
2015 			}
2016 		}
2017 		if (in_quote || paren_count != 0)
2018 			ereport(ERROR,
2019 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2020 					 errmsg("improper type name")));
2021 
2022 		ptr2 = ptr;
2023 		if (*ptr == ',')
2024 		{
2025 			had_comma = true;
2026 			*ptr++ = '\0';
2027 		}
2028 		else
2029 		{
2030 			had_comma = false;
2031 			Assert(*ptr == '\0');
2032 		}
2033 		/* Lop off trailing whitespace */
2034 		while (--ptr2 >= typename)
2035 		{
2036 			if (!scanner_isspace(*ptr2))
2037 				break;
2038 			*ptr2 = '\0';
2039 		}
2040 
2041 		if (allowNone && pg_strcasecmp(typename, "none") == 0)
2042 		{
2043 			/* Special case for NONE */
2044 			typeid = InvalidOid;
2045 			typmod = -1;
2046 		}
2047 		else
2048 		{
2049 			/* Use full parser to resolve the type name */
2050 			parseTypeString(typename, &typeid, &typmod, false);
2051 		}
2052 		if (*nargs >= FUNC_MAX_ARGS)
2053 			ereport(ERROR,
2054 					(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2055 					 errmsg("too many arguments")));
2056 
2057 		argtypes[*nargs] = typeid;
2058 		(*nargs)++;
2059 	}
2060 
2061 	pfree(rawname);
2062 }
2063