Coverage Report

Created: 2025-09-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/adt/regproc.c
Line
Count
Source
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-2025, PostgreSQL Global Development Group
12
 * Portions Copyright (c) 1994, Regents of the University of California
13
 *
14
 *
15
 * IDENTIFICATION
16
 *    src/backend/utils/adt/regproc.c
17
 *
18
 *-------------------------------------------------------------------------
19
 */
20
#include "postgres.h"
21
22
#include <ctype.h>
23
24
#include "access/htup_details.h"
25
#include "catalog/namespace.h"
26
#include "catalog/pg_class.h"
27
#include "catalog/pg_collation.h"
28
#include "catalog/pg_database.h"
29
#include "catalog/pg_operator.h"
30
#include "catalog/pg_proc.h"
31
#include "catalog/pg_ts_config.h"
32
#include "catalog/pg_ts_dict.h"
33
#include "catalog/pg_type.h"
34
#include "lib/stringinfo.h"
35
#include "mb/pg_wchar.h"
36
#include "miscadmin.h"
37
#include "nodes/miscnodes.h"
38
#include "parser/parse_type.h"
39
#include "parser/scansup.h"
40
#include "utils/acl.h"
41
#include "utils/builtins.h"
42
#include "utils/lsyscache.h"
43
#include "utils/regproc.h"
44
#include "utils/syscache.h"
45
#include "utils/varlena.h"
46
47
static bool parseNumericOid(char *string, Oid *result, Node *escontext);
48
static bool parseDashOrOid(char *string, Oid *result, Node *escontext);
49
static bool parseNameAndArgTypes(const char *string, bool allowNone,
50
                 List **names, int *nargs, Oid *argtypes,
51
                 Node *escontext);
52
53
54
/*****************************************************************************
55
 *   USER I/O ROUTINES                             *
56
 *****************************************************************************/
57
58
/*
59
 * regprocin    - converts "proname" to proc OID
60
 *
61
 * We also accept a numeric OID, for symmetry with the output routine.
62
 *
63
 * '-' signifies unknown (OID 0).  In all other cases, the input must
64
 * match an existing pg_proc entry.
65
 */
66
Datum
67
regprocin(PG_FUNCTION_ARGS)
68
0
{
69
0
  char     *pro_name_or_oid = PG_GETARG_CSTRING(0);
70
0
  Node     *escontext = fcinfo->context;
71
0
  RegProcedure result;
72
0
  List     *names;
73
0
  FuncCandidateList clist;
74
0
  int     fgc_flags;
75
76
  /* Handle "-" or numeric OID */
77
0
  if (parseDashOrOid(pro_name_or_oid, &result, escontext))
78
0
    PG_RETURN_OID(result);
79
80
  /* Else it's a name, possibly schema-qualified */
81
82
  /*
83
   * We should never get here in bootstrap mode, as all references should
84
   * have been resolved by genbki.pl.
85
   */
86
0
  if (IsBootstrapProcessingMode())
87
0
    elog(ERROR, "regproc values must be OIDs in bootstrap mode");
88
89
  /*
90
   * Normal case: parse the name into components and see if it matches any
91
   * pg_proc entries in the current search path.
92
   */
93
0
  names = stringToQualifiedNameList(pro_name_or_oid, escontext);
94
0
  if (names == NIL)
95
0
    PG_RETURN_NULL();
96
97
0
  clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true,
98
0
                  &fgc_flags);
99
100
0
  if (clist == NULL)
101
0
    ereturn(escontext, (Datum) 0,
102
0
        (errcode(ERRCODE_UNDEFINED_FUNCTION),
103
0
         errmsg("function \"%s\" does not exist", pro_name_or_oid)));
104
0
  else if (clist->next != NULL)
105
0
    ereturn(escontext, (Datum) 0,
106
0
        (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
107
0
         errmsg("more than one function named \"%s\"",
108
0
            pro_name_or_oid)));
109
110
0
  result = clist->oid;
111
112
0
  PG_RETURN_OID(result);
113
0
}
114
115
/*
116
 * to_regproc - converts "proname" to proc OID
117
 *
118
 * If the name is not found, we return NULL.
119
 */
120
Datum
121
to_regproc(PG_FUNCTION_ARGS)
122
0
{
123
0
  char     *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
124
0
  Datum   result;
125
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
126
127
0
  if (!DirectInputFunctionCallSafe(regprocin, pro_name,
128
0
                   InvalidOid, -1,
129
0
                   (Node *) &escontext,
130
0
                   &result))
131
0
    PG_RETURN_NULL();
132
0
  PG_RETURN_DATUM(result);
133
0
}
134
135
/*
136
 * regprocout   - converts proc OID to "pro_name"
137
 */
138
Datum
139
regprocout(PG_FUNCTION_ARGS)
140
0
{
141
0
  RegProcedure proid = PG_GETARG_OID(0);
142
0
  char     *result;
143
0
  HeapTuple proctup;
144
145
0
  if (proid == InvalidOid)
146
0
  {
147
0
    result = pstrdup("-");
148
0
    PG_RETURN_CSTRING(result);
149
0
  }
150
151
0
  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
152
153
0
  if (HeapTupleIsValid(proctup))
154
0
  {
155
0
    Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
156
0
    char     *proname = NameStr(procform->proname);
157
158
    /*
159
     * In bootstrap mode, skip the fancy namespace stuff and just return
160
     * the proc name.  (This path is only needed for debugging output
161
     * anyway.)
162
     */
163
0
    if (IsBootstrapProcessingMode())
164
0
      result = pstrdup(proname);
165
0
    else
166
0
    {
167
0
      char     *nspname;
168
0
      FuncCandidateList clist;
169
0
      int     fgc_flags;
170
171
      /*
172
       * Would this proc be found (uniquely!) by regprocin? If not,
173
       * qualify it.
174
       */
175
0
      clist = FuncnameGetCandidates(list_make1(makeString(proname)),
176
0
                      -1, NIL, false, false, false, false,
177
0
                      &fgc_flags);
178
0
      if (clist != NULL && clist->next == NULL &&
179
0
        clist->oid == proid)
180
0
        nspname = NULL;
181
0
      else
182
0
        nspname = get_namespace_name(procform->pronamespace);
183
184
0
      result = quote_qualified_identifier(nspname, proname);
185
0
    }
186
187
0
    ReleaseSysCache(proctup);
188
0
  }
189
0
  else
190
0
  {
191
    /* If OID doesn't match any pg_proc entry, return it numerically */
192
0
    result = (char *) palloc(NAMEDATALEN);
193
0
    snprintf(result, NAMEDATALEN, "%u", proid);
194
0
  }
195
196
0
  PG_RETURN_CSTRING(result);
197
0
}
198
199
/*
200
 *    regprocrecv     - converts external binary format to regproc
201
 */
202
Datum
203
regprocrecv(PG_FUNCTION_ARGS)
204
0
{
205
  /* Exactly the same as oidrecv, so share code */
206
0
  return oidrecv(fcinfo);
207
0
}
208
209
/*
210
 *    regprocsend     - converts regproc to binary format
211
 */
212
Datum
213
regprocsend(PG_FUNCTION_ARGS)
214
0
{
215
  /* Exactly the same as oidsend, so share code */
216
0
  return oidsend(fcinfo);
217
0
}
218
219
220
/*
221
 * regprocedurein   - converts "proname(args)" to proc OID
222
 *
223
 * We also accept a numeric OID, for symmetry with the output routine.
224
 *
225
 * '-' signifies unknown (OID 0).  In all other cases, the input must
226
 * match an existing pg_proc entry.
227
 */
228
Datum
229
regprocedurein(PG_FUNCTION_ARGS)
230
0
{
231
0
  char     *pro_name_or_oid = PG_GETARG_CSTRING(0);
232
0
  Node     *escontext = fcinfo->context;
233
0
  RegProcedure result;
234
0
  List     *names;
235
0
  int     nargs;
236
0
  Oid     argtypes[FUNC_MAX_ARGS];
237
0
  FuncCandidateList clist;
238
0
  int     fgc_flags;
239
240
  /* Handle "-" or numeric OID */
241
0
  if (parseDashOrOid(pro_name_or_oid, &result, escontext))
242
0
    PG_RETURN_OID(result);
243
244
  /* The rest of this wouldn't work in bootstrap mode */
245
0
  if (IsBootstrapProcessingMode())
246
0
    elog(ERROR, "regprocedure values must be OIDs in bootstrap mode");
247
248
  /*
249
   * Else it's a name and arguments.  Parse the name and arguments, look up
250
   * potential matches in the current namespace search list, and scan to see
251
   * which one exactly matches the given argument types.  (There will not be
252
   * more than one match.)
253
   */
254
0
  if (!parseNameAndArgTypes(pro_name_or_oid, false,
255
0
                &names, &nargs, argtypes,
256
0
                escontext))
257
0
    PG_RETURN_NULL();
258
259
0
  clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false, true,
260
0
                  &fgc_flags);
261
262
0
  for (; clist; clist = clist->next)
263
0
  {
264
0
    if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
265
0
      break;
266
0
  }
267
268
0
  if (clist == NULL)
269
0
    ereturn(escontext, (Datum) 0,
270
0
        (errcode(ERRCODE_UNDEFINED_FUNCTION),
271
0
         errmsg("function \"%s\" does not exist", pro_name_or_oid)));
272
273
0
  result = clist->oid;
274
275
0
  PG_RETURN_OID(result);
276
0
}
277
278
/*
279
 * to_regprocedure  - converts "proname(args)" to proc OID
280
 *
281
 * If the name is not found, we return NULL.
282
 */
283
Datum
284
to_regprocedure(PG_FUNCTION_ARGS)
285
0
{
286
0
  char     *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
287
0
  Datum   result;
288
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
289
290
0
  if (!DirectInputFunctionCallSafe(regprocedurein, pro_name,
291
0
                   InvalidOid, -1,
292
0
                   (Node *) &escontext,
293
0
                   &result))
294
0
    PG_RETURN_NULL();
295
0
  PG_RETURN_DATUM(result);
296
0
}
297
298
/*
299
 * format_procedure   - converts proc OID to "pro_name(args)"
300
 *
301
 * This exports the useful functionality of regprocedureout for use
302
 * in other backend modules.  The result is a palloc'd string.
303
 */
304
char *
305
format_procedure(Oid procedure_oid)
306
0
{
307
0
  return format_procedure_extended(procedure_oid, 0);
308
0
}
309
310
char *
311
format_procedure_qualified(Oid procedure_oid)
312
0
{
313
0
  return format_procedure_extended(procedure_oid, FORMAT_PROC_FORCE_QUALIFY);
314
0
}
315
316
/*
317
 * format_procedure_extended - converts procedure OID to "pro_name(args)"
318
 *
319
 * This exports the useful functionality of regprocedureout for use
320
 * in other backend modules.  The result is a palloc'd string, or NULL.
321
 *
322
 * Routine to produce regprocedure names; see format_procedure above.
323
 *
324
 * The following bits in 'flags' modify the behavior:
325
 * - FORMAT_PROC_INVALID_AS_NULL
326
 *      if the procedure OID is invalid or unknown, return NULL instead
327
 *      of the numeric OID.
328
 * - FORMAT_PROC_FORCE_QUALIFY
329
 *      always schema-qualify procedure names, regardless of search_path
330
 */
331
char *
332
format_procedure_extended(Oid procedure_oid, bits16 flags)
333
0
{
334
0
  char     *result;
335
0
  HeapTuple proctup;
336
337
0
  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
338
339
0
  if (HeapTupleIsValid(proctup))
340
0
  {
341
0
    Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
342
0
    char     *proname = NameStr(procform->proname);
343
0
    int     nargs = procform->pronargs;
344
0
    int     i;
345
0
    char     *nspname;
346
0
    StringInfoData buf;
347
348
    /* XXX no support here for bootstrap mode */
349
0
    Assert(!IsBootstrapProcessingMode());
350
351
0
    initStringInfo(&buf);
352
353
    /*
354
     * Would this proc be found (given the right args) by regprocedurein?
355
     * If not, or if caller requests it, we need to qualify it.
356
     */
357
0
    if ((flags & FORMAT_PROC_FORCE_QUALIFY) == 0 &&
358
0
      FunctionIsVisible(procedure_oid))
359
0
      nspname = NULL;
360
0
    else
361
0
      nspname = get_namespace_name(procform->pronamespace);
362
363
0
    appendStringInfo(&buf, "%s(",
364
0
             quote_qualified_identifier(nspname, proname));
365
0
    for (i = 0; i < nargs; i++)
366
0
    {
367
0
      Oid     thisargtype = procform->proargtypes.values[i];
368
369
0
      if (i > 0)
370
0
        appendStringInfoChar(&buf, ',');
371
0
      appendStringInfoString(&buf,
372
0
                   (flags & FORMAT_PROC_FORCE_QUALIFY) != 0 ?
373
0
                   format_type_be_qualified(thisargtype) :
374
0
                   format_type_be(thisargtype));
375
0
    }
376
0
    appendStringInfoChar(&buf, ')');
377
378
0
    result = buf.data;
379
380
0
    ReleaseSysCache(proctup);
381
0
  }
382
0
  else if ((flags & FORMAT_PROC_INVALID_AS_NULL) != 0)
383
0
  {
384
    /* If object is undefined, return NULL as wanted by caller */
385
0
    result = NULL;
386
0
  }
387
0
  else
388
0
  {
389
    /* If OID doesn't match any pg_proc entry, return it numerically */
390
0
    result = (char *) palloc(NAMEDATALEN);
391
0
    snprintf(result, NAMEDATALEN, "%u", procedure_oid);
392
0
  }
393
394
0
  return result;
395
0
}
396
397
/*
398
 * Output an objname/objargs representation for the procedure with the
399
 * given OID.  If it doesn't exist, an error is thrown.
400
 *
401
 * This can be used to feed get_object_address.
402
 */
403
void
404
format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs,
405
             bool missing_ok)
406
0
{
407
0
  HeapTuple proctup;
408
0
  Form_pg_proc procform;
409
0
  int     nargs;
410
0
  int     i;
411
412
0
  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
413
414
0
  if (!HeapTupleIsValid(proctup))
415
0
  {
416
0
    if (!missing_ok)
417
0
      elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
418
0
    return;
419
0
  }
420
421
0
  procform = (Form_pg_proc) GETSTRUCT(proctup);
422
0
  nargs = procform->pronargs;
423
424
0
  *objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
425
0
               pstrdup(NameStr(procform->proname)));
426
0
  *objargs = NIL;
427
0
  for (i = 0; i < nargs; i++)
428
0
  {
429
0
    Oid     thisargtype = procform->proargtypes.values[i];
430
431
0
    *objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
432
0
  }
433
434
0
  ReleaseSysCache(proctup);
435
0
}
436
437
/*
438
 * regprocedureout    - converts proc OID to "pro_name(args)"
439
 */
440
Datum
441
regprocedureout(PG_FUNCTION_ARGS)
442
0
{
443
0
  RegProcedure proid = PG_GETARG_OID(0);
444
0
  char     *result;
445
446
0
  if (proid == InvalidOid)
447
0
    result = pstrdup("-");
448
0
  else
449
0
    result = format_procedure(proid);
450
451
0
  PG_RETURN_CSTRING(result);
452
0
}
453
454
/*
455
 *    regprocedurerecv      - converts external binary format to regprocedure
456
 */
457
Datum
458
regprocedurerecv(PG_FUNCTION_ARGS)
459
0
{
460
  /* Exactly the same as oidrecv, so share code */
461
0
  return oidrecv(fcinfo);
462
0
}
463
464
/*
465
 *    regproceduresend      - converts regprocedure to binary format
466
 */
467
Datum
468
regproceduresend(PG_FUNCTION_ARGS)
469
0
{
470
  /* Exactly the same as oidsend, so share code */
471
0
  return oidsend(fcinfo);
472
0
}
473
474
475
/*
476
 * regoperin    - converts "oprname" to operator OID
477
 *
478
 * We also accept a numeric OID, for symmetry with the output routine.
479
 *
480
 * '0' signifies unknown (OID 0).  In all other cases, the input must
481
 * match an existing pg_operator entry.
482
 */
483
Datum
484
regoperin(PG_FUNCTION_ARGS)
485
0
{
486
0
  char     *opr_name_or_oid = PG_GETARG_CSTRING(0);
487
0
  Node     *escontext = fcinfo->context;
488
0
  Oid     result;
489
0
  List     *names;
490
0
  FuncCandidateList clist;
491
0
  int     fgc_flags;
492
493
  /* Handle "0" or numeric OID */
494
0
  if (parseNumericOid(opr_name_or_oid, &result, escontext))
495
0
    PG_RETURN_OID(result);
496
497
  /* Else it's a name, possibly schema-qualified */
498
499
  /* The rest of this wouldn't work in bootstrap mode */
500
0
  if (IsBootstrapProcessingMode())
501
0
    elog(ERROR, "regoper values must be OIDs in bootstrap mode");
502
503
  /*
504
   * Normal case: parse the name into components and see if it matches any
505
   * pg_operator entries in the current search path.
506
   */
507
0
  names = stringToQualifiedNameList(opr_name_or_oid, escontext);
508
0
  if (names == NIL)
509
0
    PG_RETURN_NULL();
510
511
0
  clist = OpernameGetCandidates(names, '\0', true, &fgc_flags);
512
513
0
  if (clist == NULL)
514
0
    ereturn(escontext, (Datum) 0,
515
0
        (errcode(ERRCODE_UNDEFINED_FUNCTION),
516
0
         errmsg("operator does not exist: %s", opr_name_or_oid)));
517
0
  else if (clist->next != NULL)
518
0
    ereturn(escontext, (Datum) 0,
519
0
        (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
520
0
         errmsg("more than one operator named %s",
521
0
            opr_name_or_oid)));
522
523
0
  result = clist->oid;
524
525
0
  PG_RETURN_OID(result);
526
0
}
527
528
/*
529
 * to_regoper   - converts "oprname" to operator OID
530
 *
531
 * If the name is not found, we return NULL.
532
 */
533
Datum
534
to_regoper(PG_FUNCTION_ARGS)
535
0
{
536
0
  char     *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
537
0
  Datum   result;
538
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
539
540
0
  if (!DirectInputFunctionCallSafe(regoperin, opr_name,
541
0
                   InvalidOid, -1,
542
0
                   (Node *) &escontext,
543
0
                   &result))
544
0
    PG_RETURN_NULL();
545
0
  PG_RETURN_DATUM(result);
546
0
}
547
548
/*
549
 * regoperout   - converts operator OID to "opr_name"
550
 */
551
Datum
552
regoperout(PG_FUNCTION_ARGS)
553
0
{
554
0
  Oid     oprid = PG_GETARG_OID(0);
555
0
  char     *result;
556
0
  HeapTuple opertup;
557
558
0
  if (oprid == InvalidOid)
559
0
  {
560
0
    result = pstrdup("0");
561
0
    PG_RETURN_CSTRING(result);
562
0
  }
563
564
0
  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
565
566
0
  if (HeapTupleIsValid(opertup))
567
0
  {
568
0
    Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
569
0
    char     *oprname = NameStr(operform->oprname);
570
571
    /*
572
     * In bootstrap mode, skip the fancy namespace stuff and just return
573
     * the oper name.  (This path is only needed for debugging output
574
     * anyway.)
575
     */
576
0
    if (IsBootstrapProcessingMode())
577
0
      result = pstrdup(oprname);
578
0
    else
579
0
    {
580
0
      FuncCandidateList clist;
581
0
      int     fgc_flags;
582
583
      /*
584
       * Would this oper be found (uniquely!) by regoperin? If not,
585
       * qualify it.
586
       */
587
0
      clist = OpernameGetCandidates(list_make1(makeString(oprname)),
588
0
                      '\0', false, &fgc_flags);
589
0
      if (clist != NULL && clist->next == NULL &&
590
0
        clist->oid == oprid)
591
0
        result = pstrdup(oprname);
592
0
      else
593
0
      {
594
0
        const char *nspname;
595
596
0
        nspname = get_namespace_name(operform->oprnamespace);
597
0
        nspname = quote_identifier(nspname);
598
0
        result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2);
599
0
        sprintf(result, "%s.%s", nspname, oprname);
600
0
      }
601
0
    }
602
603
0
    ReleaseSysCache(opertup);
604
0
  }
605
0
  else
606
0
  {
607
    /*
608
     * If OID doesn't match any pg_operator entry, return it numerically
609
     */
610
0
    result = (char *) palloc(NAMEDATALEN);
611
0
    snprintf(result, NAMEDATALEN, "%u", oprid);
612
0
  }
613
614
0
  PG_RETURN_CSTRING(result);
615
0
}
616
617
/*
618
 *    regoperrecv     - converts external binary format to regoper
619
 */
620
Datum
621
regoperrecv(PG_FUNCTION_ARGS)
622
0
{
623
  /* Exactly the same as oidrecv, so share code */
624
0
  return oidrecv(fcinfo);
625
0
}
626
627
/*
628
 *    regopersend     - converts regoper to binary format
629
 */
630
Datum
631
regopersend(PG_FUNCTION_ARGS)
632
0
{
633
  /* Exactly the same as oidsend, so share code */
634
0
  return oidsend(fcinfo);
635
0
}
636
637
638
/*
639
 * regoperatorin    - converts "oprname(args)" to operator OID
640
 *
641
 * We also accept a numeric OID, for symmetry with the output routine.
642
 *
643
 * '0' signifies unknown (OID 0).  In all other cases, the input must
644
 * match an existing pg_operator entry.
645
 */
646
Datum
647
regoperatorin(PG_FUNCTION_ARGS)
648
0
{
649
0
  char     *opr_name_or_oid = PG_GETARG_CSTRING(0);
650
0
  Node     *escontext = fcinfo->context;
651
0
  Oid     result;
652
0
  List     *names;
653
0
  int     nargs;
654
0
  Oid     argtypes[FUNC_MAX_ARGS];
655
656
  /* Handle "0" or numeric OID */
657
0
  if (parseNumericOid(opr_name_or_oid, &result, escontext))
658
0
    PG_RETURN_OID(result);
659
660
  /* The rest of this wouldn't work in bootstrap mode */
661
0
  if (IsBootstrapProcessingMode())
662
0
    elog(ERROR, "regoperator values must be OIDs in bootstrap mode");
663
664
  /*
665
   * Else it's a name and arguments.  Parse the name and arguments, look up
666
   * potential matches in the current namespace search list, and scan to see
667
   * which one exactly matches the given argument types.  (There will not be
668
   * more than one match.)
669
   */
670
0
  if (!parseNameAndArgTypes(opr_name_or_oid, true,
671
0
                &names, &nargs, argtypes,
672
0
                escontext))
673
0
    PG_RETURN_NULL();
674
675
0
  if (nargs == 1)
676
0
    ereturn(escontext, (Datum) 0,
677
0
        (errcode(ERRCODE_UNDEFINED_PARAMETER),
678
0
         errmsg("missing argument"),
679
0
         errhint("Use NONE to denote the missing argument of a unary operator.")));
680
0
  if (nargs != 2)
681
0
    ereturn(escontext, (Datum) 0,
682
0
        (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
683
0
         errmsg("too many arguments"),
684
0
         errhint("Provide two argument types for operator.")));
685
686
0
  result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
687
688
0
  if (!OidIsValid(result))
689
0
    ereturn(escontext, (Datum) 0,
690
0
        (errcode(ERRCODE_UNDEFINED_FUNCTION),
691
0
         errmsg("operator does not exist: %s", opr_name_or_oid)));
692
693
0
  PG_RETURN_OID(result);
694
0
}
695
696
/*
697
 * to_regoperator - converts "oprname(args)" to operator OID
698
 *
699
 * If the name is not found, we return NULL.
700
 */
701
Datum
702
to_regoperator(PG_FUNCTION_ARGS)
703
0
{
704
0
  char     *opr_name_or_oid = text_to_cstring(PG_GETARG_TEXT_PP(0));
705
0
  Datum   result;
706
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
707
708
0
  if (!DirectInputFunctionCallSafe(regoperatorin, opr_name_or_oid,
709
0
                   InvalidOid, -1,
710
0
                   (Node *) &escontext,
711
0
                   &result))
712
0
    PG_RETURN_NULL();
713
0
  PG_RETURN_DATUM(result);
714
0
}
715
716
/*
717
 * format_operator_extended - converts operator OID to "opr_name(args)"
718
 *
719
 * This exports the useful functionality of regoperatorout for use
720
 * in other backend modules.  The result is a palloc'd string, or NULL.
721
 *
722
 * The following bits in 'flags' modify the behavior:
723
 * - FORMAT_OPERATOR_INVALID_AS_NULL
724
 *      if the operator OID is invalid or unknown, return NULL instead
725
 *      of the numeric OID.
726
 * - FORMAT_OPERATOR_FORCE_QUALIFY
727
 *      always schema-qualify operator names, regardless of search_path
728
 */
729
char *
730
format_operator_extended(Oid operator_oid, bits16 flags)
731
0
{
732
0
  char     *result;
733
0
  HeapTuple opertup;
734
735
0
  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
736
737
0
  if (HeapTupleIsValid(opertup))
738
0
  {
739
0
    Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
740
0
    char     *oprname = NameStr(operform->oprname);
741
0
    char     *nspname;
742
0
    StringInfoData buf;
743
744
    /* XXX no support here for bootstrap mode */
745
0
    Assert(!IsBootstrapProcessingMode());
746
747
0
    initStringInfo(&buf);
748
749
    /*
750
     * Would this oper be found (given the right args) by regoperatorin?
751
     * If not, or if caller explicitly requests it, we need to qualify it.
752
     */
753
0
    if ((flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ||
754
0
      !OperatorIsVisible(operator_oid))
755
0
    {
756
0
      nspname = get_namespace_name(operform->oprnamespace);
757
0
      appendStringInfo(&buf, "%s.",
758
0
               quote_identifier(nspname));
759
0
    }
760
761
0
    appendStringInfo(&buf, "%s(", oprname);
762
763
0
    if (operform->oprleft)
764
0
      appendStringInfo(&buf, "%s,",
765
0
               (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
766
0
               format_type_be_qualified(operform->oprleft) :
767
0
               format_type_be(operform->oprleft));
768
0
    else
769
0
      appendStringInfoString(&buf, "NONE,");
770
771
0
    if (operform->oprright)
772
0
      appendStringInfo(&buf, "%s)",
773
0
               (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
774
0
               format_type_be_qualified(operform->oprright) :
775
0
               format_type_be(operform->oprright));
776
0
    else
777
0
      appendStringInfoString(&buf, "NONE)");
778
779
0
    result = buf.data;
780
781
0
    ReleaseSysCache(opertup);
782
0
  }
783
0
  else if ((flags & FORMAT_OPERATOR_INVALID_AS_NULL) != 0)
784
0
  {
785
    /* If object is undefined, return NULL as wanted by caller */
786
0
    result = NULL;
787
0
  }
788
0
  else
789
0
  {
790
    /*
791
     * If OID doesn't match any pg_operator entry, return it numerically
792
     */
793
0
    result = (char *) palloc(NAMEDATALEN);
794
0
    snprintf(result, NAMEDATALEN, "%u", operator_oid);
795
0
  }
796
797
0
  return result;
798
0
}
799
800
char *
801
format_operator(Oid operator_oid)
802
0
{
803
0
  return format_operator_extended(operator_oid, 0);
804
0
}
805
806
char *
807
format_operator_qualified(Oid operator_oid)
808
0
{
809
0
  return format_operator_extended(operator_oid,
810
0
                  FORMAT_OPERATOR_FORCE_QUALIFY);
811
0
}
812
813
void
814
format_operator_parts(Oid operator_oid, List **objnames, List **objargs,
815
            bool missing_ok)
816
0
{
817
0
  HeapTuple opertup;
818
0
  Form_pg_operator oprForm;
819
820
0
  opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
821
0
  if (!HeapTupleIsValid(opertup))
822
0
  {
823
0
    if (!missing_ok)
824
0
      elog(ERROR, "cache lookup failed for operator with OID %u",
825
0
         operator_oid);
826
0
    return;
827
0
  }
828
829
0
  oprForm = (Form_pg_operator) GETSTRUCT(opertup);
830
0
  *objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
831
0
               pstrdup(NameStr(oprForm->oprname)));
832
0
  *objargs = NIL;
833
0
  if (oprForm->oprleft)
834
0
    *objargs = lappend(*objargs,
835
0
               format_type_be_qualified(oprForm->oprleft));
836
0
  if (oprForm->oprright)
837
0
    *objargs = lappend(*objargs,
838
0
               format_type_be_qualified(oprForm->oprright));
839
840
0
  ReleaseSysCache(opertup);
841
0
}
842
843
/*
844
 * regoperatorout   - converts operator OID to "opr_name(args)"
845
 */
846
Datum
847
regoperatorout(PG_FUNCTION_ARGS)
848
0
{
849
0
  Oid     oprid = PG_GETARG_OID(0);
850
0
  char     *result;
851
852
0
  if (oprid == InvalidOid)
853
0
    result = pstrdup("0");
854
0
  else
855
0
    result = format_operator(oprid);
856
857
0
  PG_RETURN_CSTRING(result);
858
0
}
859
860
/*
861
 *    regoperatorrecv     - converts external binary format to regoperator
862
 */
863
Datum
864
regoperatorrecv(PG_FUNCTION_ARGS)
865
0
{
866
  /* Exactly the same as oidrecv, so share code */
867
0
  return oidrecv(fcinfo);
868
0
}
869
870
/*
871
 *    regoperatorsend     - converts regoperator to binary format
872
 */
873
Datum
874
regoperatorsend(PG_FUNCTION_ARGS)
875
0
{
876
  /* Exactly the same as oidsend, so share code */
877
0
  return oidsend(fcinfo);
878
0
}
879
880
881
/*
882
 * regclassin   - converts "classname" to class OID
883
 *
884
 * We also accept a numeric OID, for symmetry with the output routine.
885
 *
886
 * '-' signifies unknown (OID 0).  In all other cases, the input must
887
 * match an existing pg_class entry.
888
 */
889
Datum
890
regclassin(PG_FUNCTION_ARGS)
891
0
{
892
0
  char     *class_name_or_oid = PG_GETARG_CSTRING(0);
893
0
  Node     *escontext = fcinfo->context;
894
0
  Oid     result;
895
0
  List     *names;
896
897
  /* Handle "-" or numeric OID */
898
0
  if (parseDashOrOid(class_name_or_oid, &result, escontext))
899
0
    PG_RETURN_OID(result);
900
901
  /* Else it's a name, possibly schema-qualified */
902
903
  /* The rest of this wouldn't work in bootstrap mode */
904
0
  if (IsBootstrapProcessingMode())
905
0
    elog(ERROR, "regclass values must be OIDs in bootstrap mode");
906
907
  /*
908
   * Normal case: parse the name into components and see if it matches any
909
   * pg_class entries in the current search path.
910
   */
911
0
  names = stringToQualifiedNameList(class_name_or_oid, escontext);
912
0
  if (names == NIL)
913
0
    PG_RETURN_NULL();
914
915
  /* We might not even have permissions on this relation; don't lock it. */
916
0
  result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
917
918
0
  if (!OidIsValid(result))
919
0
    ereturn(escontext, (Datum) 0,
920
0
        (errcode(ERRCODE_UNDEFINED_TABLE),
921
0
         errmsg("relation \"%s\" does not exist",
922
0
            NameListToString(names))));
923
924
0
  PG_RETURN_OID(result);
925
0
}
926
927
/*
928
 * to_regclass    - converts "classname" to class OID
929
 *
930
 * If the name is not found, we return NULL.
931
 */
932
Datum
933
to_regclass(PG_FUNCTION_ARGS)
934
0
{
935
0
  char     *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
936
0
  Datum   result;
937
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
938
939
0
  if (!DirectInputFunctionCallSafe(regclassin, class_name,
940
0
                   InvalidOid, -1,
941
0
                   (Node *) &escontext,
942
0
                   &result))
943
0
    PG_RETURN_NULL();
944
0
  PG_RETURN_DATUM(result);
945
0
}
946
947
/*
948
 * regclassout    - converts class OID to "class_name"
949
 */
950
Datum
951
regclassout(PG_FUNCTION_ARGS)
952
0
{
953
0
  Oid     classid = PG_GETARG_OID(0);
954
0
  char     *result;
955
0
  HeapTuple classtup;
956
957
0
  if (classid == InvalidOid)
958
0
  {
959
0
    result = pstrdup("-");
960
0
    PG_RETURN_CSTRING(result);
961
0
  }
962
963
0
  classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
964
965
0
  if (HeapTupleIsValid(classtup))
966
0
  {
967
0
    Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
968
0
    char     *classname = NameStr(classform->relname);
969
970
    /*
971
     * In bootstrap mode, skip the fancy namespace stuff and just return
972
     * the class name.  (This path is only needed for debugging output
973
     * anyway.)
974
     */
975
0
    if (IsBootstrapProcessingMode())
976
0
      result = pstrdup(classname);
977
0
    else
978
0
    {
979
0
      char     *nspname;
980
981
      /*
982
       * Would this class be found by regclassin? If not, qualify it.
983
       */
984
0
      if (RelationIsVisible(classid))
985
0
        nspname = NULL;
986
0
      else
987
0
        nspname = get_namespace_name(classform->relnamespace);
988
989
0
      result = quote_qualified_identifier(nspname, classname);
990
0
    }
991
992
0
    ReleaseSysCache(classtup);
993
0
  }
994
0
  else
995
0
  {
996
    /* If OID doesn't match any pg_class entry, return it numerically */
997
0
    result = (char *) palloc(NAMEDATALEN);
998
0
    snprintf(result, NAMEDATALEN, "%u", classid);
999
0
  }
1000
1001
0
  PG_RETURN_CSTRING(result);
1002
0
}
1003
1004
/*
1005
 *    regclassrecv      - converts external binary format to regclass
1006
 */
1007
Datum
1008
regclassrecv(PG_FUNCTION_ARGS)
1009
0
{
1010
  /* Exactly the same as oidrecv, so share code */
1011
0
  return oidrecv(fcinfo);
1012
0
}
1013
1014
/*
1015
 *    regclasssend      - converts regclass to binary format
1016
 */
1017
Datum
1018
regclasssend(PG_FUNCTION_ARGS)
1019
0
{
1020
  /* Exactly the same as oidsend, so share code */
1021
0
  return oidsend(fcinfo);
1022
0
}
1023
1024
1025
/*
1026
 * regcollationin   - converts "collationname" to collation OID
1027
 *
1028
 * We also accept a numeric OID, for symmetry with the output routine.
1029
 *
1030
 * '-' signifies unknown (OID 0).  In all other cases, the input must
1031
 * match an existing pg_collation entry.
1032
 */
1033
Datum
1034
regcollationin(PG_FUNCTION_ARGS)
1035
0
{
1036
0
  char     *collation_name_or_oid = PG_GETARG_CSTRING(0);
1037
0
  Node     *escontext = fcinfo->context;
1038
0
  Oid     result;
1039
0
  List     *names;
1040
1041
  /* Handle "-" or numeric OID */
1042
0
  if (parseDashOrOid(collation_name_or_oid, &result, escontext))
1043
0
    PG_RETURN_OID(result);
1044
1045
  /* Else it's a name, possibly schema-qualified */
1046
1047
  /* The rest of this wouldn't work in bootstrap mode */
1048
0
  if (IsBootstrapProcessingMode())
1049
0
    elog(ERROR, "regcollation values must be OIDs in bootstrap mode");
1050
1051
  /*
1052
   * Normal case: parse the name into components and see if it matches any
1053
   * pg_collation entries in the current search path.
1054
   */
1055
0
  names = stringToQualifiedNameList(collation_name_or_oid, escontext);
1056
0
  if (names == NIL)
1057
0
    PG_RETURN_NULL();
1058
1059
0
  result = get_collation_oid(names, true);
1060
1061
0
  if (!OidIsValid(result))
1062
0
    ereturn(escontext, (Datum) 0,
1063
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
1064
0
         errmsg("collation \"%s\" for encoding \"%s\" does not exist",
1065
0
            NameListToString(names), GetDatabaseEncodingName())));
1066
1067
0
  PG_RETURN_OID(result);
1068
0
}
1069
1070
/*
1071
 * to_regcollation    - converts "collationname" to collation OID
1072
 *
1073
 * If the name is not found, we return NULL.
1074
 */
1075
Datum
1076
to_regcollation(PG_FUNCTION_ARGS)
1077
0
{
1078
0
  char     *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1079
0
  Datum   result;
1080
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
1081
1082
0
  if (!DirectInputFunctionCallSafe(regcollationin, collation_name,
1083
0
                   InvalidOid, -1,
1084
0
                   (Node *) &escontext,
1085
0
                   &result))
1086
0
    PG_RETURN_NULL();
1087
0
  PG_RETURN_DATUM(result);
1088
0
}
1089
1090
/*
1091
 * regcollationout    - converts collation OID to "collation_name"
1092
 */
1093
Datum
1094
regcollationout(PG_FUNCTION_ARGS)
1095
0
{
1096
0
  Oid     collationid = PG_GETARG_OID(0);
1097
0
  char     *result;
1098
0
  HeapTuple collationtup;
1099
1100
0
  if (collationid == InvalidOid)
1101
0
  {
1102
0
    result = pstrdup("-");
1103
0
    PG_RETURN_CSTRING(result);
1104
0
  }
1105
1106
0
  collationtup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationid));
1107
1108
0
  if (HeapTupleIsValid(collationtup))
1109
0
  {
1110
0
    Form_pg_collation collationform = (Form_pg_collation) GETSTRUCT(collationtup);
1111
0
    char     *collationname = NameStr(collationform->collname);
1112
1113
    /*
1114
     * In bootstrap mode, skip the fancy namespace stuff and just return
1115
     * the collation name.  (This path is only needed for debugging output
1116
     * anyway.)
1117
     */
1118
0
    if (IsBootstrapProcessingMode())
1119
0
      result = pstrdup(collationname);
1120
0
    else
1121
0
    {
1122
0
      char     *nspname;
1123
1124
      /*
1125
       * Would this collation be found by regcollationin? If not,
1126
       * qualify it.
1127
       */
1128
0
      if (CollationIsVisible(collationid))
1129
0
        nspname = NULL;
1130
0
      else
1131
0
        nspname = get_namespace_name(collationform->collnamespace);
1132
1133
0
      result = quote_qualified_identifier(nspname, collationname);
1134
0
    }
1135
1136
0
    ReleaseSysCache(collationtup);
1137
0
  }
1138
0
  else
1139
0
  {
1140
    /* If OID doesn't match any pg_collation entry, return it numerically */
1141
0
    result = (char *) palloc(NAMEDATALEN);
1142
0
    snprintf(result, NAMEDATALEN, "%u", collationid);
1143
0
  }
1144
1145
0
  PG_RETURN_CSTRING(result);
1146
0
}
1147
1148
/*
1149
 *    regcollationrecv      - converts external binary format to regcollation
1150
 */
1151
Datum
1152
regcollationrecv(PG_FUNCTION_ARGS)
1153
0
{
1154
  /* Exactly the same as oidrecv, so share code */
1155
0
  return oidrecv(fcinfo);
1156
0
}
1157
1158
/*
1159
 *    regcollationsend      - converts regcollation to binary format
1160
 */
1161
Datum
1162
regcollationsend(PG_FUNCTION_ARGS)
1163
0
{
1164
  /* Exactly the same as oidsend, so share code */
1165
0
  return oidsend(fcinfo);
1166
0
}
1167
1168
1169
/*
1170
 * regtypein    - converts "typename" to type OID
1171
 *
1172
 * The type name can be specified using the full type syntax recognized by
1173
 * the parser; for example, DOUBLE PRECISION and INTEGER[] will work and be
1174
 * translated to the correct type names.  (We ignore any typmod info
1175
 * generated by the parser, however.)
1176
 *
1177
 * We also accept a numeric OID, for symmetry with the output routine,
1178
 * and for possible use in bootstrap mode.
1179
 *
1180
 * '-' signifies unknown (OID 0).  In all other cases, the input must
1181
 * match an existing pg_type entry.
1182
 */
1183
Datum
1184
regtypein(PG_FUNCTION_ARGS)
1185
0
{
1186
0
  char     *typ_name_or_oid = PG_GETARG_CSTRING(0);
1187
0
  Node     *escontext = fcinfo->context;
1188
0
  Oid     result;
1189
0
  int32   typmod;
1190
1191
  /* Handle "-" or numeric OID */
1192
0
  if (parseDashOrOid(typ_name_or_oid, &result, escontext))
1193
0
    PG_RETURN_OID(result);
1194
1195
  /* Else it's a type name, possibly schema-qualified or decorated */
1196
1197
  /* The rest of this wouldn't work in bootstrap mode */
1198
0
  if (IsBootstrapProcessingMode())
1199
0
    elog(ERROR, "regtype values must be OIDs in bootstrap mode");
1200
1201
  /*
1202
   * Normal case: invoke the full parser to deal with special cases such as
1203
   * array syntax.  We don't need to check for parseTypeString failure,
1204
   * since we'll just return anyway.
1205
   */
1206
0
  (void) parseTypeString(typ_name_or_oid, &result, &typmod, escontext);
1207
1208
0
  PG_RETURN_OID(result);
1209
0
}
1210
1211
/*
1212
 * to_regtype   - converts "typename" to type OID
1213
 *
1214
 * If the name is not found, we return NULL.
1215
 */
1216
Datum
1217
to_regtype(PG_FUNCTION_ARGS)
1218
0
{
1219
0
  char     *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1220
0
  Datum   result;
1221
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
1222
1223
0
  if (!DirectInputFunctionCallSafe(regtypein, typ_name,
1224
0
                   InvalidOid, -1,
1225
0
                   (Node *) &escontext,
1226
0
                   &result))
1227
0
    PG_RETURN_NULL();
1228
0
  PG_RETURN_DATUM(result);
1229
0
}
1230
1231
/*
1232
 * to_regtypemod  - converts "typename" to type modifier
1233
 *
1234
 * If the name is not found, we return NULL.
1235
 */
1236
Datum
1237
to_regtypemod(PG_FUNCTION_ARGS)
1238
0
{
1239
0
  char     *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1240
0
  Oid     typid;
1241
0
  int32   typmod;
1242
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
1243
1244
  /* We rely on parseTypeString to parse the input. */
1245
0
  if (!parseTypeString(typ_name, &typid, &typmod, (Node *) &escontext))
1246
0
    PG_RETURN_NULL();
1247
1248
0
  PG_RETURN_INT32(typmod);
1249
0
}
1250
1251
/*
1252
 * regtypeout   - converts type OID to "typ_name"
1253
 */
1254
Datum
1255
regtypeout(PG_FUNCTION_ARGS)
1256
0
{
1257
0
  Oid     typid = PG_GETARG_OID(0);
1258
0
  char     *result;
1259
0
  HeapTuple typetup;
1260
1261
0
  if (typid == InvalidOid)
1262
0
  {
1263
0
    result = pstrdup("-");
1264
0
    PG_RETURN_CSTRING(result);
1265
0
  }
1266
1267
0
  typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1268
1269
0
  if (HeapTupleIsValid(typetup))
1270
0
  {
1271
0
    Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup);
1272
1273
    /*
1274
     * In bootstrap mode, skip the fancy namespace stuff and just return
1275
     * the type name.  (This path is only needed for debugging output
1276
     * anyway.)
1277
     */
1278
0
    if (IsBootstrapProcessingMode())
1279
0
    {
1280
0
      char     *typname = NameStr(typeform->typname);
1281
1282
0
      result = pstrdup(typname);
1283
0
    }
1284
0
    else
1285
0
      result = format_type_be(typid);
1286
1287
0
    ReleaseSysCache(typetup);
1288
0
  }
1289
0
  else
1290
0
  {
1291
    /* If OID doesn't match any pg_type entry, return it numerically */
1292
0
    result = (char *) palloc(NAMEDATALEN);
1293
0
    snprintf(result, NAMEDATALEN, "%u", typid);
1294
0
  }
1295
1296
0
  PG_RETURN_CSTRING(result);
1297
0
}
1298
1299
/*
1300
 *    regtyperecv     - converts external binary format to regtype
1301
 */
1302
Datum
1303
regtyperecv(PG_FUNCTION_ARGS)
1304
0
{
1305
  /* Exactly the same as oidrecv, so share code */
1306
0
  return oidrecv(fcinfo);
1307
0
}
1308
1309
/*
1310
 *    regtypesend     - converts regtype to binary format
1311
 */
1312
Datum
1313
regtypesend(PG_FUNCTION_ARGS)
1314
0
{
1315
  /* Exactly the same as oidsend, so share code */
1316
0
  return oidsend(fcinfo);
1317
0
}
1318
1319
1320
/*
1321
 * regconfigin    - converts "tsconfigname" to tsconfig OID
1322
 *
1323
 * We also accept a numeric OID, for symmetry with the output routine.
1324
 *
1325
 * '-' signifies unknown (OID 0).  In all other cases, the input must
1326
 * match an existing pg_ts_config entry.
1327
 */
1328
Datum
1329
regconfigin(PG_FUNCTION_ARGS)
1330
0
{
1331
0
  char     *cfg_name_or_oid = PG_GETARG_CSTRING(0);
1332
0
  Node     *escontext = fcinfo->context;
1333
0
  Oid     result;
1334
0
  List     *names;
1335
1336
  /* Handle "-" or numeric OID */
1337
0
  if (parseDashOrOid(cfg_name_or_oid, &result, escontext))
1338
0
    PG_RETURN_OID(result);
1339
1340
  /* The rest of this wouldn't work in bootstrap mode */
1341
0
  if (IsBootstrapProcessingMode())
1342
0
    elog(ERROR, "regconfig values must be OIDs in bootstrap mode");
1343
1344
  /*
1345
   * Normal case: parse the name into components and see if it matches any
1346
   * pg_ts_config entries in the current search path.
1347
   */
1348
0
  names = stringToQualifiedNameList(cfg_name_or_oid, escontext);
1349
0
  if (names == NIL)
1350
0
    PG_RETURN_NULL();
1351
1352
0
  result = get_ts_config_oid(names, true);
1353
1354
0
  if (!OidIsValid(result))
1355
0
    ereturn(escontext, (Datum) 0,
1356
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
1357
0
         errmsg("text search configuration \"%s\" does not exist",
1358
0
            NameListToString(names))));
1359
1360
0
  PG_RETURN_OID(result);
1361
0
}
1362
1363
/*
1364
 * regconfigout   - converts tsconfig OID to "tsconfigname"
1365
 */
1366
Datum
1367
regconfigout(PG_FUNCTION_ARGS)
1368
0
{
1369
0
  Oid     cfgid = PG_GETARG_OID(0);
1370
0
  char     *result;
1371
0
  HeapTuple cfgtup;
1372
1373
0
  if (cfgid == InvalidOid)
1374
0
  {
1375
0
    result = pstrdup("-");
1376
0
    PG_RETURN_CSTRING(result);
1377
0
  }
1378
1379
0
  cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
1380
1381
0
  if (HeapTupleIsValid(cfgtup))
1382
0
  {
1383
0
    Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
1384
0
    char     *cfgname = NameStr(cfgform->cfgname);
1385
0
    char     *nspname;
1386
1387
    /*
1388
     * Would this config be found by regconfigin? If not, qualify it.
1389
     */
1390
0
    if (TSConfigIsVisible(cfgid))
1391
0
      nspname = NULL;
1392
0
    else
1393
0
      nspname = get_namespace_name(cfgform->cfgnamespace);
1394
1395
0
    result = quote_qualified_identifier(nspname, cfgname);
1396
1397
0
    ReleaseSysCache(cfgtup);
1398
0
  }
1399
0
  else
1400
0
  {
1401
    /* If OID doesn't match any pg_ts_config row, return it numerically */
1402
0
    result = (char *) palloc(NAMEDATALEN);
1403
0
    snprintf(result, NAMEDATALEN, "%u", cfgid);
1404
0
  }
1405
1406
0
  PG_RETURN_CSTRING(result);
1407
0
}
1408
1409
/*
1410
 *    regconfigrecv     - converts external binary format to regconfig
1411
 */
1412
Datum
1413
regconfigrecv(PG_FUNCTION_ARGS)
1414
0
{
1415
  /* Exactly the same as oidrecv, so share code */
1416
0
  return oidrecv(fcinfo);
1417
0
}
1418
1419
/*
1420
 *    regconfigsend     - converts regconfig to binary format
1421
 */
1422
Datum
1423
regconfigsend(PG_FUNCTION_ARGS)
1424
0
{
1425
  /* Exactly the same as oidsend, so share code */
1426
0
  return oidsend(fcinfo);
1427
0
}
1428
1429
1430
/*
1431
 * regdictionaryin    - converts "tsdictionaryname" to tsdictionary OID
1432
 *
1433
 * We also accept a numeric OID, for symmetry with the output routine.
1434
 *
1435
 * '-' signifies unknown (OID 0).  In all other cases, the input must
1436
 * match an existing pg_ts_dict entry.
1437
 */
1438
Datum
1439
regdictionaryin(PG_FUNCTION_ARGS)
1440
0
{
1441
0
  char     *dict_name_or_oid = PG_GETARG_CSTRING(0);
1442
0
  Node     *escontext = fcinfo->context;
1443
0
  Oid     result;
1444
0
  List     *names;
1445
1446
  /* Handle "-" or numeric OID */
1447
0
  if (parseDashOrOid(dict_name_or_oid, &result, escontext))
1448
0
    PG_RETURN_OID(result);
1449
1450
  /* The rest of this wouldn't work in bootstrap mode */
1451
0
  if (IsBootstrapProcessingMode())
1452
0
    elog(ERROR, "regdictionary values must be OIDs in bootstrap mode");
1453
1454
  /*
1455
   * Normal case: parse the name into components and see if it matches any
1456
   * pg_ts_dict entries in the current search path.
1457
   */
1458
0
  names = stringToQualifiedNameList(dict_name_or_oid, escontext);
1459
0
  if (names == NIL)
1460
0
    PG_RETURN_NULL();
1461
1462
0
  result = get_ts_dict_oid(names, true);
1463
1464
0
  if (!OidIsValid(result))
1465
0
    ereturn(escontext, (Datum) 0,
1466
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
1467
0
         errmsg("text search dictionary \"%s\" does not exist",
1468
0
            NameListToString(names))));
1469
1470
0
  PG_RETURN_OID(result);
1471
0
}
1472
1473
/*
1474
 * regdictionaryout   - converts tsdictionary OID to "tsdictionaryname"
1475
 */
1476
Datum
1477
regdictionaryout(PG_FUNCTION_ARGS)
1478
0
{
1479
0
  Oid     dictid = PG_GETARG_OID(0);
1480
0
  char     *result;
1481
0
  HeapTuple dicttup;
1482
1483
0
  if (dictid == InvalidOid)
1484
0
  {
1485
0
    result = pstrdup("-");
1486
0
    PG_RETURN_CSTRING(result);
1487
0
  }
1488
1489
0
  dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
1490
1491
0
  if (HeapTupleIsValid(dicttup))
1492
0
  {
1493
0
    Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
1494
0
    char     *dictname = NameStr(dictform->dictname);
1495
0
    char     *nspname;
1496
1497
    /*
1498
     * Would this dictionary be found by regdictionaryin? If not, qualify
1499
     * it.
1500
     */
1501
0
    if (TSDictionaryIsVisible(dictid))
1502
0
      nspname = NULL;
1503
0
    else
1504
0
      nspname = get_namespace_name(dictform->dictnamespace);
1505
1506
0
    result = quote_qualified_identifier(nspname, dictname);
1507
1508
0
    ReleaseSysCache(dicttup);
1509
0
  }
1510
0
  else
1511
0
  {
1512
    /* If OID doesn't match any pg_ts_dict row, return it numerically */
1513
0
    result = (char *) palloc(NAMEDATALEN);
1514
0
    snprintf(result, NAMEDATALEN, "%u", dictid);
1515
0
  }
1516
1517
0
  PG_RETURN_CSTRING(result);
1518
0
}
1519
1520
/*
1521
 *    regdictionaryrecv - converts external binary format to regdictionary
1522
 */
1523
Datum
1524
regdictionaryrecv(PG_FUNCTION_ARGS)
1525
0
{
1526
  /* Exactly the same as oidrecv, so share code */
1527
0
  return oidrecv(fcinfo);
1528
0
}
1529
1530
/*
1531
 *    regdictionarysend - converts regdictionary to binary format
1532
 */
1533
Datum
1534
regdictionarysend(PG_FUNCTION_ARGS)
1535
0
{
1536
  /* Exactly the same as oidsend, so share code */
1537
0
  return oidsend(fcinfo);
1538
0
}
1539
1540
/*
1541
 * regrolein  - converts "rolename" to role OID
1542
 *
1543
 * We also accept a numeric OID, for symmetry with the output routine.
1544
 *
1545
 * '-' signifies unknown (OID 0).  In all other cases, the input must
1546
 * match an existing pg_authid entry.
1547
 */
1548
Datum
1549
regrolein(PG_FUNCTION_ARGS)
1550
0
{
1551
0
  char     *role_name_or_oid = PG_GETARG_CSTRING(0);
1552
0
  Node     *escontext = fcinfo->context;
1553
0
  Oid     result;
1554
0
  List     *names;
1555
1556
  /* Handle "-" or numeric OID */
1557
0
  if (parseDashOrOid(role_name_or_oid, &result, escontext))
1558
0
    PG_RETURN_OID(result);
1559
1560
  /* The rest of this wouldn't work in bootstrap mode */
1561
0
  if (IsBootstrapProcessingMode())
1562
0
    elog(ERROR, "regrole values must be OIDs in bootstrap mode");
1563
1564
  /* Normal case: see if the name matches any pg_authid entry. */
1565
0
  names = stringToQualifiedNameList(role_name_or_oid, escontext);
1566
0
  if (names == NIL)
1567
0
    PG_RETURN_NULL();
1568
1569
0
  if (list_length(names) != 1)
1570
0
    ereturn(escontext, (Datum) 0,
1571
0
        (errcode(ERRCODE_INVALID_NAME),
1572
0
         errmsg("invalid name syntax")));
1573
1574
0
  result = get_role_oid(strVal(linitial(names)), true);
1575
1576
0
  if (!OidIsValid(result))
1577
0
    ereturn(escontext, (Datum) 0,
1578
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
1579
0
         errmsg("role \"%s\" does not exist",
1580
0
            strVal(linitial(names)))));
1581
1582
0
  PG_RETURN_OID(result);
1583
0
}
1584
1585
/*
1586
 * to_regrole   - converts "rolename" to role OID
1587
 *
1588
 * If the name is not found, we return NULL.
1589
 */
1590
Datum
1591
to_regrole(PG_FUNCTION_ARGS)
1592
0
{
1593
0
  char     *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1594
0
  Datum   result;
1595
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
1596
1597
0
  if (!DirectInputFunctionCallSafe(regrolein, role_name,
1598
0
                   InvalidOid, -1,
1599
0
                   (Node *) &escontext,
1600
0
                   &result))
1601
0
    PG_RETURN_NULL();
1602
0
  PG_RETURN_DATUM(result);
1603
0
}
1604
1605
/*
1606
 * regroleout   - converts role OID to "role_name"
1607
 */
1608
Datum
1609
regroleout(PG_FUNCTION_ARGS)
1610
0
{
1611
0
  Oid     roleoid = PG_GETARG_OID(0);
1612
0
  char     *result;
1613
1614
0
  if (roleoid == InvalidOid)
1615
0
  {
1616
0
    result = pstrdup("-");
1617
0
    PG_RETURN_CSTRING(result);
1618
0
  }
1619
1620
0
  result = GetUserNameFromId(roleoid, true);
1621
1622
0
  if (result)
1623
0
  {
1624
    /* pstrdup is not really necessary, but it avoids a compiler warning */
1625
0
    result = pstrdup(quote_identifier(result));
1626
0
  }
1627
0
  else
1628
0
  {
1629
    /* If OID doesn't match any role, return it numerically */
1630
0
    result = (char *) palloc(NAMEDATALEN);
1631
0
    snprintf(result, NAMEDATALEN, "%u", roleoid);
1632
0
  }
1633
1634
0
  PG_RETURN_CSTRING(result);
1635
0
}
1636
1637
/*
1638
 *    regrolerecv - converts external binary format to regrole
1639
 */
1640
Datum
1641
regrolerecv(PG_FUNCTION_ARGS)
1642
0
{
1643
  /* Exactly the same as oidrecv, so share code */
1644
0
  return oidrecv(fcinfo);
1645
0
}
1646
1647
/*
1648
 *    regrolesend - converts regrole to binary format
1649
 */
1650
Datum
1651
regrolesend(PG_FUNCTION_ARGS)
1652
0
{
1653
  /* Exactly the same as oidsend, so share code */
1654
0
  return oidsend(fcinfo);
1655
0
}
1656
1657
/*
1658
 * regnamespacein   - converts "nspname" to namespace OID
1659
 *
1660
 * We also accept a numeric OID, for symmetry with the output routine.
1661
 *
1662
 * '-' signifies unknown (OID 0).  In all other cases, the input must
1663
 * match an existing pg_namespace entry.
1664
 */
1665
Datum
1666
regnamespacein(PG_FUNCTION_ARGS)
1667
0
{
1668
0
  char     *nsp_name_or_oid = PG_GETARG_CSTRING(0);
1669
0
  Node     *escontext = fcinfo->context;
1670
0
  Oid     result;
1671
0
  List     *names;
1672
1673
  /* Handle "-" or numeric OID */
1674
0
  if (parseDashOrOid(nsp_name_or_oid, &result, escontext))
1675
0
    PG_RETURN_OID(result);
1676
1677
  /* The rest of this wouldn't work in bootstrap mode */
1678
0
  if (IsBootstrapProcessingMode())
1679
0
    elog(ERROR, "regnamespace values must be OIDs in bootstrap mode");
1680
1681
  /* Normal case: see if the name matches any pg_namespace entry. */
1682
0
  names = stringToQualifiedNameList(nsp_name_or_oid, escontext);
1683
0
  if (names == NIL)
1684
0
    PG_RETURN_NULL();
1685
1686
0
  if (list_length(names) != 1)
1687
0
    ereturn(escontext, (Datum) 0,
1688
0
        (errcode(ERRCODE_INVALID_NAME),
1689
0
         errmsg("invalid name syntax")));
1690
1691
0
  result = get_namespace_oid(strVal(linitial(names)), true);
1692
1693
0
  if (!OidIsValid(result))
1694
0
    ereturn(escontext, (Datum) 0,
1695
0
        (errcode(ERRCODE_UNDEFINED_SCHEMA),
1696
0
         errmsg("schema \"%s\" does not exist",
1697
0
            strVal(linitial(names)))));
1698
1699
0
  PG_RETURN_OID(result);
1700
0
}
1701
1702
/*
1703
 * to_regnamespace    - converts "nspname" to namespace OID
1704
 *
1705
 * If the name is not found, we return NULL.
1706
 */
1707
Datum
1708
to_regnamespace(PG_FUNCTION_ARGS)
1709
0
{
1710
0
  char     *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1711
0
  Datum   result;
1712
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
1713
1714
0
  if (!DirectInputFunctionCallSafe(regnamespacein, nsp_name,
1715
0
                   InvalidOid, -1,
1716
0
                   (Node *) &escontext,
1717
0
                   &result))
1718
0
    PG_RETURN_NULL();
1719
0
  PG_RETURN_DATUM(result);
1720
0
}
1721
1722
/*
1723
 * regnamespaceout    - converts namespace OID to "nsp_name"
1724
 */
1725
Datum
1726
regnamespaceout(PG_FUNCTION_ARGS)
1727
0
{
1728
0
  Oid     nspid = PG_GETARG_OID(0);
1729
0
  char     *result;
1730
1731
0
  if (nspid == InvalidOid)
1732
0
  {
1733
0
    result = pstrdup("-");
1734
0
    PG_RETURN_CSTRING(result);
1735
0
  }
1736
1737
0
  result = get_namespace_name(nspid);
1738
1739
0
  if (result)
1740
0
  {
1741
    /* pstrdup is not really necessary, but it avoids a compiler warning */
1742
0
    result = pstrdup(quote_identifier(result));
1743
0
  }
1744
0
  else
1745
0
  {
1746
    /* If OID doesn't match any namespace, return it numerically */
1747
0
    result = (char *) palloc(NAMEDATALEN);
1748
0
    snprintf(result, NAMEDATALEN, "%u", nspid);
1749
0
  }
1750
1751
0
  PG_RETURN_CSTRING(result);
1752
0
}
1753
1754
/*
1755
 *    regnamespacerecv  - converts external binary format to regnamespace
1756
 */
1757
Datum
1758
regnamespacerecv(PG_FUNCTION_ARGS)
1759
0
{
1760
  /* Exactly the same as oidrecv, so share code */
1761
0
  return oidrecv(fcinfo);
1762
0
}
1763
1764
/*
1765
 *    regnamespacesend    - converts regnamespace to binary format
1766
 */
1767
Datum
1768
regnamespacesend(PG_FUNCTION_ARGS)
1769
0
{
1770
  /* Exactly the same as oidsend, so share code */
1771
0
  return oidsend(fcinfo);
1772
0
}
1773
1774
/*
1775
 * regdatabasein - converts database name to database OID
1776
 *
1777
 * We also accept a numeric OID, for symmetry with the output routine.
1778
 *
1779
 * '-' signifies unknown (OID 0).  In all other cases, the input must
1780
 * match an existing pg_database entry.
1781
 */
1782
Datum
1783
regdatabasein(PG_FUNCTION_ARGS)
1784
0
{
1785
0
  char     *db_name_or_oid = PG_GETARG_CSTRING(0);
1786
0
  Node     *escontext = fcinfo->context;
1787
0
  Oid     result;
1788
0
  List     *names;
1789
1790
  /* Handle "-" or numeric OID */
1791
0
  if (parseDashOrOid(db_name_or_oid, &result, escontext))
1792
0
    PG_RETURN_OID(result);
1793
1794
  /* The rest of this wouldn't work in bootstrap mode */
1795
0
  if (IsBootstrapProcessingMode())
1796
0
    elog(ERROR, "regdatabase values must be OIDs in bootstrap mode");
1797
1798
  /* Normal case: see if the name matches any pg_database entry. */
1799
0
  names = stringToQualifiedNameList(db_name_or_oid, escontext);
1800
0
  if (names == NIL)
1801
0
    PG_RETURN_NULL();
1802
1803
0
  if (list_length(names) != 1)
1804
0
    ereturn(escontext, (Datum) 0,
1805
0
        (errcode(ERRCODE_INVALID_NAME),
1806
0
         errmsg("invalid name syntax")));
1807
1808
0
  result = get_database_oid(strVal(linitial(names)), true);
1809
1810
0
  if (!OidIsValid(result))
1811
0
    ereturn(escontext, (Datum) 0,
1812
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
1813
0
         errmsg("database \"%s\" does not exist",
1814
0
            strVal(linitial(names)))));
1815
1816
0
  PG_RETURN_OID(result);
1817
0
}
1818
1819
/*
1820
 * to_regdatabase - converts database name to database OID
1821
 *
1822
 * If the name is not found, we return NULL.
1823
 */
1824
Datum
1825
to_regdatabase(PG_FUNCTION_ARGS)
1826
0
{
1827
0
  char     *db_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1828
0
  Datum   result;
1829
0
  ErrorSaveContext escontext = {T_ErrorSaveContext};
1830
1831
0
  if (!DirectInputFunctionCallSafe(regdatabasein, db_name,
1832
0
                   InvalidOid, -1,
1833
0
                   (Node *) &escontext,
1834
0
                   &result))
1835
0
    PG_RETURN_NULL();
1836
0
  PG_RETURN_DATUM(result);
1837
0
}
1838
1839
/*
1840
 * regdatabaseout - converts database OID to database name
1841
 */
1842
Datum
1843
regdatabaseout(PG_FUNCTION_ARGS)
1844
0
{
1845
0
  Oid     dboid = PG_GETARG_OID(0);
1846
0
  char     *result;
1847
1848
0
  if (dboid == InvalidOid)
1849
0
  {
1850
0
    result = pstrdup("-");
1851
0
    PG_RETURN_CSTRING(result);
1852
0
  }
1853
1854
0
  result = get_database_name(dboid);
1855
1856
0
  if (result)
1857
0
  {
1858
    /* pstrdup is not really necessary, but it avoids a compiler warning */
1859
0
    result = pstrdup(quote_identifier(result));
1860
0
  }
1861
0
  else
1862
0
  {
1863
    /* If OID doesn't match any database, return it numerically */
1864
0
    result = (char *) palloc(NAMEDATALEN);
1865
0
    snprintf(result, NAMEDATALEN, "%u", dboid);
1866
0
  }
1867
1868
0
  PG_RETURN_CSTRING(result);
1869
0
}
1870
1871
/*
1872
 * regdatabaserecv - converts external binary format to regdatabase
1873
 */
1874
Datum
1875
regdatabaserecv(PG_FUNCTION_ARGS)
1876
0
{
1877
  /* Exactly the same as oidrecv, so share code */
1878
0
  return oidrecv(fcinfo);
1879
0
}
1880
1881
/*
1882
 * regdatabasesend - converts regdatabase to binary format
1883
 */
1884
Datum
1885
regdatabasesend(PG_FUNCTION_ARGS)
1886
0
{
1887
  /* Exactly the same as oidsend, so share code */
1888
0
  return oidsend(fcinfo);
1889
0
}
1890
1891
/*
1892
 * text_regclass: convert text to regclass
1893
 *
1894
 * This could be replaced by CoerceViaIO, except that we need to treat
1895
 * text-to-regclass as an implicit cast to support legacy forms of nextval()
1896
 * and related functions.
1897
 */
1898
Datum
1899
text_regclass(PG_FUNCTION_ARGS)
1900
0
{
1901
0
  text     *relname = PG_GETARG_TEXT_PP(0);
1902
0
  Oid     result;
1903
0
  RangeVar   *rv;
1904
1905
0
  rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
1906
1907
  /* We might not even have permissions on this relation; don't lock it. */
1908
0
  result = RangeVarGetRelid(rv, NoLock, false);
1909
1910
0
  PG_RETURN_OID(result);
1911
0
}
1912
1913
1914
/*
1915
 * Given a C string, parse it into a qualified-name list.
1916
 *
1917
 * If escontext is an ErrorSaveContext node, invalid input will be
1918
 * reported there instead of being thrown, and we return NIL.
1919
 * (NIL is not possible as a success return, since empty-input is an error.)
1920
 */
1921
List *
1922
stringToQualifiedNameList(const char *string, Node *escontext)
1923
0
{
1924
0
  char     *rawname;
1925
0
  List     *result = NIL;
1926
0
  List     *namelist;
1927
0
  ListCell   *l;
1928
1929
  /* We need a modifiable copy of the input string. */
1930
0
  rawname = pstrdup(string);
1931
1932
0
  if (!SplitIdentifierString(rawname, '.', &namelist))
1933
0
    ereturn(escontext, NIL,
1934
0
        (errcode(ERRCODE_INVALID_NAME),
1935
0
         errmsg("invalid name syntax")));
1936
1937
0
  if (namelist == NIL)
1938
0
    ereturn(escontext, NIL,
1939
0
        (errcode(ERRCODE_INVALID_NAME),
1940
0
         errmsg("invalid name syntax")));
1941
1942
0
  foreach(l, namelist)
1943
0
  {
1944
0
    char     *curname = (char *) lfirst(l);
1945
1946
0
    result = lappend(result, makeString(pstrdup(curname)));
1947
0
  }
1948
1949
0
  pfree(rawname);
1950
0
  list_free(namelist);
1951
1952
0
  return result;
1953
0
}
1954
1955
/*****************************************************************************
1956
 *   SUPPORT ROUTINES                            *
1957
 *****************************************************************************/
1958
1959
/*
1960
 * Given a C string, see if it is all-digits (and not empty).
1961
 * If so, convert directly to OID and return true.
1962
 * If it is not all-digits, return false.
1963
 *
1964
 * If escontext is an ErrorSaveContext node, any error in oidin() will be
1965
 * reported there instead of being thrown (but we still return true).
1966
 */
1967
static bool
1968
parseNumericOid(char *string, Oid *result, Node *escontext)
1969
0
{
1970
0
  if (string[0] >= '0' && string[0] <= '9' &&
1971
0
    strspn(string, "0123456789") == strlen(string))
1972
0
  {
1973
0
    Datum   oid_datum;
1974
1975
    /* We need not care here whether oidin() fails or not. */
1976
0
    (void) DirectInputFunctionCallSafe(oidin, string,
1977
0
                       InvalidOid, -1,
1978
0
                       escontext,
1979
0
                       &oid_datum);
1980
0
    *result = DatumGetObjectId(oid_datum);
1981
0
    return true;
1982
0
  }
1983
1984
  /* Prevent uninitialized-variable warnings from stupider compilers. */
1985
0
  *result = InvalidOid;
1986
0
  return false;
1987
0
}
1988
1989
/*
1990
 * As above, but also accept "-" as meaning 0 (InvalidOid).
1991
 */
1992
static bool
1993
parseDashOrOid(char *string, Oid *result, Node *escontext)
1994
0
{
1995
  /* '-' ? */
1996
0
  if (strcmp(string, "-") == 0)
1997
0
  {
1998
0
    *result = InvalidOid;
1999
0
    return true;
2000
0
  }
2001
2002
  /* Numeric OID? */
2003
0
  return parseNumericOid(string, result, escontext);
2004
0
}
2005
2006
/*
2007
 * Given a C string, parse it into a qualified function or operator name
2008
 * followed by a parenthesized list of type names.  Reduce the
2009
 * type names to an array of OIDs (returned into *nargs and *argtypes;
2010
 * the argtypes array should be of size FUNC_MAX_ARGS).  The function or
2011
 * operator name is returned to *names as a List of Strings.
2012
 *
2013
 * If allowNone is true, accept "NONE" and return it as InvalidOid (this is
2014
 * for unary operators).
2015
 *
2016
 * Returns true on success, false on failure (the latter only possible
2017
 * if escontext is an ErrorSaveContext node).
2018
 */
2019
static bool
2020
parseNameAndArgTypes(const char *string, bool allowNone, List **names,
2021
           int *nargs, Oid *argtypes,
2022
           Node *escontext)
2023
0
{
2024
0
  char     *rawname;
2025
0
  char     *ptr;
2026
0
  char     *ptr2;
2027
0
  char     *typename;
2028
0
  bool    in_quote;
2029
0
  bool    had_comma;
2030
0
  int     paren_count;
2031
0
  Oid     typeid;
2032
0
  int32   typmod;
2033
2034
  /* We need a modifiable copy of the input string. */
2035
0
  rawname = pstrdup(string);
2036
2037
  /* Scan to find the expected left paren; mustn't be quoted */
2038
0
  in_quote = false;
2039
0
  for (ptr = rawname; *ptr; ptr++)
2040
0
  {
2041
0
    if (*ptr == '"')
2042
0
      in_quote = !in_quote;
2043
0
    else if (*ptr == '(' && !in_quote)
2044
0
      break;
2045
0
  }
2046
0
  if (*ptr == '\0')
2047
0
    ereturn(escontext, false,
2048
0
        (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2049
0
         errmsg("expected a left parenthesis")));
2050
2051
  /* Separate the name and parse it into a list */
2052
0
  *ptr++ = '\0';
2053
0
  *names = stringToQualifiedNameList(rawname, escontext);
2054
0
  if (*names == NIL)
2055
0
    return false;
2056
2057
  /* Check for the trailing right parenthesis and remove it */
2058
0
  ptr2 = ptr + strlen(ptr);
2059
0
  while (--ptr2 > ptr)
2060
0
  {
2061
0
    if (!scanner_isspace(*ptr2))
2062
0
      break;
2063
0
  }
2064
0
  if (*ptr2 != ')')
2065
0
    ereturn(escontext, false,
2066
0
        (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2067
0
         errmsg("expected a right parenthesis")));
2068
2069
0
  *ptr2 = '\0';
2070
2071
  /* Separate the remaining string into comma-separated type names */
2072
0
  *nargs = 0;
2073
0
  had_comma = false;
2074
2075
0
  for (;;)
2076
0
  {
2077
    /* allow leading whitespace */
2078
0
    while (scanner_isspace(*ptr))
2079
0
      ptr++;
2080
0
    if (*ptr == '\0')
2081
0
    {
2082
      /* End of string.  Okay unless we had a comma before. */
2083
0
      if (had_comma)
2084
0
        ereturn(escontext, false,
2085
0
            (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2086
0
             errmsg("expected a type name")));
2087
0
      break;
2088
0
    }
2089
0
    typename = ptr;
2090
    /* Find end of type name --- end of string or comma */
2091
    /* ... but not a quoted or parenthesized comma */
2092
0
    in_quote = false;
2093
0
    paren_count = 0;
2094
0
    for (; *ptr; ptr++)
2095
0
    {
2096
0
      if (*ptr == '"')
2097
0
        in_quote = !in_quote;
2098
0
      else if (*ptr == ',' && !in_quote && paren_count == 0)
2099
0
        break;
2100
0
      else if (!in_quote)
2101
0
      {
2102
0
        switch (*ptr)
2103
0
        {
2104
0
          case '(':
2105
0
          case '[':
2106
0
            paren_count++;
2107
0
            break;
2108
0
          case ')':
2109
0
          case ']':
2110
0
            paren_count--;
2111
0
            break;
2112
0
        }
2113
0
      }
2114
0
    }
2115
0
    if (in_quote || paren_count != 0)
2116
0
      ereturn(escontext, false,
2117
0
          (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2118
0
           errmsg("improper type name")));
2119
2120
0
    ptr2 = ptr;
2121
0
    if (*ptr == ',')
2122
0
    {
2123
0
      had_comma = true;
2124
0
      *ptr++ = '\0';
2125
0
    }
2126
0
    else
2127
0
    {
2128
0
      had_comma = false;
2129
0
      Assert(*ptr == '\0');
2130
0
    }
2131
    /* Lop off trailing whitespace */
2132
0
    while (--ptr2 >= typename)
2133
0
    {
2134
0
      if (!scanner_isspace(*ptr2))
2135
0
        break;
2136
0
      *ptr2 = '\0';
2137
0
    }
2138
2139
0
    if (allowNone && pg_strcasecmp(typename, "none") == 0)
2140
0
    {
2141
      /* Special case for NONE */
2142
0
      typeid = InvalidOid;
2143
0
      typmod = -1;
2144
0
    }
2145
0
    else
2146
0
    {
2147
      /* Use full parser to resolve the type name */
2148
0
      if (!parseTypeString(typename, &typeid, &typmod, escontext))
2149
0
        return false;
2150
0
    }
2151
0
    if (*nargs >= FUNC_MAX_ARGS)
2152
0
      ereturn(escontext, false,
2153
0
          (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2154
0
           errmsg("too many arguments")));
2155
2156
0
    argtypes[*nargs] = typeid;
2157
0
    (*nargs)++;
2158
0
  }
2159
2160
0
  pfree(rawname);
2161
2162
  return true;
2163
0
}