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