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