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