]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/regproc.c
Implement types regprocedure, regoper, regoperator, regclass, regtype
[postgresql] / src / backend / utils / adt / regproc.c
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-2001, PostgreSQL Global Development Group
12  * Portions Copyright (c) 1994, Regents of the University of California
13  *
14  *
15  * IDENTIFICATION
16  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.66 2002/04/25 02:56:55 tgl Exp $
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 "catalog/catname.h"
27 #include "catalog/indexing.h"
28 #include "catalog/namespace.h"
29 #include "catalog/pg_operator.h"
30 #include "catalog/pg_proc.h"
31 #include "catalog/pg_type.h"
32 #include "lib/stringinfo.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
40
41 static List *stringToQualifiedNameList(const char *string, const char *caller);
42 static void parseNameAndArgTypes(const char *string, const char *caller,
43                                                                  bool allow_none,
44                                                                  List **names, int *nargs, Oid *argtypes);
45
46
47 /*****************************************************************************
48  *       USER I/O ROUTINES                                                                                                               *
49  *****************************************************************************/
50
51 /*
52  * regprocin            - converts "proname" to proc OID
53  *
54  * We also accept a numeric OID, mostly for historical reasons.
55  *
56  * '-' signifies unknown (OID 0).  In all other cases, the input must
57  * match an existing pg_proc entry.
58  */
59 Datum
60 regprocin(PG_FUNCTION_ARGS)
61 {
62         char       *pro_name_or_oid = PG_GETARG_CSTRING(0);
63         RegProcedure result = InvalidOid;
64         List       *names;
65         FuncCandidateList clist;
66
67         /* '-' ? */
68         if (strcmp(pro_name_or_oid, "-") == 0)
69                 PG_RETURN_OID(InvalidOid);
70
71         /* Numeric OID? */
72         if (pro_name_or_oid[0] >= '0' &&
73                 pro_name_or_oid[0] <= '9' &&
74                 strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
75         {
76                 Oid                     searchOid;
77
78                 searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
79                                                                           CStringGetDatum(pro_name_or_oid)));
80                 result = (RegProcedure) GetSysCacheOid(PROCOID,
81                                                                                          ObjectIdGetDatum(searchOid),
82                                                                                            0, 0, 0);
83                 if (!RegProcedureIsValid(result))
84                         elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
85                 PG_RETURN_OID(result);
86         }
87
88         /* Else it's a name, possibly schema-qualified */
89
90         /*
91          * In bootstrap mode we assume the given name is not schema-qualified,
92          * and just search pg_proc for a unique match.  This is needed for
93          * initializing other system catalogs (pg_namespace may not exist yet,
94          * and certainly there are no schemas other than pg_catalog).
95          */
96         if (IsBootstrapProcessingMode())
97         {
98                 int                     matches = 0;
99                 Relation        hdesc;
100                 ScanKeyData skey[1];
101                 SysScanDesc     sysscan;
102                 HeapTuple       tuple;
103
104                 ScanKeyEntryInitialize(&skey[0], 0x0,
105                                                            (AttrNumber) Anum_pg_proc_proname,
106                                                            (RegProcedure) F_NAMEEQ,
107                                                            CStringGetDatum(pro_name_or_oid));
108
109                 hdesc = heap_openr(ProcedureRelationName, AccessShareLock);
110                 sysscan = systable_beginscan(hdesc, ProcedureNameNspIndex, true,
111                                                                          SnapshotNow, 1, skey);
112
113                 while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
114                 {
115                         result = (RegProcedure) tuple->t_data->t_oid;
116                         if (++matches > 1)
117                                 break;
118                 }
119
120                 systable_endscan(sysscan);
121                 heap_close(hdesc, AccessShareLock);
122
123                 if (matches == 0)
124                         elog(ERROR, "No procedure with name %s", pro_name_or_oid);
125                 else if (matches > 1)
126                         elog(ERROR, "There is more than one procedure named %s",
127                                  pro_name_or_oid);
128                 PG_RETURN_OID(result);
129         }
130
131         /*
132          * Normal case: parse the name into components and see if it
133          * matches any pg_proc entries in the current search path.
134          */
135         names = stringToQualifiedNameList(pro_name_or_oid, "regprocin");
136         clist = FuncnameGetCandidates(names, -1);
137
138         if (clist == NULL)
139                 elog(ERROR, "No procedure with name %s", pro_name_or_oid);
140         else if (clist->next != NULL)
141                 elog(ERROR, "There is more than one procedure named %s",
142                          pro_name_or_oid);
143
144         result = clist->oid;
145
146         PG_RETURN_OID(result);
147 }
148
149 /*
150  * regprocout           - converts proc OID to "pro_name"
151  */
152 Datum
153 regprocout(PG_FUNCTION_ARGS)
154 {
155         RegProcedure proid = PG_GETARG_OID(0);
156         char       *result;
157         HeapTuple       proctup;
158
159         if (proid == InvalidOid)
160         {
161                 result = pstrdup("-");
162                 PG_RETURN_CSTRING(result);
163         }
164
165         proctup = SearchSysCache(PROCOID,
166                                                          ObjectIdGetDatum(proid),
167                                                          0, 0, 0);
168
169         if (HeapTupleIsValid(proctup))
170         {
171                 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
172                 char       *proname = NameStr(procform->proname);
173
174                 /*
175                  * In bootstrap mode, skip the fancy namespace stuff and just
176                  * return the proc name.  (This path is only needed for debugging
177                  * output anyway.)
178                  */
179                 if (IsBootstrapProcessingMode())
180                 {
181                         result = pstrdup(proname);
182                 }
183                 else
184                 {
185                         char       *nspname;
186                         FuncCandidateList clist;
187
188                         /*
189                          * Would this proc be found (uniquely!) by regprocin?
190                          * If not, qualify it.
191                          */
192                         clist = FuncnameGetCandidates(makeList1(makeString(proname)), -1);
193                         if (clist != NULL && clist->next == NULL &&
194                                 clist->oid == proid)
195                                 nspname = NULL;
196                         else
197                                 nspname = get_namespace_name(procform->pronamespace);
198
199                         result = quote_qualified_identifier(nspname, proname);
200                 }
201
202                 ReleaseSysCache(proctup);
203         }
204         else
205         {
206                 /* If OID doesn't match any pg_proc entry, return it numerically */
207                 result = (char *) palloc(NAMEDATALEN);
208                 snprintf(result, NAMEDATALEN, "%u", proid);
209         }
210
211         PG_RETURN_CSTRING(result);
212 }
213
214
215 /*
216  * regprocedurein               - converts "proname(args)" to proc OID
217  *
218  * We also accept a numeric OID, mostly for historical reasons.
219  *
220  * '-' signifies unknown (OID 0).  In all other cases, the input must
221  * match an existing pg_proc entry.
222  */
223 Datum
224 regprocedurein(PG_FUNCTION_ARGS)
225 {
226         char       *pro_name_or_oid = PG_GETARG_CSTRING(0);
227         RegProcedure result = InvalidOid;
228         List       *names;
229         int                     nargs;
230         Oid                     argtypes[FUNC_MAX_ARGS];
231         FuncCandidateList clist;
232
233         /* '-' ? */
234         if (strcmp(pro_name_or_oid, "-") == 0)
235                 PG_RETURN_OID(InvalidOid);
236
237         /* Numeric OID? */
238         if (pro_name_or_oid[0] >= '0' &&
239                 pro_name_or_oid[0] <= '9' &&
240                 strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
241         {
242                 Oid                     searchOid;
243
244                 searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
245                                                                           CStringGetDatum(pro_name_or_oid)));
246                 result = (RegProcedure) GetSysCacheOid(PROCOID,
247                                                                                          ObjectIdGetDatum(searchOid),
248                                                                                            0, 0, 0);
249                 if (!RegProcedureIsValid(result))
250                         elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
251                 PG_RETURN_OID(result);
252         }
253
254         /*
255          * Else it's a name and arguments.  Parse the name and arguments,
256          * look up potential matches in the current namespace search list,
257          * and scan to see which one exactly matches the given argument
258          * types.  (There will not be more than one match.)
259          *
260          * XXX at present, this code will not work in bootstrap mode, hence this
261          * datatype cannot be used for any system column that needs to receive
262          * data during bootstrap.
263          */
264         parseNameAndArgTypes(pro_name_or_oid, "regprocedurein", false,
265                                                  &names, &nargs, argtypes);
266
267         clist = FuncnameGetCandidates(names, nargs);
268
269         for (; clist; clist = clist->next)
270         {
271                 if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
272                         break;
273         }
274
275         if (clist == NULL)
276                 elog(ERROR, "No procedure with name %s", pro_name_or_oid);
277
278         result = clist->oid;
279
280         PG_RETURN_OID(result);
281 }
282
283 /*
284  * regprocedureout              - converts proc OID to "pro_name(args)"
285  */
286 Datum
287 regprocedureout(PG_FUNCTION_ARGS)
288 {
289         RegProcedure proid = PG_GETARG_OID(0);
290         char       *result;
291         HeapTuple       proctup;
292
293         if (proid == InvalidOid)
294         {
295                 result = pstrdup("-");
296                 PG_RETURN_CSTRING(result);
297         }
298
299         proctup = SearchSysCache(PROCOID,
300                                                          ObjectIdGetDatum(proid),
301                                                          0, 0, 0);
302
303         if (HeapTupleIsValid(proctup))
304         {
305                 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
306                 char       *proname = NameStr(procform->proname);
307                 int                     nargs = procform->pronargs;
308                 int                     i;
309                 char       *nspname;
310                 FuncCandidateList clist;
311                 StringInfoData buf;
312
313                 /* XXX no support here for bootstrap mode */
314
315                 /*
316                  * Would this proc be found (given the right args) by regprocedurein?
317                  * If not, we need to qualify it.
318                  */
319                 clist = FuncnameGetCandidates(makeList1(makeString(proname)), nargs);
320
321                 for (; clist; clist = clist->next)
322                 {
323                         if (memcmp(clist->args, procform->proargtypes,
324                                            nargs * sizeof(Oid)) == 0)
325                                 break;
326                 }
327
328                 if (clist != NULL && clist->oid == proid)
329                         nspname = NULL;
330                 else
331                         nspname = get_namespace_name(procform->pronamespace);
332
333                 initStringInfo(&buf);
334
335                 appendStringInfo(&buf, "%s(",
336                                                  quote_qualified_identifier(nspname, proname));
337                 for (i = 0; i < nargs; i++)
338                 {
339                         appendStringInfo(&buf, "%s%s",
340                                                          (i > 0) ? "," : "",
341                                                          format_type_be(procform->proargtypes[i]));
342                 }
343
344                 appendStringInfo(&buf, ")");
345
346                 result = buf.data;
347
348                 ReleaseSysCache(proctup);
349         }
350         else
351         {
352                 /* If OID doesn't match any pg_proc entry, return it numerically */
353                 result = (char *) palloc(NAMEDATALEN);
354                 snprintf(result, NAMEDATALEN, "%u", proid);
355         }
356
357         PG_RETURN_CSTRING(result);
358 }
359
360
361 /*
362  * regoperin            - converts "oprname" to operator OID
363  *
364  * We also accept a numeric OID, mostly for historical reasons.
365  *
366  * '0' signifies unknown (OID 0).  In all other cases, the input must
367  * match an existing pg_operator entry.
368  */
369 Datum
370 regoperin(PG_FUNCTION_ARGS)
371 {
372         char       *opr_name_or_oid = PG_GETARG_CSTRING(0);
373         Oid                     result = InvalidOid;
374         List       *names;
375         FuncCandidateList clist;
376
377         /* '0' ? */
378         if (strcmp(opr_name_or_oid, "0") == 0)
379                 PG_RETURN_OID(InvalidOid);
380
381         /* Numeric OID? */
382         if (opr_name_or_oid[0] >= '0' &&
383                 opr_name_or_oid[0] <= '9' &&
384                 strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
385         {
386                 Oid                     searchOid;
387
388                 searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
389                                                                           CStringGetDatum(opr_name_or_oid)));
390                 result = GetSysCacheOid(OPEROID,
391                                                                 ObjectIdGetDatum(searchOid),
392                                                                 0, 0, 0);
393                 if (!OidIsValid(result))
394                         elog(ERROR, "No operator with oid %s", opr_name_or_oid);
395                 PG_RETURN_OID(result);
396         }
397
398         /* Else it's a name, possibly schema-qualified */
399
400         /*
401          * In bootstrap mode we assume the given name is not schema-qualified,
402          * and just search pg_operator for a unique match.  This is needed for
403          * initializing other system catalogs (pg_namespace may not exist yet,
404          * and certainly there are no schemas other than pg_catalog).
405          */
406         if (IsBootstrapProcessingMode())
407         {
408                 int                     matches = 0;
409                 Relation        hdesc;
410                 ScanKeyData skey[1];
411                 SysScanDesc     sysscan;
412                 HeapTuple       tuple;
413
414                 ScanKeyEntryInitialize(&skey[0], 0x0,
415                                                            (AttrNumber) Anum_pg_operator_oprname,
416                                                            (RegProcedure) F_NAMEEQ,
417                                                            CStringGetDatum(opr_name_or_oid));
418
419                 hdesc = heap_openr(OperatorRelationName, AccessShareLock);
420                 sysscan = systable_beginscan(hdesc, OperatorNameNspIndex, true,
421                                                                          SnapshotNow, 1, skey);
422
423                 while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
424                 {
425                         result = tuple->t_data->t_oid;
426                         if (++matches > 1)
427                                 break;
428                 }
429
430                 systable_endscan(sysscan);
431                 heap_close(hdesc, AccessShareLock);
432
433                 if (matches == 0)
434                         elog(ERROR, "No operator with name %s", opr_name_or_oid);
435                 else if (matches > 1)
436                         elog(ERROR, "There is more than one operator named %s",
437                                  opr_name_or_oid);
438                 PG_RETURN_OID(result);
439         }
440
441         /*
442          * Normal case: parse the name into components and see if it
443          * matches any pg_operator entries in the current search path.
444          */
445         names = stringToQualifiedNameList(opr_name_or_oid, "regoperin");
446         clist = OpernameGetCandidates(names, '\0');
447
448         if (clist == NULL)
449                 elog(ERROR, "No operator with name %s", opr_name_or_oid);
450         else if (clist->next != NULL)
451                 elog(ERROR, "There is more than one operator named %s",
452                          opr_name_or_oid);
453
454         result = clist->oid;
455
456         PG_RETURN_OID(result);
457 }
458
459 /*
460  * regoperout           - converts operator OID to "opr_name"
461  */
462 Datum
463 regoperout(PG_FUNCTION_ARGS)
464 {
465         Oid                     oprid = PG_GETARG_OID(0);
466         char       *result;
467         HeapTuple       opertup;
468
469         if (oprid == InvalidOid)
470         {
471                 result = pstrdup("0");
472                 PG_RETURN_CSTRING(result);
473         }
474
475         opertup = SearchSysCache(OPEROID,
476                                                          ObjectIdGetDatum(oprid),
477                                                          0, 0, 0);
478
479         if (HeapTupleIsValid(opertup))
480         {
481                 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
482                 char       *oprname = NameStr(operform->oprname);
483
484                 /*
485                  * In bootstrap mode, skip the fancy namespace stuff and just
486                  * return the oper name.  (This path is only needed for debugging
487                  * output anyway.)
488                  */
489                 if (IsBootstrapProcessingMode())
490                 {
491                         result = pstrdup(oprname);
492                 }
493                 else
494                 {
495                         FuncCandidateList clist;
496
497                         /*
498                          * Would this oper be found (uniquely!) by regoperin?
499                          * If not, qualify it.
500                          */
501                         clist = OpernameGetCandidates(makeList1(makeString(oprname)),
502                                                                                   '\0');
503                         if (clist != NULL && clist->next == NULL &&
504                                 clist->oid == oprid)
505                                 result = pstrdup(oprname);
506                         else
507                         {
508                                 const char *nspname;
509
510                                 nspname = get_namespace_name(operform->oprnamespace);
511                                 nspname = quote_identifier(nspname);
512                                 result = (char *) palloc(strlen(nspname)+strlen(oprname)+2);
513                                 sprintf(result, "%s.%s", nspname, oprname);
514                         }
515                 }
516
517                 ReleaseSysCache(opertup);
518         }
519         else
520         {
521                 /* If OID doesn't match any pg_operator entry, return it numerically */
522                 result = (char *) palloc(NAMEDATALEN);
523                 snprintf(result, NAMEDATALEN, "%u", oprid);
524         }
525
526         PG_RETURN_CSTRING(result);
527 }
528
529
530 /*
531  * regoperatorin                - converts "oprname(args)" to operator OID
532  *
533  * We also accept a numeric OID, mostly for historical reasons.
534  *
535  * '0' signifies unknown (OID 0).  In all other cases, the input must
536  * match an existing pg_operator entry.
537  */
538 Datum
539 regoperatorin(PG_FUNCTION_ARGS)
540 {
541         char       *opr_name_or_oid = PG_GETARG_CSTRING(0);
542         Oid                     result = InvalidOid;
543         List       *names;
544         int                     nargs;
545         Oid                     argtypes[FUNC_MAX_ARGS];
546         char            oprkind;
547         FuncCandidateList clist;
548
549         /* '0' ? */
550         if (strcmp(opr_name_or_oid, "0") == 0)
551                 PG_RETURN_OID(InvalidOid);
552
553         /* Numeric OID? */
554         if (opr_name_or_oid[0] >= '0' &&
555                 opr_name_or_oid[0] <= '9' &&
556                 strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
557         {
558                 Oid                     searchOid;
559
560                 searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
561                                                                           CStringGetDatum(opr_name_or_oid)));
562                 result = GetSysCacheOid(OPEROID,
563                                                                 ObjectIdGetDatum(searchOid),
564                                                                 0, 0, 0);
565                 if (!OidIsValid(result))
566                         elog(ERROR, "No operator with oid %s", opr_name_or_oid);
567                 PG_RETURN_OID(result);
568         }
569
570         /*
571          * Else it's a name and arguments.  Parse the name and arguments,
572          * look up potential matches in the current namespace search list,
573          * and scan to see which one exactly matches the given argument
574          * types.  (There will not be more than one match.)
575          *
576          * XXX at present, this code will not work in bootstrap mode, hence this
577          * datatype cannot be used for any system column that needs to receive
578          * data during bootstrap.
579          */
580         parseNameAndArgTypes(opr_name_or_oid, "regoperatorin", true,
581                                                  &names, &nargs, argtypes);
582         if (nargs == 1)
583                 elog(ERROR, "regoperatorin: use NONE to denote the missing argument of a unary operator");
584         if (nargs != 2)
585                 elog(ERROR, "regoperatorin: provide two argument types for operator");
586
587         if (argtypes[0] == InvalidOid)
588                 oprkind = 'l';
589         else if (argtypes[1] == InvalidOid)
590                 oprkind = 'r';
591         else
592                 oprkind = 'b';
593
594         clist = OpernameGetCandidates(names, oprkind);
595
596         for (; clist; clist = clist->next)
597         {
598                 if (memcmp(clist->args, argtypes, 2 * sizeof(Oid)) == 0)
599                         break;
600         }
601
602         if (clist == NULL)
603                 elog(ERROR, "No operator with name %s", opr_name_or_oid);
604
605         result = clist->oid;
606
607         PG_RETURN_OID(result);
608 }
609
610 /*
611  * regoperatorout               - converts operator OID to "opr_name(args)"
612  */
613 Datum
614 regoperatorout(PG_FUNCTION_ARGS)
615 {
616         Oid                     oprid = PG_GETARG_OID(0);
617         char       *result;
618         HeapTuple       opertup;
619
620         if (oprid == InvalidOid)
621         {
622                 result = pstrdup("0");
623                 PG_RETURN_CSTRING(result);
624         }
625
626         opertup = SearchSysCache(OPEROID,
627                                                          ObjectIdGetDatum(oprid),
628                                                          0, 0, 0);
629
630         if (HeapTupleIsValid(opertup))
631         {
632                 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
633                 char       *oprname = NameStr(operform->oprname);
634                 char       *nspname;
635                 FuncCandidateList clist;
636                 StringInfoData buf;
637
638                 /* XXX no support here for bootstrap mode */
639
640                 /*
641                  * Would this oper be found (given the right args) by regoperatorin?
642                  * If not, we need to qualify it.
643                  */
644                 clist = OpernameGetCandidates(makeList1(makeString(oprname)),
645                                                                           operform->oprkind);
646
647                 for (; clist; clist = clist->next)
648                 {
649                         if (clist->args[0] == operform->oprleft &&
650                                 clist->args[1] == operform->oprright)
651                                 break;
652                 }
653
654                 initStringInfo(&buf);
655
656                 if (clist == NULL || clist->oid != oprid)
657                 {
658                         nspname = get_namespace_name(operform->oprnamespace);
659                         appendStringInfo(&buf, "%s.",
660                                                          quote_identifier(nspname));
661                 }
662
663                 appendStringInfo(&buf, "%s(", oprname);
664
665                 if (operform->oprleft)
666                         appendStringInfo(&buf, "%s,",
667                                                          format_type_be(operform->oprleft));
668                 else
669                         appendStringInfo(&buf, "NONE,");
670
671                 if (operform->oprright)
672                         appendStringInfo(&buf, "%s)",
673                                                          format_type_be(operform->oprright));
674                 else
675                         appendStringInfo(&buf, "NONE)");
676
677                 result = buf.data;
678
679                 ReleaseSysCache(opertup);
680         }
681         else
682         {
683                 /* If OID doesn't match any pg_operator entry, return it numerically */
684                 result = (char *) palloc(NAMEDATALEN);
685                 snprintf(result, NAMEDATALEN, "%u", oprid);
686         }
687
688         PG_RETURN_CSTRING(result);
689 }
690
691
692 /*
693  * regclassin           - converts "classname" to class OID
694  *
695  * We also accept a numeric OID, mostly for historical reasons.
696  *
697  * '-' signifies unknown (OID 0).  In all other cases, the input must
698  * match an existing pg_class entry.
699  */
700 Datum
701 regclassin(PG_FUNCTION_ARGS)
702 {
703         char       *class_name_or_oid = PG_GETARG_CSTRING(0);
704         Oid                     result = InvalidOid;
705         List       *names;
706
707         /* '-' ? */
708         if (strcmp(class_name_or_oid, "-") == 0)
709                 PG_RETURN_OID(InvalidOid);
710
711         /* Numeric OID? */
712         if (class_name_or_oid[0] >= '0' &&
713                 class_name_or_oid[0] <= '9' &&
714                 strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
715         {
716                 Oid                     searchOid;
717
718                 searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
719                                                                           CStringGetDatum(class_name_or_oid)));
720                 result = GetSysCacheOid(RELOID,
721                                                                 ObjectIdGetDatum(searchOid),
722                                                                 0, 0, 0);
723                 if (!OidIsValid(result))
724                         elog(ERROR, "No class with oid %s", class_name_or_oid);
725                 PG_RETURN_OID(result);
726         }
727
728         /* Else it's a name, possibly schema-qualified */
729
730         /*
731          * In bootstrap mode we assume the given name is not schema-qualified,
732          * and just search pg_class for a match.  This is needed for
733          * initializing other system catalogs (pg_namespace may not exist yet,
734          * and certainly there are no schemas other than pg_catalog).
735          */
736         if (IsBootstrapProcessingMode())
737         {
738                 Relation        hdesc;
739                 ScanKeyData skey[1];
740                 SysScanDesc     sysscan;
741                 HeapTuple       tuple;
742
743                 ScanKeyEntryInitialize(&skey[0], 0x0,
744                                                            (AttrNumber) Anum_pg_class_relname,
745                                                            (RegProcedure) F_NAMEEQ,
746                                                            CStringGetDatum(class_name_or_oid));
747
748                 hdesc = heap_openr(RelationRelationName, AccessShareLock);
749                 sysscan = systable_beginscan(hdesc, ClassNameNspIndex, true,
750                                                                          SnapshotNow, 1, skey);
751
752                 if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
753                         result = tuple->t_data->t_oid;
754                 else
755                         elog(ERROR, "No class with name %s", class_name_or_oid);
756
757                 /* We assume there can be only one match */
758
759                 systable_endscan(sysscan);
760                 heap_close(hdesc, AccessShareLock);
761
762                 PG_RETURN_OID(result);
763         }
764
765         /*
766          * Normal case: parse the name into components and see if it
767          * matches any pg_class entries in the current search path.
768          */
769         names = stringToQualifiedNameList(class_name_or_oid, "regclassin");
770
771         result = RangeVarGetRelid(makeRangeVarFromNameList(names), false);
772
773         PG_RETURN_OID(result);
774 }
775
776 /*
777  * regclassout          - converts class OID to "class_name"
778  */
779 Datum
780 regclassout(PG_FUNCTION_ARGS)
781 {
782         Oid                     classid = PG_GETARG_OID(0);
783         char       *result;
784         HeapTuple       classtup;
785
786         if (classid == InvalidOid)
787         {
788                 result = pstrdup("-");
789                 PG_RETURN_CSTRING(result);
790         }
791
792         classtup = SearchSysCache(RELOID,
793                                                           ObjectIdGetDatum(classid),
794                                                           0, 0, 0);
795
796         if (HeapTupleIsValid(classtup))
797         {
798                 Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
799                 char       *classname = NameStr(classform->relname);
800
801                 /*
802                  * In bootstrap mode, skip the fancy namespace stuff and just
803                  * return the class name.  (This path is only needed for debugging
804                  * output anyway.)
805                  */
806                 if (IsBootstrapProcessingMode())
807                 {
808                         result = pstrdup(classname);
809                 }
810                 else
811                 {
812                         char       *nspname;
813
814                         /*
815                          * Would this class be found by regclassin?
816                          * If not, qualify it.
817                          */
818                         if (RelnameGetRelid(classname) == classid)
819                                 nspname = NULL;
820                         else
821                                 nspname = get_namespace_name(classform->relnamespace);
822
823                         result = quote_qualified_identifier(nspname, classname);
824                 }
825
826                 ReleaseSysCache(classtup);
827         }
828         else
829         {
830                 /* If OID doesn't match any pg_class entry, return it numerically */
831                 result = (char *) palloc(NAMEDATALEN);
832                 snprintf(result, NAMEDATALEN, "%u", classid);
833         }
834
835         PG_RETURN_CSTRING(result);
836 }
837
838
839 /*
840  * regtypein            - converts "typename" to type OID
841  *
842  * We also accept a numeric OID, mostly for historical reasons.
843  *
844  * '-' signifies unknown (OID 0).  In all other cases, the input must
845  * match an existing pg_type entry.
846  *
847  * In bootstrap mode the name must just equal some existing name in pg_type.
848  * In normal mode the type name can be specified using the full type syntax
849  * recognized by the parser; for example, DOUBLE PRECISION and INTEGER[] will
850  * work and be translated to the correct type names.  (We ignore any typmod
851  * info generated by the parser, however.)
852  */
853 Datum
854 regtypein(PG_FUNCTION_ARGS)
855 {
856         char       *typ_name_or_oid = PG_GETARG_CSTRING(0);
857         Oid                     result = InvalidOid;
858         int32           typmod;
859
860         /* '-' ? */
861         if (strcmp(typ_name_or_oid, "-") == 0)
862                 PG_RETURN_OID(InvalidOid);
863
864         /* Numeric OID? */
865         if (typ_name_or_oid[0] >= '0' &&
866                 typ_name_or_oid[0] <= '9' &&
867                 strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
868         {
869                 Oid                     searchOid;
870
871                 searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
872                                                                           CStringGetDatum(typ_name_or_oid)));
873                 result = GetSysCacheOid(TYPEOID,
874                                                                 ObjectIdGetDatum(searchOid),
875                                                                 0, 0, 0);
876                 if (!OidIsValid(result))
877                         elog(ERROR, "No type with oid %s", typ_name_or_oid);
878                 PG_RETURN_OID(result);
879         }
880
881         /* Else it's a type name, possibly schema-qualified or decorated */
882
883         /*
884          * In bootstrap mode we assume the given name is not schema-qualified,
885          * and just search pg_type for a match.  This is needed for
886          * initializing other system catalogs (pg_namespace may not exist yet,
887          * and certainly there are no schemas other than pg_catalog).
888          */
889         if (IsBootstrapProcessingMode())
890         {
891                 Relation        hdesc;
892                 ScanKeyData skey[1];
893                 SysScanDesc     sysscan;
894                 HeapTuple       tuple;
895
896                 ScanKeyEntryInitialize(&skey[0], 0x0,
897                                                            (AttrNumber) Anum_pg_type_typname,
898                                                            (RegProcedure) F_NAMEEQ,
899                                                            CStringGetDatum(typ_name_or_oid));
900
901                 hdesc = heap_openr(TypeRelationName, AccessShareLock);
902                 sysscan = systable_beginscan(hdesc, TypeNameNspIndex, true,
903                                                                          SnapshotNow, 1, skey);
904
905                 if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
906                         result = tuple->t_data->t_oid;
907                 else
908                         elog(ERROR, "No type with name %s", typ_name_or_oid);
909
910                 /* We assume there can be only one match */
911
912                 systable_endscan(sysscan);
913                 heap_close(hdesc, AccessShareLock);
914
915                 PG_RETURN_OID(result);
916         }
917
918         /*
919          * Normal case: invoke the full parser to deal with special cases
920          * such as array syntax.
921          */
922         parseTypeString(typ_name_or_oid, &result, &typmod);
923
924         PG_RETURN_OID(result);
925 }
926
927 /*
928  * regtypeout           - converts type OID to "typ_name"
929  */
930 Datum
931 regtypeout(PG_FUNCTION_ARGS)
932 {
933         Oid                     typid = PG_GETARG_OID(0);
934         char       *result;
935         HeapTuple       typetup;
936
937         if (typid == InvalidOid)
938         {
939                 result = pstrdup("-");
940                 PG_RETURN_CSTRING(result);
941         }
942
943         typetup = SearchSysCache(TYPEOID,
944                                                          ObjectIdGetDatum(typid),
945                                                          0, 0, 0);
946
947         if (HeapTupleIsValid(typetup))
948         {
949                 Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup);
950                 char       *typname = NameStr(typeform->typname);
951
952                 /*
953                  * In bootstrap mode, skip the fancy namespace stuff and just
954                  * return the type name.  (This path is only needed for debugging
955                  * output anyway.)
956                  */
957                 if (IsBootstrapProcessingMode())
958                 {
959                         result = pstrdup(typname);
960                 }
961                 else
962                 {
963                         char       *nspname;
964
965                         /*
966                          * Would this type be found by regtypein?
967                          * If not, qualify it.
968                          *
969                          * XXX shouldn't we use format_type instead?
970                          */
971                         if (TypenameGetTypid(typname) == typid)
972                                 nspname = NULL;
973                         else
974                                 nspname = get_namespace_name(typeform->typnamespace);
975
976                         result = quote_qualified_identifier(nspname, typname);
977                 }
978
979                 ReleaseSysCache(typetup);
980         }
981         else
982         {
983                 /* If OID doesn't match any pg_type entry, return it numerically */
984                 result = (char *) palloc(NAMEDATALEN);
985                 snprintf(result, NAMEDATALEN, "%u", typid);
986         }
987
988         PG_RETURN_CSTRING(result);
989 }
990
991
992 /*****************************************************************************
993  *       SUPPORT ROUTINES                                                                                                                *
994  *****************************************************************************/
995
996 /*
997  * Given a C string, parse it into a qualified-name list.
998  */
999 static List *
1000 stringToQualifiedNameList(const char *string, const char *caller)
1001 {
1002         char       *rawname;
1003         List       *result = NIL;
1004         List       *namelist;
1005         List       *l;
1006
1007         /* We need a modifiable copy of the input string. */
1008         rawname = pstrdup(string);
1009
1010         if (!SplitIdentifierString(rawname, '.', &namelist))
1011                 elog(ERROR, "%s: invalid name syntax", caller);
1012
1013         if (namelist == NIL)
1014                 elog(ERROR, "%s: invalid name syntax", caller);
1015
1016         foreach(l, namelist)
1017         {
1018                 char   *curname = (char *) lfirst(l);
1019
1020                 result = lappend(result, makeString(pstrdup(curname)));
1021         }
1022
1023         pfree(rawname);
1024         freeList(namelist);
1025
1026         return result;
1027 }
1028
1029 /*
1030  * Given a C string, parse it into a qualified function or operator name
1031  * followed by a parenthesized list of type names.  Reduce the
1032  * type names to an array of OIDs (returned into *nargs and *argtypes;
1033  * the argtypes array should be of size FUNC_MAX_ARGS).  The function or
1034  * operator name is returned to *names as a List of Strings.
1035  *
1036  * NONE is accepted as a placeholder for OID 0 if allow_none is true.
1037  */
1038 static void
1039 parseNameAndArgTypes(const char *string, const char *caller, bool allow_none,
1040                                          List **names, int *nargs, Oid *argtypes)
1041 {
1042         char       *rawname;
1043         char       *ptr;
1044         char       *ptr2;
1045         char       *typename;
1046         bool            in_quote;
1047         bool            had_comma;
1048         int                     paren_count;
1049         Oid                     typeid;
1050         int32           typmod;
1051
1052         /* We need a modifiable copy of the input string. */
1053         rawname = pstrdup(string);
1054
1055         /* Scan to find the expected left paren; mustn't be quoted */
1056         in_quote = false;
1057         for (ptr = rawname; *ptr; ptr++)
1058         {
1059                 if (*ptr == '"')
1060                         in_quote = !in_quote;
1061                 else if (*ptr == '(' && !in_quote)
1062                         break;
1063         }
1064         if (*ptr == '\0')
1065                 elog(ERROR, "%s: expected a left parenthesis", caller);
1066
1067         /* Separate the name and parse it into a list */
1068         *ptr++ = '\0';
1069         *names = stringToQualifiedNameList(rawname, caller);
1070
1071         /* Check for the trailing right parenthesis and remove it */
1072         ptr2 = ptr + strlen(ptr);
1073         while (--ptr2 > ptr)
1074         {
1075                 if (!isspace((unsigned char) *ptr2))
1076                         break;
1077         }
1078         if (*ptr2 != ')')
1079                 elog(ERROR, "%s: expected a right parenthesis", caller);
1080         *ptr2 = '\0';
1081
1082         /* Separate the remaining string into comma-separated type names */
1083         *nargs = 0;
1084         had_comma = false;
1085
1086         for (;;)
1087         {
1088                 /* allow leading whitespace */
1089                 while (isspace((unsigned char) *ptr))
1090                         ptr++;
1091                 if (*ptr == '\0')
1092                 {
1093                         /* End of string.  Okay unless we had a comma before. */
1094                         if (had_comma)
1095                                 elog(ERROR, "%s: expected a type name", caller);
1096                         break;
1097                 }
1098                 typename = ptr;
1099                 /* Find end of type name --- end of string or comma */
1100                 /* ... but not a quoted or parenthesized comma */
1101                 in_quote = false;
1102                 paren_count = 0;
1103                 for (; *ptr; ptr++)
1104                 {
1105                         if (*ptr == '"')
1106                                 in_quote = !in_quote;
1107                         else if (*ptr == ',' && !in_quote && paren_count == 0)
1108                                 break;
1109                         else if (!in_quote)
1110                         {
1111                                 switch (*ptr)
1112                                 {
1113                                         case '(':
1114                                         case '[':
1115                                                 paren_count++;
1116                                                 break;
1117                                         case ')':
1118                                         case ']':
1119                                                 paren_count--;
1120                                                 break;
1121                                 }
1122                         }
1123                 }
1124                 if (in_quote || paren_count != 0)
1125                         elog(ERROR, "%s: improper type name", caller);
1126                 ptr2 = ptr;
1127                 if (*ptr == ',')
1128                 {
1129                         had_comma = true;
1130                         *ptr++ = '\0';
1131                 }
1132                 else
1133                 {
1134                         had_comma = false;
1135                         Assert(*ptr == '\0');
1136                 }
1137                 /* Lop off trailing whitespace */
1138                 while (--ptr2 >= typename)
1139                 {
1140                         if (!isspace((unsigned char) *ptr2))
1141                                 break;
1142                         *ptr2 = '\0';
1143                 }
1144
1145                 if (allow_none && strcasecmp(typename, "none") == 0)
1146                 {
1147                         /* Report NONE as OID 0 */
1148                         typeid = InvalidOid;
1149                         typmod = -1;
1150                 }
1151                 else
1152                 {
1153                         /* Use full parser to resolve the type name */
1154                         parseTypeString(typename, &typeid, &typmod);
1155                 }
1156                 if (*nargs >= FUNC_MAX_ARGS)
1157                         elog(ERROR, "%s: too many argument datatypes", caller);
1158                 argtypes[*nargs] = typeid;
1159                 (*nargs)++;
1160         }
1161
1162         pfree(rawname);
1163 }