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