Move the HTSU_Result enum definition into snapshot.h, to avoid including
[PostgreSQL.git] / src / backend / utils / adt / regproc.c
blob7e52e79dde631862194c8ee334a5845e5ab370a6
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_operator.h"
29 #include "catalog/pg_proc.h"
30 #include "catalog/pg_ts_config.h"
31 #include "catalog/pg_ts_dict.h"
32 #include "catalog/pg_type.h"
33 #include "miscadmin.h"
34 #include "parser/parse_type.h"
35 #include "utils/builtins.h"
36 #include "utils/fmgroids.h"
37 #include "utils/lsyscache.h"
38 #include "utils/syscache.h"
39 #include "utils/tqual.h"
41 static void parseNameAndArgTypes(const char *string, bool allowNone,
42 List **names, int *nargs, Oid *argtypes);
45 /*****************************************************************************
46 * USER I/O ROUTINES *
47 *****************************************************************************/
50 * regprocin - converts "proname" to proc OID
52 * We also accept a numeric OID, for symmetry with the output routine.
54 * '-' signifies unknown (OID 0). In all other cases, the input must
55 * match an existing pg_proc entry.
57 Datum
58 regprocin(PG_FUNCTION_ARGS)
60 char *pro_name_or_oid = PG_GETARG_CSTRING(0);
61 RegProcedure result = InvalidOid;
62 List *names;
63 FuncCandidateList clist;
65 /* '-' ? */
66 if (strcmp(pro_name_or_oid, "-") == 0)
67 PG_RETURN_OID(InvalidOid);
69 /* Numeric OID? */
70 if (pro_name_or_oid[0] >= '0' &&
71 pro_name_or_oid[0] <= '9' &&
72 strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
74 result = DatumGetObjectId(DirectFunctionCall1(oidin,
75 CStringGetDatum(pro_name_or_oid)));
76 PG_RETURN_OID(result);
79 /* Else it's a name, possibly schema-qualified */
82 * In bootstrap mode we assume the given name is not schema-qualified, and
83 * just search pg_proc for a unique match. This is needed for
84 * initializing other system catalogs (pg_namespace may not exist yet, and
85 * certainly there are no schemas other than pg_catalog).
87 if (IsBootstrapProcessingMode())
89 int matches = 0;
90 Relation hdesc;
91 ScanKeyData skey[1];
92 SysScanDesc sysscan;
93 HeapTuple tuple;
95 ScanKeyInit(&skey[0],
96 Anum_pg_proc_proname,
97 BTEqualStrategyNumber, F_NAMEEQ,
98 CStringGetDatum(pro_name_or_oid));
100 hdesc = heap_open(ProcedureRelationId, AccessShareLock);
101 sysscan = systable_beginscan(hdesc, ProcedureNameArgsNspIndexId, true,
102 SnapshotNow, 1, skey);
104 while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
106 result = (RegProcedure) HeapTupleGetOid(tuple);
107 if (++matches > 1)
108 break;
111 systable_endscan(sysscan);
112 heap_close(hdesc, AccessShareLock);
114 if (matches == 0)
115 ereport(ERROR,
116 (errcode(ERRCODE_UNDEFINED_FUNCTION),
117 errmsg("function \"%s\" does not exist", pro_name_or_oid)));
119 else if (matches > 1)
120 ereport(ERROR,
121 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
122 errmsg("more than one function named \"%s\"",
123 pro_name_or_oid)));
125 PG_RETURN_OID(result);
129 * Normal case: parse the name into components and see if it matches any
130 * pg_proc entries in the current search path.
132 names = stringToQualifiedNameList(pro_name_or_oid);
133 clist = FuncnameGetCandidates(names, -1);
135 if (clist == NULL)
136 ereport(ERROR,
137 (errcode(ERRCODE_UNDEFINED_FUNCTION),
138 errmsg("function \"%s\" does not exist", pro_name_or_oid)));
139 else if (clist->next != NULL)
140 ereport(ERROR,
141 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
142 errmsg("more than one function named \"%s\"",
143 pro_name_or_oid)));
145 result = clist->oid;
147 PG_RETURN_OID(result);
151 * regprocout - converts proc OID to "pro_name"
153 Datum
154 regprocout(PG_FUNCTION_ARGS)
156 RegProcedure proid = PG_GETARG_OID(0);
157 char *result;
158 HeapTuple proctup;
160 if (proid == InvalidOid)
162 result = pstrdup("-");
163 PG_RETURN_CSTRING(result);
166 proctup = SearchSysCache(PROCOID,
167 ObjectIdGetDatum(proid),
168 0, 0, 0);
170 if (HeapTupleIsValid(proctup))
172 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
173 char *proname = NameStr(procform->proname);
176 * In bootstrap mode, skip the fancy namespace stuff and just return
177 * the proc name. (This path is only needed for debugging output
178 * anyway.)
180 if (IsBootstrapProcessingMode())
181 result = pstrdup(proname);
182 else
184 char *nspname;
185 FuncCandidateList clist;
188 * Would this proc be found (uniquely!) by regprocin? If not,
189 * qualify it.
191 clist = FuncnameGetCandidates(list_make1(makeString(proname)), -1);
192 if (clist != NULL && clist->next == NULL &&
193 clist->oid == proid)
194 nspname = NULL;
195 else
196 nspname = get_namespace_name(procform->pronamespace);
198 result = quote_qualified_identifier(nspname, proname);
201 ReleaseSysCache(proctup);
203 else
205 /* If OID doesn't match any pg_proc entry, return it numerically */
206 result = (char *) palloc(NAMEDATALEN);
207 snprintf(result, NAMEDATALEN, "%u", proid);
210 PG_RETURN_CSTRING(result);
214 * regprocrecv - converts external binary format to regproc
216 Datum
217 regprocrecv(PG_FUNCTION_ARGS)
219 /* Exactly the same as oidrecv, so share code */
220 return oidrecv(fcinfo);
224 * regprocsend - converts regproc to binary format
226 Datum
227 regprocsend(PG_FUNCTION_ARGS)
229 /* Exactly the same as oidsend, so share code */
230 return oidsend(fcinfo);
235 * regprocedurein - converts "proname(args)" to proc OID
237 * We also accept a numeric OID, for symmetry with the output routine.
239 * '-' signifies unknown (OID 0). In all other cases, the input must
240 * match an existing pg_proc entry.
242 Datum
243 regprocedurein(PG_FUNCTION_ARGS)
245 char *pro_name_or_oid = PG_GETARG_CSTRING(0);
246 RegProcedure result = InvalidOid;
247 List *names;
248 int nargs;
249 Oid argtypes[FUNC_MAX_ARGS];
250 FuncCandidateList clist;
252 /* '-' ? */
253 if (strcmp(pro_name_or_oid, "-") == 0)
254 PG_RETURN_OID(InvalidOid);
256 /* Numeric OID? */
257 if (pro_name_or_oid[0] >= '0' &&
258 pro_name_or_oid[0] <= '9' &&
259 strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
261 result = DatumGetObjectId(DirectFunctionCall1(oidin,
262 CStringGetDatum(pro_name_or_oid)));
263 PG_RETURN_OID(result);
267 * Else it's a name and arguments. Parse the name and arguments, look up
268 * potential matches in the current namespace search list, and scan to see
269 * which one exactly matches the given argument types. (There will not be
270 * more than one match.)
272 * XXX at present, this code will not work in bootstrap mode, hence this
273 * datatype cannot be used for any system column that needs to receive
274 * data during bootstrap.
276 parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
278 clist = FuncnameGetCandidates(names, nargs);
280 for (; clist; clist = clist->next)
282 if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
283 break;
286 if (clist == NULL)
287 ereport(ERROR,
288 (errcode(ERRCODE_UNDEFINED_FUNCTION),
289 errmsg("function \"%s\" does not exist", pro_name_or_oid)));
291 result = clist->oid;
293 PG_RETURN_OID(result);
297 * format_procedure - converts proc OID to "pro_name(args)"
299 * This exports the useful functionality of regprocedureout for use
300 * in other backend modules. The result is a palloc'd string.
302 char *
303 format_procedure(Oid procedure_oid)
305 char *result;
306 HeapTuple proctup;
308 proctup = SearchSysCache(PROCOID,
309 ObjectIdGetDatum(procedure_oid),
310 0, 0, 0);
312 if (HeapTupleIsValid(proctup))
314 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
315 char *proname = NameStr(procform->proname);
316 int nargs = procform->pronargs;
317 int i;
318 char *nspname;
319 StringInfoData buf;
321 /* XXX no support here for bootstrap mode */
323 initStringInfo(&buf);
326 * Would this proc be found (given the right args) by regprocedurein?
327 * If not, we need to qualify it.
329 if (FunctionIsVisible(procedure_oid))
330 nspname = NULL;
331 else
332 nspname = get_namespace_name(procform->pronamespace);
334 appendStringInfo(&buf, "%s(",
335 quote_qualified_identifier(nspname, proname));
336 for (i = 0; i < nargs; i++)
338 Oid thisargtype = procform->proargtypes.values[i];
340 if (i > 0)
341 appendStringInfoChar(&buf, ',');
342 appendStringInfoString(&buf, format_type_be(thisargtype));
344 appendStringInfoChar(&buf, ')');
346 result = buf.data;
348 ReleaseSysCache(proctup);
350 else
352 /* If OID doesn't match any pg_proc entry, return it numerically */
353 result = (char *) palloc(NAMEDATALEN);
354 snprintf(result, NAMEDATALEN, "%u", procedure_oid);
357 return result;
361 * regprocedureout - converts proc OID to "pro_name(args)"
363 Datum
364 regprocedureout(PG_FUNCTION_ARGS)
366 RegProcedure proid = PG_GETARG_OID(0);
367 char *result;
369 if (proid == InvalidOid)
370 result = pstrdup("-");
371 else
372 result = format_procedure(proid);
374 PG_RETURN_CSTRING(result);
378 * regprocedurerecv - converts external binary format to regprocedure
380 Datum
381 regprocedurerecv(PG_FUNCTION_ARGS)
383 /* Exactly the same as oidrecv, so share code */
384 return oidrecv(fcinfo);
388 * regproceduresend - converts regprocedure to binary format
390 Datum
391 regproceduresend(PG_FUNCTION_ARGS)
393 /* Exactly the same as oidsend, so share code */
394 return oidsend(fcinfo);
399 * regoperin - converts "oprname" to operator OID
401 * We also accept a numeric OID, for symmetry with the output routine.
403 * '0' signifies unknown (OID 0). In all other cases, the input must
404 * match an existing pg_operator entry.
406 Datum
407 regoperin(PG_FUNCTION_ARGS)
409 char *opr_name_or_oid = PG_GETARG_CSTRING(0);
410 Oid result = InvalidOid;
411 List *names;
412 FuncCandidateList clist;
414 /* '0' ? */
415 if (strcmp(opr_name_or_oid, "0") == 0)
416 PG_RETURN_OID(InvalidOid);
418 /* Numeric OID? */
419 if (opr_name_or_oid[0] >= '0' &&
420 opr_name_or_oid[0] <= '9' &&
421 strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
423 result = DatumGetObjectId(DirectFunctionCall1(oidin,
424 CStringGetDatum(opr_name_or_oid)));
425 PG_RETURN_OID(result);
428 /* Else it's a name, possibly schema-qualified */
431 * In bootstrap mode we assume the given name is not schema-qualified, and
432 * just search pg_operator for a unique match. This is needed for
433 * initializing other system catalogs (pg_namespace may not exist yet, and
434 * certainly there are no schemas other than pg_catalog).
436 if (IsBootstrapProcessingMode())
438 int matches = 0;
439 Relation hdesc;
440 ScanKeyData skey[1];
441 SysScanDesc sysscan;
442 HeapTuple tuple;
444 ScanKeyInit(&skey[0],
445 Anum_pg_operator_oprname,
446 BTEqualStrategyNumber, F_NAMEEQ,
447 CStringGetDatum(opr_name_or_oid));
449 hdesc = heap_open(OperatorRelationId, AccessShareLock);
450 sysscan = systable_beginscan(hdesc, OperatorNameNspIndexId, true,
451 SnapshotNow, 1, skey);
453 while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
455 result = HeapTupleGetOid(tuple);
456 if (++matches > 1)
457 break;
460 systable_endscan(sysscan);
461 heap_close(hdesc, AccessShareLock);
463 if (matches == 0)
464 ereport(ERROR,
465 (errcode(ERRCODE_UNDEFINED_FUNCTION),
466 errmsg("operator does not exist: %s", opr_name_or_oid)));
467 else if (matches > 1)
468 ereport(ERROR,
469 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
470 errmsg("more than one operator named %s",
471 opr_name_or_oid)));
473 PG_RETURN_OID(result);
477 * Normal case: parse the name into components and see if it matches any
478 * pg_operator entries in the current search path.
480 names = stringToQualifiedNameList(opr_name_or_oid);
481 clist = OpernameGetCandidates(names, '\0');
483 if (clist == NULL)
484 ereport(ERROR,
485 (errcode(ERRCODE_UNDEFINED_FUNCTION),
486 errmsg("operator does not exist: %s", opr_name_or_oid)));
487 else if (clist->next != NULL)
488 ereport(ERROR,
489 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
490 errmsg("more than one operator named %s",
491 opr_name_or_oid)));
493 result = clist->oid;
495 PG_RETURN_OID(result);
499 * regoperout - converts operator OID to "opr_name"
501 Datum
502 regoperout(PG_FUNCTION_ARGS)
504 Oid oprid = PG_GETARG_OID(0);
505 char *result;
506 HeapTuple opertup;
508 if (oprid == InvalidOid)
510 result = pstrdup("0");
511 PG_RETURN_CSTRING(result);
514 opertup = SearchSysCache(OPEROID,
515 ObjectIdGetDatum(oprid),
516 0, 0, 0);
518 if (HeapTupleIsValid(opertup))
520 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
521 char *oprname = NameStr(operform->oprname);
524 * In bootstrap mode, skip the fancy namespace stuff and just return
525 * the oper name. (This path is only needed for debugging output
526 * anyway.)
528 if (IsBootstrapProcessingMode())
529 result = pstrdup(oprname);
530 else
532 FuncCandidateList clist;
535 * Would this oper be found (uniquely!) by regoperin? If not,
536 * qualify it.
538 clist = OpernameGetCandidates(list_make1(makeString(oprname)),
539 '\0');
540 if (clist != NULL && clist->next == NULL &&
541 clist->oid == oprid)
542 result = pstrdup(oprname);
543 else
545 const char *nspname;
547 nspname = get_namespace_name(operform->oprnamespace);
548 nspname = quote_identifier(nspname);
549 result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2);
550 sprintf(result, "%s.%s", nspname, oprname);
554 ReleaseSysCache(opertup);
556 else
559 * If OID doesn't match any pg_operator entry, return it numerically
561 result = (char *) palloc(NAMEDATALEN);
562 snprintf(result, NAMEDATALEN, "%u", oprid);
565 PG_RETURN_CSTRING(result);
569 * regoperrecv - converts external binary format to regoper
571 Datum
572 regoperrecv(PG_FUNCTION_ARGS)
574 /* Exactly the same as oidrecv, so share code */
575 return oidrecv(fcinfo);
579 * regopersend - converts regoper to binary format
581 Datum
582 regopersend(PG_FUNCTION_ARGS)
584 /* Exactly the same as oidsend, so share code */
585 return oidsend(fcinfo);
590 * regoperatorin - converts "oprname(args)" to operator OID
592 * We also accept a numeric OID, for symmetry with the output routine.
594 * '0' signifies unknown (OID 0). In all other cases, the input must
595 * match an existing pg_operator entry.
597 Datum
598 regoperatorin(PG_FUNCTION_ARGS)
600 char *opr_name_or_oid = PG_GETARG_CSTRING(0);
601 Oid result;
602 List *names;
603 int nargs;
604 Oid argtypes[FUNC_MAX_ARGS];
606 /* '0' ? */
607 if (strcmp(opr_name_or_oid, "0") == 0)
608 PG_RETURN_OID(InvalidOid);
610 /* Numeric OID? */
611 if (opr_name_or_oid[0] >= '0' &&
612 opr_name_or_oid[0] <= '9' &&
613 strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
615 result = DatumGetObjectId(DirectFunctionCall1(oidin,
616 CStringGetDatum(opr_name_or_oid)));
617 PG_RETURN_OID(result);
621 * Else it's a name and arguments. Parse the name and arguments, look up
622 * potential matches in the current namespace search list, and scan to see
623 * which one exactly matches the given argument types. (There will not be
624 * more than one match.)
626 * XXX at present, this code will not work in bootstrap mode, hence this
627 * datatype cannot be used for any system column that needs to receive
628 * data during bootstrap.
630 parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes);
631 if (nargs == 1)
632 ereport(ERROR,
633 (errcode(ERRCODE_UNDEFINED_PARAMETER),
634 errmsg("missing argument"),
635 errhint("Use NONE to denote the missing argument of a unary operator.")));
636 if (nargs != 2)
637 ereport(ERROR,
638 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
639 errmsg("too many arguments"),
640 errhint("Provide two argument types for operator.")));
642 result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
644 if (!OidIsValid(result))
645 ereport(ERROR,
646 (errcode(ERRCODE_UNDEFINED_FUNCTION),
647 errmsg("operator does not exist: %s", opr_name_or_oid)));
649 PG_RETURN_OID(result);
653 * format_operator - converts operator OID to "opr_name(args)"
655 * This exports the useful functionality of regoperatorout for use
656 * in other backend modules. The result is a palloc'd string.
658 char *
659 format_operator(Oid operator_oid)
661 char *result;
662 HeapTuple opertup;
664 opertup = SearchSysCache(OPEROID,
665 ObjectIdGetDatum(operator_oid),
666 0, 0, 0);
668 if (HeapTupleIsValid(opertup))
670 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
671 char *oprname = NameStr(operform->oprname);
672 char *nspname;
673 StringInfoData buf;
675 /* XXX no support here for bootstrap mode */
677 initStringInfo(&buf);
680 * Would this oper be found (given the right args) by regoperatorin?
681 * If not, we need to qualify it.
683 if (!OperatorIsVisible(operator_oid))
685 nspname = get_namespace_name(operform->oprnamespace);
686 appendStringInfo(&buf, "%s.",
687 quote_identifier(nspname));
690 appendStringInfo(&buf, "%s(", oprname);
692 if (operform->oprleft)
693 appendStringInfo(&buf, "%s,",
694 format_type_be(operform->oprleft));
695 else
696 appendStringInfo(&buf, "NONE,");
698 if (operform->oprright)
699 appendStringInfo(&buf, "%s)",
700 format_type_be(operform->oprright));
701 else
702 appendStringInfo(&buf, "NONE)");
704 result = buf.data;
706 ReleaseSysCache(opertup);
708 else
711 * If OID doesn't match any pg_operator entry, return it numerically
713 result = (char *) palloc(NAMEDATALEN);
714 snprintf(result, NAMEDATALEN, "%u", operator_oid);
717 return result;
721 * regoperatorout - converts operator OID to "opr_name(args)"
723 Datum
724 regoperatorout(PG_FUNCTION_ARGS)
726 Oid oprid = PG_GETARG_OID(0);
727 char *result;
729 if (oprid == InvalidOid)
730 result = pstrdup("0");
731 else
732 result = format_operator(oprid);
734 PG_RETURN_CSTRING(result);
738 * regoperatorrecv - converts external binary format to regoperator
740 Datum
741 regoperatorrecv(PG_FUNCTION_ARGS)
743 /* Exactly the same as oidrecv, so share code */
744 return oidrecv(fcinfo);
748 * regoperatorsend - converts regoperator to binary format
750 Datum
751 regoperatorsend(PG_FUNCTION_ARGS)
753 /* Exactly the same as oidsend, so share code */
754 return oidsend(fcinfo);
759 * regclassin - converts "classname" to class OID
761 * We also accept a numeric OID, for symmetry with the output routine.
763 * '-' signifies unknown (OID 0). In all other cases, the input must
764 * match an existing pg_class entry.
766 Datum
767 regclassin(PG_FUNCTION_ARGS)
769 char *class_name_or_oid = PG_GETARG_CSTRING(0);
770 Oid result = InvalidOid;
771 List *names;
773 /* '-' ? */
774 if (strcmp(class_name_or_oid, "-") == 0)
775 PG_RETURN_OID(InvalidOid);
777 /* Numeric OID? */
778 if (class_name_or_oid[0] >= '0' &&
779 class_name_or_oid[0] <= '9' &&
780 strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
782 result = DatumGetObjectId(DirectFunctionCall1(oidin,
783 CStringGetDatum(class_name_or_oid)));
784 PG_RETURN_OID(result);
787 /* Else it's a name, possibly schema-qualified */
790 * In bootstrap mode we assume the given name is not schema-qualified, and
791 * just search pg_class for a match. This is needed for initializing
792 * other system catalogs (pg_namespace may not exist yet, and certainly
793 * there are no schemas other than pg_catalog).
795 if (IsBootstrapProcessingMode())
797 Relation hdesc;
798 ScanKeyData skey[1];
799 SysScanDesc sysscan;
800 HeapTuple tuple;
802 ScanKeyInit(&skey[0],
803 Anum_pg_class_relname,
804 BTEqualStrategyNumber, F_NAMEEQ,
805 CStringGetDatum(class_name_or_oid));
807 hdesc = heap_open(RelationRelationId, AccessShareLock);
808 sysscan = systable_beginscan(hdesc, ClassNameNspIndexId, true,
809 SnapshotNow, 1, skey);
811 if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
812 result = HeapTupleGetOid(tuple);
813 else
814 ereport(ERROR,
815 (errcode(ERRCODE_UNDEFINED_TABLE),
816 errmsg("relation \"%s\" does not exist", class_name_or_oid)));
818 /* We assume there can be only one match */
820 systable_endscan(sysscan);
821 heap_close(hdesc, AccessShareLock);
823 PG_RETURN_OID(result);
827 * Normal case: parse the name into components and see if it matches any
828 * pg_class entries in the current search path.
830 names = stringToQualifiedNameList(class_name_or_oid);
832 result = RangeVarGetRelid(makeRangeVarFromNameList(names), false);
834 PG_RETURN_OID(result);
838 * regclassout - converts class OID to "class_name"
840 Datum
841 regclassout(PG_FUNCTION_ARGS)
843 Oid classid = PG_GETARG_OID(0);
844 char *result;
845 HeapTuple classtup;
847 if (classid == InvalidOid)
849 result = pstrdup("-");
850 PG_RETURN_CSTRING(result);
853 classtup = SearchSysCache(RELOID,
854 ObjectIdGetDatum(classid),
855 0, 0, 0);
857 if (HeapTupleIsValid(classtup))
859 Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
860 char *classname = NameStr(classform->relname);
863 * In bootstrap mode, skip the fancy namespace stuff and just return
864 * the class name. (This path is only needed for debugging output
865 * anyway.)
867 if (IsBootstrapProcessingMode())
868 result = pstrdup(classname);
869 else
871 char *nspname;
874 * Would this class be found by regclassin? If not, qualify it.
876 if (RelationIsVisible(classid))
877 nspname = NULL;
878 else
879 nspname = get_namespace_name(classform->relnamespace);
881 result = quote_qualified_identifier(nspname, classname);
884 ReleaseSysCache(classtup);
886 else
888 /* If OID doesn't match any pg_class entry, return it numerically */
889 result = (char *) palloc(NAMEDATALEN);
890 snprintf(result, NAMEDATALEN, "%u", classid);
893 PG_RETURN_CSTRING(result);
897 * regclassrecv - converts external binary format to regclass
899 Datum
900 regclassrecv(PG_FUNCTION_ARGS)
902 /* Exactly the same as oidrecv, so share code */
903 return oidrecv(fcinfo);
907 * regclasssend - converts regclass to binary format
909 Datum
910 regclasssend(PG_FUNCTION_ARGS)
912 /* Exactly the same as oidsend, so share code */
913 return oidsend(fcinfo);
918 * regtypein - converts "typename" to type OID
920 * We also accept a numeric OID, for symmetry with the output routine.
922 * '-' signifies unknown (OID 0). In all other cases, the input must
923 * match an existing pg_type entry.
925 * In bootstrap mode the name must just equal some existing name in pg_type.
926 * In normal mode the type name can be specified using the full type syntax
927 * recognized by the parser; for example, DOUBLE PRECISION and INTEGER[] will
928 * work and be translated to the correct type names. (We ignore any typmod
929 * info generated by the parser, however.)
931 Datum
932 regtypein(PG_FUNCTION_ARGS)
934 char *typ_name_or_oid = PG_GETARG_CSTRING(0);
935 Oid result = InvalidOid;
936 int32 typmod;
938 /* '-' ? */
939 if (strcmp(typ_name_or_oid, "-") == 0)
940 PG_RETURN_OID(InvalidOid);
942 /* Numeric OID? */
943 if (typ_name_or_oid[0] >= '0' &&
944 typ_name_or_oid[0] <= '9' &&
945 strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
947 result = DatumGetObjectId(DirectFunctionCall1(oidin,
948 CStringGetDatum(typ_name_or_oid)));
949 PG_RETURN_OID(result);
952 /* Else it's a type name, possibly schema-qualified or decorated */
955 * In bootstrap mode we assume the given name is not schema-qualified, and
956 * just search pg_type for a match. This is needed for initializing other
957 * system catalogs (pg_namespace may not exist yet, and certainly there
958 * are no schemas other than pg_catalog).
960 if (IsBootstrapProcessingMode())
962 Relation hdesc;
963 ScanKeyData skey[1];
964 SysScanDesc sysscan;
965 HeapTuple tuple;
967 ScanKeyInit(&skey[0],
968 Anum_pg_type_typname,
969 BTEqualStrategyNumber, F_NAMEEQ,
970 CStringGetDatum(typ_name_or_oid));
972 hdesc = heap_open(TypeRelationId, AccessShareLock);
973 sysscan = systable_beginscan(hdesc, TypeNameNspIndexId, true,
974 SnapshotNow, 1, skey);
976 if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
977 result = HeapTupleGetOid(tuple);
978 else
979 ereport(ERROR,
980 (errcode(ERRCODE_UNDEFINED_OBJECT),
981 errmsg("type \"%s\" does not exist", typ_name_or_oid)));
983 /* We assume there can be only one match */
985 systable_endscan(sysscan);
986 heap_close(hdesc, AccessShareLock);
988 PG_RETURN_OID(result);
992 * Normal case: invoke the full parser to deal with special cases such as
993 * array syntax.
995 parseTypeString(typ_name_or_oid, &result, &typmod);
997 PG_RETURN_OID(result);
1001 * regtypeout - converts type OID to "typ_name"
1003 Datum
1004 regtypeout(PG_FUNCTION_ARGS)
1006 Oid typid = PG_GETARG_OID(0);
1007 char *result;
1008 HeapTuple typetup;
1010 if (typid == InvalidOid)
1012 result = pstrdup("-");
1013 PG_RETURN_CSTRING(result);
1016 typetup = SearchSysCache(TYPEOID,
1017 ObjectIdGetDatum(typid),
1018 0, 0, 0);
1020 if (HeapTupleIsValid(typetup))
1022 Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup);
1025 * In bootstrap mode, skip the fancy namespace stuff and just return
1026 * the type name. (This path is only needed for debugging output
1027 * anyway.)
1029 if (IsBootstrapProcessingMode())
1031 char *typname = NameStr(typeform->typname);
1033 result = pstrdup(typname);
1035 else
1036 result = format_type_be(typid);
1038 ReleaseSysCache(typetup);
1040 else
1042 /* If OID doesn't match any pg_type entry, return it numerically */
1043 result = (char *) palloc(NAMEDATALEN);
1044 snprintf(result, NAMEDATALEN, "%u", typid);
1047 PG_RETURN_CSTRING(result);
1051 * regtyperecv - converts external binary format to regtype
1053 Datum
1054 regtyperecv(PG_FUNCTION_ARGS)
1056 /* Exactly the same as oidrecv, so share code */
1057 return oidrecv(fcinfo);
1061 * regtypesend - converts regtype to binary format
1063 Datum
1064 regtypesend(PG_FUNCTION_ARGS)
1066 /* Exactly the same as oidsend, so share code */
1067 return oidsend(fcinfo);
1072 * regconfigin - converts "tsconfigname" to tsconfig OID
1074 * We also accept a numeric OID, for symmetry with the output routine.
1076 * '-' signifies unknown (OID 0). In all other cases, the input must
1077 * match an existing pg_ts_config entry.
1079 * This function is not needed in bootstrap mode, so we don't worry about
1080 * making it work then.
1082 Datum
1083 regconfigin(PG_FUNCTION_ARGS)
1085 char *cfg_name_or_oid = PG_GETARG_CSTRING(0);
1086 Oid result;
1087 List *names;
1089 /* '-' ? */
1090 if (strcmp(cfg_name_or_oid, "-") == 0)
1091 PG_RETURN_OID(InvalidOid);
1093 /* Numeric OID? */
1094 if (cfg_name_or_oid[0] >= '0' &&
1095 cfg_name_or_oid[0] <= '9' &&
1096 strspn(cfg_name_or_oid, "0123456789") == strlen(cfg_name_or_oid))
1098 result = DatumGetObjectId(DirectFunctionCall1(oidin,
1099 CStringGetDatum(cfg_name_or_oid)));
1100 PG_RETURN_OID(result);
1104 * Normal case: parse the name into components and see if it matches any
1105 * pg_ts_config entries in the current search path.
1107 names = stringToQualifiedNameList(cfg_name_or_oid);
1109 result = TSConfigGetCfgid(names, false);
1111 PG_RETURN_OID(result);
1115 * regconfigout - converts tsconfig OID to "tsconfigname"
1117 Datum
1118 regconfigout(PG_FUNCTION_ARGS)
1120 Oid cfgid = PG_GETARG_OID(0);
1121 char *result;
1122 HeapTuple cfgtup;
1124 if (cfgid == InvalidOid)
1126 result = pstrdup("-");
1127 PG_RETURN_CSTRING(result);
1130 cfgtup = SearchSysCache(TSCONFIGOID,
1131 ObjectIdGetDatum(cfgid),
1132 0, 0, 0);
1134 if (HeapTupleIsValid(cfgtup))
1136 Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
1137 char *cfgname = NameStr(cfgform->cfgname);
1138 char *nspname;
1141 * Would this config be found by regconfigin? If not, qualify it.
1143 if (TSConfigIsVisible(cfgid))
1144 nspname = NULL;
1145 else
1146 nspname = get_namespace_name(cfgform->cfgnamespace);
1148 result = quote_qualified_identifier(nspname, cfgname);
1150 ReleaseSysCache(cfgtup);
1152 else
1154 /* If OID doesn't match any pg_ts_config row, return it numerically */
1155 result = (char *) palloc(NAMEDATALEN);
1156 snprintf(result, NAMEDATALEN, "%u", cfgid);
1159 PG_RETURN_CSTRING(result);
1163 * regconfigrecv - converts external binary format to regconfig
1165 Datum
1166 regconfigrecv(PG_FUNCTION_ARGS)
1168 /* Exactly the same as oidrecv, so share code */
1169 return oidrecv(fcinfo);
1173 * regconfigsend - converts regconfig to binary format
1175 Datum
1176 regconfigsend(PG_FUNCTION_ARGS)
1178 /* Exactly the same as oidsend, so share code */
1179 return oidsend(fcinfo);
1184 * regdictionaryin - converts "tsdictionaryname" to tsdictionary OID
1186 * We also accept a numeric OID, for symmetry with the output routine.
1188 * '-' signifies unknown (OID 0). In all other cases, the input must
1189 * match an existing pg_ts_dict entry.
1191 * This function is not needed in bootstrap mode, so we don't worry about
1192 * making it work then.
1194 Datum
1195 regdictionaryin(PG_FUNCTION_ARGS)
1197 char *dict_name_or_oid = PG_GETARG_CSTRING(0);
1198 Oid result;
1199 List *names;
1201 /* '-' ? */
1202 if (strcmp(dict_name_or_oid, "-") == 0)
1203 PG_RETURN_OID(InvalidOid);
1205 /* Numeric OID? */
1206 if (dict_name_or_oid[0] >= '0' &&
1207 dict_name_or_oid[0] <= '9' &&
1208 strspn(dict_name_or_oid, "0123456789") == strlen(dict_name_or_oid))
1210 result = DatumGetObjectId(DirectFunctionCall1(oidin,
1211 CStringGetDatum(dict_name_or_oid)));
1212 PG_RETURN_OID(result);
1216 * Normal case: parse the name into components and see if it matches any
1217 * pg_ts_dict entries in the current search path.
1219 names = stringToQualifiedNameList(dict_name_or_oid);
1221 result = TSDictionaryGetDictid(names, false);
1223 PG_RETURN_OID(result);
1227 * regdictionaryout - converts tsdictionary OID to "tsdictionaryname"
1229 Datum
1230 regdictionaryout(PG_FUNCTION_ARGS)
1232 Oid dictid = PG_GETARG_OID(0);
1233 char *result;
1234 HeapTuple dicttup;
1236 if (dictid == InvalidOid)
1238 result = pstrdup("-");
1239 PG_RETURN_CSTRING(result);
1242 dicttup = SearchSysCache(TSDICTOID,
1243 ObjectIdGetDatum(dictid),
1244 0, 0, 0);
1246 if (HeapTupleIsValid(dicttup))
1248 Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
1249 char *dictname = NameStr(dictform->dictname);
1250 char *nspname;
1253 * Would this dictionary be found by regdictionaryin? If not, qualify
1254 * it.
1256 if (TSDictionaryIsVisible(dictid))
1257 nspname = NULL;
1258 else
1259 nspname = get_namespace_name(dictform->dictnamespace);
1261 result = quote_qualified_identifier(nspname, dictname);
1263 ReleaseSysCache(dicttup);
1265 else
1267 /* If OID doesn't match any pg_ts_dict row, return it numerically */
1268 result = (char *) palloc(NAMEDATALEN);
1269 snprintf(result, NAMEDATALEN, "%u", dictid);
1272 PG_RETURN_CSTRING(result);
1276 * regdictionaryrecv - converts external binary format to regdictionary
1278 Datum
1279 regdictionaryrecv(PG_FUNCTION_ARGS)
1281 /* Exactly the same as oidrecv, so share code */
1282 return oidrecv(fcinfo);
1286 * regdictionarysend - converts regdictionary to binary format
1288 Datum
1289 regdictionarysend(PG_FUNCTION_ARGS)
1291 /* Exactly the same as oidsend, so share code */
1292 return oidsend(fcinfo);
1297 * text_regclass: convert text to regclass
1299 * This could be replaced by CoerceViaIO, except that we need to treat
1300 * text-to-regclass as an implicit cast to support legacy forms of nextval()
1301 * and related functions.
1303 Datum
1304 text_regclass(PG_FUNCTION_ARGS)
1306 text *relname = PG_GETARG_TEXT_P(0);
1307 Oid result;
1308 RangeVar *rv;
1310 rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
1311 result = RangeVarGetRelid(rv, false);
1313 PG_RETURN_OID(result);
1318 * Given a C string, parse it into a qualified-name list.
1320 List *
1321 stringToQualifiedNameList(const char *string)
1323 char *rawname;
1324 List *result = NIL;
1325 List *namelist;
1326 ListCell *l;
1328 /* We need a modifiable copy of the input string. */
1329 rawname = pstrdup(string);
1331 if (!SplitIdentifierString(rawname, '.', &namelist))
1332 ereport(ERROR,
1333 (errcode(ERRCODE_INVALID_NAME),
1334 errmsg("invalid name syntax")));
1336 if (namelist == NIL)
1337 ereport(ERROR,
1338 (errcode(ERRCODE_INVALID_NAME),
1339 errmsg("invalid name syntax")));
1341 foreach(l, namelist)
1343 char *curname = (char *) lfirst(l);
1345 result = lappend(result, makeString(pstrdup(curname)));
1348 pfree(rawname);
1349 list_free(namelist);
1351 return result;
1354 /*****************************************************************************
1355 * SUPPORT ROUTINES *
1356 *****************************************************************************/
1359 * Given a C string, parse it into a qualified function or operator name
1360 * followed by a parenthesized list of type names. Reduce the
1361 * type names to an array of OIDs (returned into *nargs and *argtypes;
1362 * the argtypes array should be of size FUNC_MAX_ARGS). The function or
1363 * operator name is returned to *names as a List of Strings.
1365 * If allowNone is TRUE, accept "NONE" and return it as InvalidOid (this is
1366 * for unary operators).
1368 static void
1369 parseNameAndArgTypes(const char *string, bool allowNone, List **names,
1370 int *nargs, Oid *argtypes)
1372 char *rawname;
1373 char *ptr;
1374 char *ptr2;
1375 char *typename;
1376 bool in_quote;
1377 bool had_comma;
1378 int paren_count;
1379 Oid typeid;
1380 int32 typmod;
1382 /* We need a modifiable copy of the input string. */
1383 rawname = pstrdup(string);
1385 /* Scan to find the expected left paren; mustn't be quoted */
1386 in_quote = false;
1387 for (ptr = rawname; *ptr; ptr++)
1389 if (*ptr == '"')
1390 in_quote = !in_quote;
1391 else if (*ptr == '(' && !in_quote)
1392 break;
1394 if (*ptr == '\0')
1395 ereport(ERROR,
1396 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1397 errmsg("expected a left parenthesis")));
1399 /* Separate the name and parse it into a list */
1400 *ptr++ = '\0';
1401 *names = stringToQualifiedNameList(rawname);
1403 /* Check for the trailing right parenthesis and remove it */
1404 ptr2 = ptr + strlen(ptr);
1405 while (--ptr2 > ptr)
1407 if (!isspace((unsigned char) *ptr2))
1408 break;
1410 if (*ptr2 != ')')
1411 ereport(ERROR,
1412 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1413 errmsg("expected a right parenthesis")));
1415 *ptr2 = '\0';
1417 /* Separate the remaining string into comma-separated type names */
1418 *nargs = 0;
1419 had_comma = false;
1421 for (;;)
1423 /* allow leading whitespace */
1424 while (isspace((unsigned char) *ptr))
1425 ptr++;
1426 if (*ptr == '\0')
1428 /* End of string. Okay unless we had a comma before. */
1429 if (had_comma)
1430 ereport(ERROR,
1431 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1432 errmsg("expected a type name")));
1433 break;
1435 typename = ptr;
1436 /* Find end of type name --- end of string or comma */
1437 /* ... but not a quoted or parenthesized comma */
1438 in_quote = false;
1439 paren_count = 0;
1440 for (; *ptr; ptr++)
1442 if (*ptr == '"')
1443 in_quote = !in_quote;
1444 else if (*ptr == ',' && !in_quote && paren_count == 0)
1445 break;
1446 else if (!in_quote)
1448 switch (*ptr)
1450 case '(':
1451 case '[':
1452 paren_count++;
1453 break;
1454 case ')':
1455 case ']':
1456 paren_count--;
1457 break;
1461 if (in_quote || paren_count != 0)
1462 ereport(ERROR,
1463 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1464 errmsg("improper type name")));
1466 ptr2 = ptr;
1467 if (*ptr == ',')
1469 had_comma = true;
1470 *ptr++ = '\0';
1472 else
1474 had_comma = false;
1475 Assert(*ptr == '\0');
1477 /* Lop off trailing whitespace */
1478 while (--ptr2 >= typename)
1480 if (!isspace((unsigned char) *ptr2))
1481 break;
1482 *ptr2 = '\0';
1485 if (allowNone && pg_strcasecmp(typename, "none") == 0)
1487 /* Special case for NONE */
1488 typeid = InvalidOid;
1489 typmod = -1;
1491 else
1493 /* Use full parser to resolve the type name */
1494 parseTypeString(typename, &typeid, &typmod);
1496 if (*nargs >= FUNC_MAX_ARGS)
1497 ereport(ERROR,
1498 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
1499 errmsg("too many arguments")));
1501 argtypes[*nargs] = typeid;
1502 (*nargs)++;
1505 pfree(rawname);