Properly access a buffer's LSN using existing access macros instead of abusing
[PostgreSQL.git] / src / backend / utils / adt / regproc.c
blob66dc9323c879568c7ef18f33bc1167d0a97a9988
1 /*-------------------------------------------------------------------------
3 * regproc.c
4 * Functions for the built-in types regproc, regclass, regtype, etc.
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.
11 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
15 * IDENTIFICATION
16 * $PostgreSQL$
18 *-------------------------------------------------------------------------
20 #include "postgres.h"
22 #include <ctype.h>
24 #include "access/genam.h"
25 #include "access/heapam.h"
26 #include "catalog/indexing.h"
27 #include "catalog/namespace.h"
28 #include "catalog/pg_class.h"
29 #include "catalog/pg_operator.h"
30 #include "catalog/pg_proc.h"
31 #include "catalog/pg_ts_config.h"
32 #include "catalog/pg_ts_dict.h"
33 #include "catalog/pg_type.h"
34 #include "miscadmin.h"
35 #include "parser/parse_type.h"
36 #include "utils/builtins.h"
37 #include "utils/fmgroids.h"
38 #include "utils/lsyscache.h"
39 #include "utils/syscache.h"
40 #include "utils/tqual.h"
42 static void parseNameAndArgTypes(const char *string, bool allowNone,
43 List **names, int *nargs, Oid *argtypes);
46 /*****************************************************************************
47 * USER I/O ROUTINES *
48 *****************************************************************************/
51 * regprocin - converts "proname" to proc OID
53 * We also accept a numeric OID, for symmetry with the output routine.
55 * '-' signifies unknown (OID 0). In all other cases, the input must
56 * match an existing pg_proc entry.
58 Datum
59 regprocin(PG_FUNCTION_ARGS)
61 char *pro_name_or_oid = PG_GETARG_CSTRING(0);
62 RegProcedure result = InvalidOid;
63 List *names;
64 FuncCandidateList clist;
66 /* '-' ? */
67 if (strcmp(pro_name_or_oid, "-") == 0)
68 PG_RETURN_OID(InvalidOid);
70 /* Numeric OID? */
71 if (pro_name_or_oid[0] >= '0' &&
72 pro_name_or_oid[0] <= '9' &&
73 strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
75 result = DatumGetObjectId(DirectFunctionCall1(oidin,
76 CStringGetDatum(pro_name_or_oid)));
77 PG_RETURN_OID(result);
80 /* Else it's a name, possibly schema-qualified */
83 * In bootstrap mode we assume the given name is not schema-qualified, and
84 * just search pg_proc for a unique match. This is needed for
85 * initializing other system catalogs (pg_namespace may not exist yet, and
86 * certainly there are no schemas other than pg_catalog).
88 if (IsBootstrapProcessingMode())
90 int matches = 0;
91 Relation hdesc;
92 ScanKeyData skey[1];
93 SysScanDesc sysscan;
94 HeapTuple tuple;
96 ScanKeyInit(&skey[0],
97 Anum_pg_proc_proname,
98 BTEqualStrategyNumber, F_NAMEEQ,
99 CStringGetDatum(pro_name_or_oid));
101 hdesc = heap_open(ProcedureRelationId, AccessShareLock);
102 sysscan = systable_beginscan(hdesc, ProcedureNameArgsNspIndexId, true,
103 SnapshotNow, 1, skey);
105 while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
107 result = (RegProcedure) HeapTupleGetOid(tuple);
108 if (++matches > 1)
109 break;
112 systable_endscan(sysscan);
113 heap_close(hdesc, AccessShareLock);
115 if (matches == 0)
116 ereport(ERROR,
117 (errcode(ERRCODE_UNDEFINED_FUNCTION),
118 errmsg("function \"%s\" does not exist", pro_name_or_oid)));
120 else if (matches > 1)
121 ereport(ERROR,
122 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
123 errmsg("more than one function named \"%s\"",
124 pro_name_or_oid)));
126 PG_RETURN_OID(result);
130 * Normal case: parse the name into components and see if it matches any
131 * pg_proc entries in the current search path.
133 names = stringToQualifiedNameList(pro_name_or_oid);
134 clist = FuncnameGetCandidates(names, -1, false);
136 if (clist == NULL)
137 ereport(ERROR,
138 (errcode(ERRCODE_UNDEFINED_FUNCTION),
139 errmsg("function \"%s\" does not exist", pro_name_or_oid)));
140 else if (clist->next != NULL)
141 ereport(ERROR,
142 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
143 errmsg("more than one function named \"%s\"",
144 pro_name_or_oid)));
146 result = clist->oid;
148 PG_RETURN_OID(result);
152 * regprocout - converts proc OID to "pro_name"
154 Datum
155 regprocout(PG_FUNCTION_ARGS)
157 RegProcedure proid = PG_GETARG_OID(0);
158 char *result;
159 HeapTuple proctup;
161 if (proid == InvalidOid)
163 result = pstrdup("-");
164 PG_RETURN_CSTRING(result);
167 proctup = SearchSysCache(PROCOID,
168 ObjectIdGetDatum(proid),
169 0, 0, 0);
171 if (HeapTupleIsValid(proctup))
173 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
174 char *proname = NameStr(procform->proname);
177 * In bootstrap mode, skip the fancy namespace stuff and just return
178 * the proc name. (This path is only needed for debugging output
179 * anyway.)
181 if (IsBootstrapProcessingMode())
182 result = pstrdup(proname);
183 else
185 char *nspname;
186 FuncCandidateList clist;
189 * Would this proc be found (uniquely!) by regprocin? If not,
190 * qualify it.
192 clist = FuncnameGetCandidates(list_make1(makeString(proname)),
193 -1, false);
194 if (clist != NULL && clist->next == NULL &&
195 clist->oid == proid)
196 nspname = NULL;
197 else
198 nspname = get_namespace_name(procform->pronamespace);
200 result = quote_qualified_identifier(nspname, proname);
203 ReleaseSysCache(proctup);
205 else
207 /* If OID doesn't match any pg_proc entry, return it numerically */
208 result = (char *) palloc(NAMEDATALEN);
209 snprintf(result, NAMEDATALEN, "%u", proid);
212 PG_RETURN_CSTRING(result);
216 * regprocrecv - converts external binary format to regproc
218 Datum
219 regprocrecv(PG_FUNCTION_ARGS)
221 /* Exactly the same as oidrecv, so share code */
222 return oidrecv(fcinfo);
226 * regprocsend - converts regproc to binary format
228 Datum
229 regprocsend(PG_FUNCTION_ARGS)
231 /* Exactly the same as oidsend, so share code */
232 return oidsend(fcinfo);
237 * regprocedurein - converts "proname(args)" to proc OID
239 * We also accept a numeric OID, for symmetry with the output routine.
241 * '-' signifies unknown (OID 0). In all other cases, the input must
242 * match an existing pg_proc entry.
244 Datum
245 regprocedurein(PG_FUNCTION_ARGS)
247 char *pro_name_or_oid = PG_GETARG_CSTRING(0);
248 RegProcedure result = InvalidOid;
249 List *names;
250 int nargs;
251 Oid argtypes[FUNC_MAX_ARGS];
252 FuncCandidateList clist;
254 /* '-' ? */
255 if (strcmp(pro_name_or_oid, "-") == 0)
256 PG_RETURN_OID(InvalidOid);
258 /* Numeric OID? */
259 if (pro_name_or_oid[0] >= '0' &&
260 pro_name_or_oid[0] <= '9' &&
261 strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
263 result = DatumGetObjectId(DirectFunctionCall1(oidin,
264 CStringGetDatum(pro_name_or_oid)));
265 PG_RETURN_OID(result);
269 * Else it's a name and arguments. Parse the name and arguments, look up
270 * potential matches in the current namespace search list, and scan to see
271 * which one exactly matches the given argument types. (There will not be
272 * more than one match.)
274 * XXX at present, this code will not work in bootstrap mode, hence this
275 * datatype cannot be used for any system column that needs to receive
276 * data during bootstrap.
278 parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
280 clist = FuncnameGetCandidates(names, nargs, false);
282 for (; clist; clist = clist->next)
284 if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
285 break;
288 if (clist == NULL)
289 ereport(ERROR,
290 (errcode(ERRCODE_UNDEFINED_FUNCTION),
291 errmsg("function \"%s\" does not exist", pro_name_or_oid)));
293 result = clist->oid;
295 PG_RETURN_OID(result);
299 * format_procedure - converts proc OID to "pro_name(args)"
301 * This exports the useful functionality of regprocedureout for use
302 * in other backend modules. The result is a palloc'd string.
304 char *
305 format_procedure(Oid procedure_oid)
307 char *result;
308 HeapTuple proctup;
310 proctup = SearchSysCache(PROCOID,
311 ObjectIdGetDatum(procedure_oid),
312 0, 0, 0);
314 if (HeapTupleIsValid(proctup))
316 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
317 char *proname = NameStr(procform->proname);
318 int nargs = procform->pronargs;
319 int i;
320 char *nspname;
321 StringInfoData buf;
323 /* XXX no support here for bootstrap mode */
325 initStringInfo(&buf);
328 * Would this proc be found (given the right args) by regprocedurein?
329 * If not, we need to qualify it.
331 if (FunctionIsVisible(procedure_oid))
332 nspname = NULL;
333 else
334 nspname = get_namespace_name(procform->pronamespace);
336 appendStringInfo(&buf, "%s(",
337 quote_qualified_identifier(nspname, proname));
338 for (i = 0; i < nargs; i++)
340 Oid thisargtype = procform->proargtypes.values[i];
342 if (i > 0)
343 appendStringInfoChar(&buf, ',');
344 appendStringInfoString(&buf, format_type_be(thisargtype));
346 appendStringInfoChar(&buf, ')');
348 result = buf.data;
350 ReleaseSysCache(proctup);
352 else
354 /* If OID doesn't match any pg_proc entry, return it numerically */
355 result = (char *) palloc(NAMEDATALEN);
356 snprintf(result, NAMEDATALEN, "%u", procedure_oid);
359 return result;
363 * regprocedureout - converts proc OID to "pro_name(args)"
365 Datum
366 regprocedureout(PG_FUNCTION_ARGS)
368 RegProcedure proid = PG_GETARG_OID(0);
369 char *result;
371 if (proid == InvalidOid)
372 result = pstrdup("-");
373 else
374 result = format_procedure(proid);
376 PG_RETURN_CSTRING(result);
380 * regprocedurerecv - converts external binary format to regprocedure
382 Datum
383 regprocedurerecv(PG_FUNCTION_ARGS)
385 /* Exactly the same as oidrecv, so share code */
386 return oidrecv(fcinfo);
390 * regproceduresend - converts regprocedure to binary format
392 Datum
393 regproceduresend(PG_FUNCTION_ARGS)
395 /* Exactly the same as oidsend, so share code */
396 return oidsend(fcinfo);
401 * regoperin - converts "oprname" to operator OID
403 * We also accept a numeric OID, for symmetry with the output routine.
405 * '0' signifies unknown (OID 0). In all other cases, the input must
406 * match an existing pg_operator entry.
408 Datum
409 regoperin(PG_FUNCTION_ARGS)
411 char *opr_name_or_oid = PG_GETARG_CSTRING(0);
412 Oid result = InvalidOid;
413 List *names;
414 FuncCandidateList clist;
416 /* '0' ? */
417 if (strcmp(opr_name_or_oid, "0") == 0)
418 PG_RETURN_OID(InvalidOid);
420 /* Numeric OID? */
421 if (opr_name_or_oid[0] >= '0' &&
422 opr_name_or_oid[0] <= '9' &&
423 strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
425 result = DatumGetObjectId(DirectFunctionCall1(oidin,
426 CStringGetDatum(opr_name_or_oid)));
427 PG_RETURN_OID(result);
430 /* Else it's a name, possibly schema-qualified */
433 * In bootstrap mode we assume the given name is not schema-qualified, and
434 * just search pg_operator for a unique match. This is needed for
435 * initializing other system catalogs (pg_namespace may not exist yet, and
436 * certainly there are no schemas other than pg_catalog).
438 if (IsBootstrapProcessingMode())
440 int matches = 0;
441 Relation hdesc;
442 ScanKeyData skey[1];
443 SysScanDesc sysscan;
444 HeapTuple tuple;
446 ScanKeyInit(&skey[0],
447 Anum_pg_operator_oprname,
448 BTEqualStrategyNumber, F_NAMEEQ,
449 CStringGetDatum(opr_name_or_oid));
451 hdesc = heap_open(OperatorRelationId, AccessShareLock);
452 sysscan = systable_beginscan(hdesc, OperatorNameNspIndexId, true,
453 SnapshotNow, 1, skey);
455 while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
457 result = HeapTupleGetOid(tuple);
458 if (++matches > 1)
459 break;
462 systable_endscan(sysscan);
463 heap_close(hdesc, AccessShareLock);
465 if (matches == 0)
466 ereport(ERROR,
467 (errcode(ERRCODE_UNDEFINED_FUNCTION),
468 errmsg("operator does not exist: %s", opr_name_or_oid)));
469 else if (matches > 1)
470 ereport(ERROR,
471 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
472 errmsg("more than one operator named %s",
473 opr_name_or_oid)));
475 PG_RETURN_OID(result);
479 * Normal case: parse the name into components and see if it matches any
480 * pg_operator entries in the current search path.
482 names = stringToQualifiedNameList(opr_name_or_oid);
483 clist = OpernameGetCandidates(names, '\0');
485 if (clist == NULL)
486 ereport(ERROR,
487 (errcode(ERRCODE_UNDEFINED_FUNCTION),
488 errmsg("operator does not exist: %s", opr_name_or_oid)));
489 else if (clist->next != NULL)
490 ereport(ERROR,
491 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
492 errmsg("more than one operator named %s",
493 opr_name_or_oid)));
495 result = clist->oid;
497 PG_RETURN_OID(result);
501 * regoperout - converts operator OID to "opr_name"
503 Datum
504 regoperout(PG_FUNCTION_ARGS)
506 Oid oprid = PG_GETARG_OID(0);
507 char *result;
508 HeapTuple opertup;
510 if (oprid == InvalidOid)
512 result = pstrdup("0");
513 PG_RETURN_CSTRING(result);
516 opertup = SearchSysCache(OPEROID,
517 ObjectIdGetDatum(oprid),
518 0, 0, 0);
520 if (HeapTupleIsValid(opertup))
522 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
523 char *oprname = NameStr(operform->oprname);
526 * In bootstrap mode, skip the fancy namespace stuff and just return
527 * the oper name. (This path is only needed for debugging output
528 * anyway.)
530 if (IsBootstrapProcessingMode())
531 result = pstrdup(oprname);
532 else
534 FuncCandidateList clist;
537 * Would this oper be found (uniquely!) by regoperin? If not,
538 * qualify it.
540 clist = OpernameGetCandidates(list_make1(makeString(oprname)),
541 '\0');
542 if (clist != NULL && clist->next == NULL &&
543 clist->oid == oprid)
544 result = pstrdup(oprname);
545 else
547 const char *nspname;
549 nspname = get_namespace_name(operform->oprnamespace);
550 nspname = quote_identifier(nspname);
551 result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2);
552 sprintf(result, "%s.%s", nspname, oprname);
556 ReleaseSysCache(opertup);
558 else
561 * If OID doesn't match any pg_operator entry, return it numerically
563 result = (char *) palloc(NAMEDATALEN);
564 snprintf(result, NAMEDATALEN, "%u", oprid);
567 PG_RETURN_CSTRING(result);
571 * regoperrecv - converts external binary format to regoper
573 Datum
574 regoperrecv(PG_FUNCTION_ARGS)
576 /* Exactly the same as oidrecv, so share code */
577 return oidrecv(fcinfo);
581 * regopersend - converts regoper to binary format
583 Datum
584 regopersend(PG_FUNCTION_ARGS)
586 /* Exactly the same as oidsend, so share code */
587 return oidsend(fcinfo);
592 * regoperatorin - converts "oprname(args)" to operator OID
594 * We also accept a numeric OID, for symmetry with the output routine.
596 * '0' signifies unknown (OID 0). In all other cases, the input must
597 * match an existing pg_operator entry.
599 Datum
600 regoperatorin(PG_FUNCTION_ARGS)
602 char *opr_name_or_oid = PG_GETARG_CSTRING(0);
603 Oid result;
604 List *names;
605 int nargs;
606 Oid argtypes[FUNC_MAX_ARGS];
608 /* '0' ? */
609 if (strcmp(opr_name_or_oid, "0") == 0)
610 PG_RETURN_OID(InvalidOid);
612 /* Numeric OID? */
613 if (opr_name_or_oid[0] >= '0' &&
614 opr_name_or_oid[0] <= '9' &&
615 strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
617 result = DatumGetObjectId(DirectFunctionCall1(oidin,
618 CStringGetDatum(opr_name_or_oid)));
619 PG_RETURN_OID(result);
623 * Else it's a name and arguments. Parse the name and arguments, look up
624 * potential matches in the current namespace search list, and scan to see
625 * which one exactly matches the given argument types. (There will not be
626 * more than one match.)
628 * XXX at present, this code will not work in bootstrap mode, hence this
629 * datatype cannot be used for any system column that needs to receive
630 * data during bootstrap.
632 parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes);
633 if (nargs == 1)
634 ereport(ERROR,
635 (errcode(ERRCODE_UNDEFINED_PARAMETER),
636 errmsg("missing argument"),
637 errhint("Use NONE to denote the missing argument of a unary operator.")));
638 if (nargs != 2)
639 ereport(ERROR,
640 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
641 errmsg("too many arguments"),
642 errhint("Provide two argument types for operator.")));
644 result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
646 if (!OidIsValid(result))
647 ereport(ERROR,
648 (errcode(ERRCODE_UNDEFINED_FUNCTION),
649 errmsg("operator does not exist: %s", opr_name_or_oid)));
651 PG_RETURN_OID(result);
655 * format_operator - converts operator OID to "opr_name(args)"
657 * This exports the useful functionality of regoperatorout for use
658 * in other backend modules. The result is a palloc'd string.
660 char *
661 format_operator(Oid operator_oid)
663 char *result;
664 HeapTuple opertup;
666 opertup = SearchSysCache(OPEROID,
667 ObjectIdGetDatum(operator_oid),
668 0, 0, 0);
670 if (HeapTupleIsValid(opertup))
672 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
673 char *oprname = NameStr(operform->oprname);
674 char *nspname;
675 StringInfoData buf;
677 /* XXX no support here for bootstrap mode */
679 initStringInfo(&buf);
682 * Would this oper be found (given the right args) by regoperatorin?
683 * If not, we need to qualify it.
685 if (!OperatorIsVisible(operator_oid))
687 nspname = get_namespace_name(operform->oprnamespace);
688 appendStringInfo(&buf, "%s.",
689 quote_identifier(nspname));
692 appendStringInfo(&buf, "%s(", oprname);
694 if (operform->oprleft)
695 appendStringInfo(&buf, "%s,",
696 format_type_be(operform->oprleft));
697 else
698 appendStringInfo(&buf, "NONE,");
700 if (operform->oprright)
701 appendStringInfo(&buf, "%s)",
702 format_type_be(operform->oprright));
703 else
704 appendStringInfo(&buf, "NONE)");
706 result = buf.data;
708 ReleaseSysCache(opertup);
710 else
713 * If OID doesn't match any pg_operator entry, return it numerically
715 result = (char *) palloc(NAMEDATALEN);
716 snprintf(result, NAMEDATALEN, "%u", operator_oid);
719 return result;
723 * regoperatorout - converts operator OID to "opr_name(args)"
725 Datum
726 regoperatorout(PG_FUNCTION_ARGS)
728 Oid oprid = PG_GETARG_OID(0);
729 char *result;
731 if (oprid == InvalidOid)
732 result = pstrdup("0");
733 else
734 result = format_operator(oprid);
736 PG_RETURN_CSTRING(result);
740 * regoperatorrecv - converts external binary format to regoperator
742 Datum
743 regoperatorrecv(PG_FUNCTION_ARGS)
745 /* Exactly the same as oidrecv, so share code */
746 return oidrecv(fcinfo);
750 * regoperatorsend - converts regoperator to binary format
752 Datum
753 regoperatorsend(PG_FUNCTION_ARGS)
755 /* Exactly the same as oidsend, so share code */
756 return oidsend(fcinfo);
761 * regclassin - converts "classname" to class OID
763 * We also accept a numeric OID, for symmetry with the output routine.
765 * '-' signifies unknown (OID 0). In all other cases, the input must
766 * match an existing pg_class entry.
768 Datum
769 regclassin(PG_FUNCTION_ARGS)
771 char *class_name_or_oid = PG_GETARG_CSTRING(0);
772 Oid result = InvalidOid;
773 List *names;
775 /* '-' ? */
776 if (strcmp(class_name_or_oid, "-") == 0)
777 PG_RETURN_OID(InvalidOid);
779 /* Numeric OID? */
780 if (class_name_or_oid[0] >= '0' &&
781 class_name_or_oid[0] <= '9' &&
782 strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
784 result = DatumGetObjectId(DirectFunctionCall1(oidin,
785 CStringGetDatum(class_name_or_oid)));
786 PG_RETURN_OID(result);
789 /* Else it's a name, possibly schema-qualified */
792 * In bootstrap mode we assume the given name is not schema-qualified, and
793 * just search pg_class for a match. This is needed for initializing
794 * other system catalogs (pg_namespace may not exist yet, and certainly
795 * there are no schemas other than pg_catalog).
797 if (IsBootstrapProcessingMode())
799 Relation hdesc;
800 ScanKeyData skey[1];
801 SysScanDesc sysscan;
802 HeapTuple tuple;
804 ScanKeyInit(&skey[0],
805 Anum_pg_class_relname,
806 BTEqualStrategyNumber, F_NAMEEQ,
807 CStringGetDatum(class_name_or_oid));
809 hdesc = heap_open(RelationRelationId, AccessShareLock);
810 sysscan = systable_beginscan(hdesc, ClassNameNspIndexId, true,
811 SnapshotNow, 1, skey);
813 if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
814 result = HeapTupleGetOid(tuple);
815 else
816 ereport(ERROR,
817 (errcode(ERRCODE_UNDEFINED_TABLE),
818 errmsg("relation \"%s\" does not exist", class_name_or_oid)));
820 /* We assume there can be only one match */
822 systable_endscan(sysscan);
823 heap_close(hdesc, AccessShareLock);
825 PG_RETURN_OID(result);
829 * Normal case: parse the name into components and see if it matches any
830 * pg_class entries in the current search path.
832 names = stringToQualifiedNameList(class_name_or_oid);
834 result = RangeVarGetRelid(makeRangeVarFromNameList(names), false);
836 PG_RETURN_OID(result);
840 * regclassout - converts class OID to "class_name"
842 Datum
843 regclassout(PG_FUNCTION_ARGS)
845 Oid classid = PG_GETARG_OID(0);
846 char *result;
847 HeapTuple classtup;
849 if (classid == InvalidOid)
851 result = pstrdup("-");
852 PG_RETURN_CSTRING(result);
855 classtup = SearchSysCache(RELOID,
856 ObjectIdGetDatum(classid),
857 0, 0, 0);
859 if (HeapTupleIsValid(classtup))
861 Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
862 char *classname = NameStr(classform->relname);
865 * In bootstrap mode, skip the fancy namespace stuff and just return
866 * the class name. (This path is only needed for debugging output
867 * anyway.)
869 if (IsBootstrapProcessingMode())
870 result = pstrdup(classname);
871 else
873 char *nspname;
876 * Would this class be found by regclassin? If not, qualify it.
878 if (RelationIsVisible(classid))
879 nspname = NULL;
880 else
881 nspname = get_namespace_name(classform->relnamespace);
883 result = quote_qualified_identifier(nspname, classname);
886 ReleaseSysCache(classtup);
888 else
890 /* If OID doesn't match any pg_class entry, return it numerically */
891 result = (char *) palloc(NAMEDATALEN);
892 snprintf(result, NAMEDATALEN, "%u", classid);
895 PG_RETURN_CSTRING(result);
899 * regclassrecv - converts external binary format to regclass
901 Datum
902 regclassrecv(PG_FUNCTION_ARGS)
904 /* Exactly the same as oidrecv, so share code */
905 return oidrecv(fcinfo);
909 * regclasssend - converts regclass to binary format
911 Datum
912 regclasssend(PG_FUNCTION_ARGS)
914 /* Exactly the same as oidsend, so share code */
915 return oidsend(fcinfo);
920 * regtypein - converts "typename" to type OID
922 * We also accept a numeric OID, for symmetry with the output routine.
924 * '-' signifies unknown (OID 0). In all other cases, the input must
925 * match an existing pg_type entry.
927 * In bootstrap mode the name must just equal some existing name in pg_type.
928 * In normal mode the type name can be specified using the full type syntax
929 * recognized by the parser; for example, DOUBLE PRECISION and INTEGER[] will
930 * work and be translated to the correct type names. (We ignore any typmod
931 * info generated by the parser, however.)
933 Datum
934 regtypein(PG_FUNCTION_ARGS)
936 char *typ_name_or_oid = PG_GETARG_CSTRING(0);
937 Oid result = InvalidOid;
938 int32 typmod;
940 /* '-' ? */
941 if (strcmp(typ_name_or_oid, "-") == 0)
942 PG_RETURN_OID(InvalidOid);
944 /* Numeric OID? */
945 if (typ_name_or_oid[0] >= '0' &&
946 typ_name_or_oid[0] <= '9' &&
947 strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
949 result = DatumGetObjectId(DirectFunctionCall1(oidin,
950 CStringGetDatum(typ_name_or_oid)));
951 PG_RETURN_OID(result);
954 /* Else it's a type name, possibly schema-qualified or decorated */
957 * In bootstrap mode we assume the given name is not schema-qualified, and
958 * just search pg_type for a match. This is needed for initializing other
959 * system catalogs (pg_namespace may not exist yet, and certainly there
960 * are no schemas other than pg_catalog).
962 if (IsBootstrapProcessingMode())
964 Relation hdesc;
965 ScanKeyData skey[1];
966 SysScanDesc sysscan;
967 HeapTuple tuple;
969 ScanKeyInit(&skey[0],
970 Anum_pg_type_typname,
971 BTEqualStrategyNumber, F_NAMEEQ,
972 CStringGetDatum(typ_name_or_oid));
974 hdesc = heap_open(TypeRelationId, AccessShareLock);
975 sysscan = systable_beginscan(hdesc, TypeNameNspIndexId, true,
976 SnapshotNow, 1, skey);
978 if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
979 result = HeapTupleGetOid(tuple);
980 else
981 ereport(ERROR,
982 (errcode(ERRCODE_UNDEFINED_OBJECT),
983 errmsg("type \"%s\" does not exist", typ_name_or_oid)));
985 /* We assume there can be only one match */
987 systable_endscan(sysscan);
988 heap_close(hdesc, AccessShareLock);
990 PG_RETURN_OID(result);
994 * Normal case: invoke the full parser to deal with special cases such as
995 * array syntax.
997 parseTypeString(typ_name_or_oid, &result, &typmod);
999 PG_RETURN_OID(result);
1003 * regtypeout - converts type OID to "typ_name"
1005 Datum
1006 regtypeout(PG_FUNCTION_ARGS)
1008 Oid typid = PG_GETARG_OID(0);
1009 char *result;
1010 HeapTuple typetup;
1012 if (typid == InvalidOid)
1014 result = pstrdup("-");
1015 PG_RETURN_CSTRING(result);
1018 typetup = SearchSysCache(TYPEOID,
1019 ObjectIdGetDatum(typid),
1020 0, 0, 0);
1022 if (HeapTupleIsValid(typetup))
1024 Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup);
1027 * In bootstrap mode, skip the fancy namespace stuff and just return
1028 * the type name. (This path is only needed for debugging output
1029 * anyway.)
1031 if (IsBootstrapProcessingMode())
1033 char *typname = NameStr(typeform->typname);
1035 result = pstrdup(typname);
1037 else
1038 result = format_type_be(typid);
1040 ReleaseSysCache(typetup);
1042 else
1044 /* If OID doesn't match any pg_type entry, return it numerically */
1045 result = (char *) palloc(NAMEDATALEN);
1046 snprintf(result, NAMEDATALEN, "%u", typid);
1049 PG_RETURN_CSTRING(result);
1053 * regtyperecv - converts external binary format to regtype
1055 Datum
1056 regtyperecv(PG_FUNCTION_ARGS)
1058 /* Exactly the same as oidrecv, so share code */
1059 return oidrecv(fcinfo);
1063 * regtypesend - converts regtype to binary format
1065 Datum
1066 regtypesend(PG_FUNCTION_ARGS)
1068 /* Exactly the same as oidsend, so share code */
1069 return oidsend(fcinfo);
1074 * regconfigin - converts "tsconfigname" to tsconfig OID
1076 * We also accept a numeric OID, for symmetry with the output routine.
1078 * '-' signifies unknown (OID 0). In all other cases, the input must
1079 * match an existing pg_ts_config entry.
1081 * This function is not needed in bootstrap mode, so we don't worry about
1082 * making it work then.
1084 Datum
1085 regconfigin(PG_FUNCTION_ARGS)
1087 char *cfg_name_or_oid = PG_GETARG_CSTRING(0);
1088 Oid result;
1089 List *names;
1091 /* '-' ? */
1092 if (strcmp(cfg_name_or_oid, "-") == 0)
1093 PG_RETURN_OID(InvalidOid);
1095 /* Numeric OID? */
1096 if (cfg_name_or_oid[0] >= '0' &&
1097 cfg_name_or_oid[0] <= '9' &&
1098 strspn(cfg_name_or_oid, "0123456789") == strlen(cfg_name_or_oid))
1100 result = DatumGetObjectId(DirectFunctionCall1(oidin,
1101 CStringGetDatum(cfg_name_or_oid)));
1102 PG_RETURN_OID(result);
1106 * Normal case: parse the name into components and see if it matches any
1107 * pg_ts_config entries in the current search path.
1109 names = stringToQualifiedNameList(cfg_name_or_oid);
1111 result = TSConfigGetCfgid(names, false);
1113 PG_RETURN_OID(result);
1117 * regconfigout - converts tsconfig OID to "tsconfigname"
1119 Datum
1120 regconfigout(PG_FUNCTION_ARGS)
1122 Oid cfgid = PG_GETARG_OID(0);
1123 char *result;
1124 HeapTuple cfgtup;
1126 if (cfgid == InvalidOid)
1128 result = pstrdup("-");
1129 PG_RETURN_CSTRING(result);
1132 cfgtup = SearchSysCache(TSCONFIGOID,
1133 ObjectIdGetDatum(cfgid),
1134 0, 0, 0);
1136 if (HeapTupleIsValid(cfgtup))
1138 Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
1139 char *cfgname = NameStr(cfgform->cfgname);
1140 char *nspname;
1143 * Would this config be found by regconfigin? If not, qualify it.
1145 if (TSConfigIsVisible(cfgid))
1146 nspname = NULL;
1147 else
1148 nspname = get_namespace_name(cfgform->cfgnamespace);
1150 result = quote_qualified_identifier(nspname, cfgname);
1152 ReleaseSysCache(cfgtup);
1154 else
1156 /* If OID doesn't match any pg_ts_config row, return it numerically */
1157 result = (char *) palloc(NAMEDATALEN);
1158 snprintf(result, NAMEDATALEN, "%u", cfgid);
1161 PG_RETURN_CSTRING(result);
1165 * regconfigrecv - converts external binary format to regconfig
1167 Datum
1168 regconfigrecv(PG_FUNCTION_ARGS)
1170 /* Exactly the same as oidrecv, so share code */
1171 return oidrecv(fcinfo);
1175 * regconfigsend - converts regconfig to binary format
1177 Datum
1178 regconfigsend(PG_FUNCTION_ARGS)
1180 /* Exactly the same as oidsend, so share code */
1181 return oidsend(fcinfo);
1186 * regdictionaryin - converts "tsdictionaryname" to tsdictionary OID
1188 * We also accept a numeric OID, for symmetry with the output routine.
1190 * '-' signifies unknown (OID 0). In all other cases, the input must
1191 * match an existing pg_ts_dict entry.
1193 * This function is not needed in bootstrap mode, so we don't worry about
1194 * making it work then.
1196 Datum
1197 regdictionaryin(PG_FUNCTION_ARGS)
1199 char *dict_name_or_oid = PG_GETARG_CSTRING(0);
1200 Oid result;
1201 List *names;
1203 /* '-' ? */
1204 if (strcmp(dict_name_or_oid, "-") == 0)
1205 PG_RETURN_OID(InvalidOid);
1207 /* Numeric OID? */
1208 if (dict_name_or_oid[0] >= '0' &&
1209 dict_name_or_oid[0] <= '9' &&
1210 strspn(dict_name_or_oid, "0123456789") == strlen(dict_name_or_oid))
1212 result = DatumGetObjectId(DirectFunctionCall1(oidin,
1213 CStringGetDatum(dict_name_or_oid)));
1214 PG_RETURN_OID(result);
1218 * Normal case: parse the name into components and see if it matches any
1219 * pg_ts_dict entries in the current search path.
1221 names = stringToQualifiedNameList(dict_name_or_oid);
1223 result = TSDictionaryGetDictid(names, false);
1225 PG_RETURN_OID(result);
1229 * regdictionaryout - converts tsdictionary OID to "tsdictionaryname"
1231 Datum
1232 regdictionaryout(PG_FUNCTION_ARGS)
1234 Oid dictid = PG_GETARG_OID(0);
1235 char *result;
1236 HeapTuple dicttup;
1238 if (dictid == InvalidOid)
1240 result = pstrdup("-");
1241 PG_RETURN_CSTRING(result);
1244 dicttup = SearchSysCache(TSDICTOID,
1245 ObjectIdGetDatum(dictid),
1246 0, 0, 0);
1248 if (HeapTupleIsValid(dicttup))
1250 Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
1251 char *dictname = NameStr(dictform->dictname);
1252 char *nspname;
1255 * Would this dictionary be found by regdictionaryin? If not, qualify
1256 * it.
1258 if (TSDictionaryIsVisible(dictid))
1259 nspname = NULL;
1260 else
1261 nspname = get_namespace_name(dictform->dictnamespace);
1263 result = quote_qualified_identifier(nspname, dictname);
1265 ReleaseSysCache(dicttup);
1267 else
1269 /* If OID doesn't match any pg_ts_dict row, return it numerically */
1270 result = (char *) palloc(NAMEDATALEN);
1271 snprintf(result, NAMEDATALEN, "%u", dictid);
1274 PG_RETURN_CSTRING(result);
1278 * regdictionaryrecv - converts external binary format to regdictionary
1280 Datum
1281 regdictionaryrecv(PG_FUNCTION_ARGS)
1283 /* Exactly the same as oidrecv, so share code */
1284 return oidrecv(fcinfo);
1288 * regdictionarysend - converts regdictionary to binary format
1290 Datum
1291 regdictionarysend(PG_FUNCTION_ARGS)
1293 /* Exactly the same as oidsend, so share code */
1294 return oidsend(fcinfo);
1299 * text_regclass: convert text to regclass
1301 * This could be replaced by CoerceViaIO, except that we need to treat
1302 * text-to-regclass as an implicit cast to support legacy forms of nextval()
1303 * and related functions.
1305 Datum
1306 text_regclass(PG_FUNCTION_ARGS)
1308 text *relname = PG_GETARG_TEXT_P(0);
1309 Oid result;
1310 RangeVar *rv;
1312 rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
1313 result = RangeVarGetRelid(rv, false);
1315 PG_RETURN_OID(result);
1320 * Given a C string, parse it into a qualified-name list.
1322 List *
1323 stringToQualifiedNameList(const char *string)
1325 char *rawname;
1326 List *result = NIL;
1327 List *namelist;
1328 ListCell *l;
1330 /* We need a modifiable copy of the input string. */
1331 rawname = pstrdup(string);
1333 if (!SplitIdentifierString(rawname, '.', &namelist))
1334 ereport(ERROR,
1335 (errcode(ERRCODE_INVALID_NAME),
1336 errmsg("invalid name syntax")));
1338 if (namelist == NIL)
1339 ereport(ERROR,
1340 (errcode(ERRCODE_INVALID_NAME),
1341 errmsg("invalid name syntax")));
1343 foreach(l, namelist)
1345 char *curname = (char *) lfirst(l);
1347 result = lappend(result, makeString(pstrdup(curname)));
1350 pfree(rawname);
1351 list_free(namelist);
1353 return result;
1356 /*****************************************************************************
1357 * SUPPORT ROUTINES *
1358 *****************************************************************************/
1361 * Given a C string, parse it into a qualified function or operator name
1362 * followed by a parenthesized list of type names. Reduce the
1363 * type names to an array of OIDs (returned into *nargs and *argtypes;
1364 * the argtypes array should be of size FUNC_MAX_ARGS). The function or
1365 * operator name is returned to *names as a List of Strings.
1367 * If allowNone is TRUE, accept "NONE" and return it as InvalidOid (this is
1368 * for unary operators).
1370 static void
1371 parseNameAndArgTypes(const char *string, bool allowNone, List **names,
1372 int *nargs, Oid *argtypes)
1374 char *rawname;
1375 char *ptr;
1376 char *ptr2;
1377 char *typename;
1378 bool in_quote;
1379 bool had_comma;
1380 int paren_count;
1381 Oid typeid;
1382 int32 typmod;
1384 /* We need a modifiable copy of the input string. */
1385 rawname = pstrdup(string);
1387 /* Scan to find the expected left paren; mustn't be quoted */
1388 in_quote = false;
1389 for (ptr = rawname; *ptr; ptr++)
1391 if (*ptr == '"')
1392 in_quote = !in_quote;
1393 else if (*ptr == '(' && !in_quote)
1394 break;
1396 if (*ptr == '\0')
1397 ereport(ERROR,
1398 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1399 errmsg("expected a left parenthesis")));
1401 /* Separate the name and parse it into a list */
1402 *ptr++ = '\0';
1403 *names = stringToQualifiedNameList(rawname);
1405 /* Check for the trailing right parenthesis and remove it */
1406 ptr2 = ptr + strlen(ptr);
1407 while (--ptr2 > ptr)
1409 if (!isspace((unsigned char) *ptr2))
1410 break;
1412 if (*ptr2 != ')')
1413 ereport(ERROR,
1414 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1415 errmsg("expected a right parenthesis")));
1417 *ptr2 = '\0';
1419 /* Separate the remaining string into comma-separated type names */
1420 *nargs = 0;
1421 had_comma = false;
1423 for (;;)
1425 /* allow leading whitespace */
1426 while (isspace((unsigned char) *ptr))
1427 ptr++;
1428 if (*ptr == '\0')
1430 /* End of string. Okay unless we had a comma before. */
1431 if (had_comma)
1432 ereport(ERROR,
1433 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1434 errmsg("expected a type name")));
1435 break;
1437 typename = ptr;
1438 /* Find end of type name --- end of string or comma */
1439 /* ... but not a quoted or parenthesized comma */
1440 in_quote = false;
1441 paren_count = 0;
1442 for (; *ptr; ptr++)
1444 if (*ptr == '"')
1445 in_quote = !in_quote;
1446 else if (*ptr == ',' && !in_quote && paren_count == 0)
1447 break;
1448 else if (!in_quote)
1450 switch (*ptr)
1452 case '(':
1453 case '[':
1454 paren_count++;
1455 break;
1456 case ')':
1457 case ']':
1458 paren_count--;
1459 break;
1463 if (in_quote || paren_count != 0)
1464 ereport(ERROR,
1465 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1466 errmsg("improper type name")));
1468 ptr2 = ptr;
1469 if (*ptr == ',')
1471 had_comma = true;
1472 *ptr++ = '\0';
1474 else
1476 had_comma = false;
1477 Assert(*ptr == '\0');
1479 /* Lop off trailing whitespace */
1480 while (--ptr2 >= typename)
1482 if (!isspace((unsigned char) *ptr2))
1483 break;
1484 *ptr2 = '\0';
1487 if (allowNone && pg_strcasecmp(typename, "none") == 0)
1489 /* Special case for NONE */
1490 typeid = InvalidOid;
1491 typmod = -1;
1493 else
1495 /* Use full parser to resolve the type name */
1496 parseTypeString(typename, &typeid, &typmod);
1498 if (*nargs >= FUNC_MAX_ARGS)
1499 ereport(ERROR,
1500 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
1501 errmsg("too many arguments")));
1503 argtypes[*nargs] = typeid;
1504 (*nargs)++;
1507 pfree(rawname);