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