Branch data Line data Source code
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-2026, 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 : 9880 : regprocin(PG_FUNCTION_ARGS)
68 : : {
69 : 9880 : char *pro_name_or_oid = PG_GETARG_CSTRING(0);
70 : 9880 : Node *escontext = fcinfo->context;
71 : 9880 : RegProcedure result;
72 : 9880 : List *names;
73 : 9880 : FuncCandidateList clist;
74 : 9880 : int fgc_flags;
75 : :
76 : : /* Handle "-" or numeric OID */
77 [ + + ]: 9880 : if (parseDashOrOid(pro_name_or_oid, &result, escontext))
78 : 9806 : 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 [ + - ]: 74 : 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 : 74 : names = stringToQualifiedNameList(pro_name_or_oid, escontext);
94 [ + - ]: 74 : if (names == NIL)
95 : 0 : PG_RETURN_NULL();
96 : :
97 : 74 : clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true,
98 : : &fgc_flags);
99 : :
100 [ + + ]: 74 : if (clist == NULL)
101 [ - + ]: 3 : ereturn(escontext, (Datum) 0,
102 : : (errcode(ERRCODE_UNDEFINED_FUNCTION),
103 : : errmsg("function \"%s\" does not exist", pro_name_or_oid)));
104 [ + - ]: 71 : else if (clist->next != NULL)
105 [ # # ]: 0 : ereturn(escontext, (Datum) 0,
106 : : (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
107 : : errmsg("more than one function named \"%s\"",
108 : : pro_name_or_oid)));
109 : :
110 : 71 : result = clist->oid;
111 : :
112 : 71 : PG_RETURN_OID(result);
113 : 9880 : }
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 : 5 : to_regproc(PG_FUNCTION_ARGS)
122 : : {
123 : 5 : char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
124 : 5 : Datum result;
125 : 5 : ErrorSaveContext escontext = {T_ErrorSaveContext};
126 : :
127 [ + + ]: 5 : if (!DirectInputFunctionCallSafe(regprocin, pro_name,
128 : : InvalidOid, -1,
129 : : (Node *) &escontext,
130 : : &result))
131 : 2 : PG_RETURN_NULL();
132 : 3 : PG_RETURN_DATUM(result);
133 : 5 : }
134 : :
135 : : /*
136 : : * regprocout - converts proc OID to "pro_name"
137 : : */
138 : : Datum
139 : 254 : regprocout(PG_FUNCTION_ARGS)
140 : : {
141 : 254 : RegProcedure proid = PG_GETARG_OID(0);
142 : 254 : char *result;
143 : 254 : HeapTuple proctup;
144 : :
145 [ + + ]: 254 : if (proid == InvalidOid)
146 : : {
147 : 86 : result = pstrdup("-");
148 : 86 : PG_RETURN_CSTRING(result);
149 : : }
150 : :
151 : 168 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
152 : :
153 [ + - ]: 168 : if (HeapTupleIsValid(proctup))
154 : : {
155 : 168 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
156 : 168 : 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 [ + - ]: 168 : if (IsBootstrapProcessingMode())
164 : 0 : result = pstrdup(proname);
165 : : else
166 : : {
167 : 168 : char *nspname;
168 : 168 : FuncCandidateList clist;
169 : 168 : int fgc_flags;
170 : :
171 : : /*
172 : : * Would this proc be found (uniquely!) by regprocin? If not,
173 : : * qualify it.
174 : : */
175 : 168 : clist = FuncnameGetCandidates(list_make1(makeString(proname)),
176 : : -1, NIL, false, false, false, false,
177 : : &fgc_flags);
178 [ + - + - : 168 : if (clist != NULL && clist->next == NULL &&
- + ]
179 : 168 : clist->oid == proid)
180 : 168 : nspname = NULL;
181 : : else
182 : 0 : nspname = get_namespace_name(procform->pronamespace);
183 : :
184 : 168 : result = quote_qualified_identifier(nspname, proname);
185 : 168 : }
186 : :
187 : 168 : ReleaseSysCache(proctup);
188 : 168 : }
189 : : else
190 : : {
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 : : }
195 : :
196 : 168 : PG_RETURN_CSTRING(result);
197 : 254 : }
198 : :
199 : : /*
200 : : * regprocrecv - converts external binary format to regproc
201 : : */
202 : : Datum
203 : 0 : regprocrecv(PG_FUNCTION_ARGS)
204 : : {
205 : : /* Exactly the same as oidrecv, so share code */
206 : 0 : return oidrecv(fcinfo);
207 : : }
208 : :
209 : : /*
210 : : * regprocsend - converts regproc to binary format
211 : : */
212 : : Datum
213 : 0 : regprocsend(PG_FUNCTION_ARGS)
214 : : {
215 : : /* Exactly the same as oidsend, so share code */
216 : 0 : return oidsend(fcinfo);
217 : : }
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 : 44 : regprocedurein(PG_FUNCTION_ARGS)
230 : : {
231 : 44 : char *pro_name_or_oid = PG_GETARG_CSTRING(0);
232 : 44 : Node *escontext = fcinfo->context;
233 : 44 : RegProcedure result;
234 : 44 : List *names;
235 : 44 : int nargs;
236 : 44 : Oid argtypes[FUNC_MAX_ARGS];
237 : 44 : FuncCandidateList clist;
238 : 44 : int fgc_flags;
239 : :
240 : : /* Handle "-" or numeric OID */
241 [ + + ]: 44 : if (parseDashOrOid(pro_name_or_oid, &result, escontext))
242 : 2 : PG_RETURN_OID(result);
243 : :
244 : : /* The rest of this wouldn't work in bootstrap mode */
245 [ + - ]: 42 : 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 [ + + + + ]: 84 : if (!parseNameAndArgTypes(pro_name_or_oid, false,
255 : 42 : &names, &nargs, argtypes,
256 : 42 : escontext))
257 : 1 : PG_RETURN_NULL();
258 : :
259 : 41 : clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false, true,
260 : : &fgc_flags);
261 : :
262 [ + + ]: 41 : for (; clist; clist = clist->next)
263 : : {
264 [ + - ]: 38 : if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
265 : 38 : break;
266 : 0 : }
267 : :
268 [ + + ]: 41 : if (clist == NULL)
269 [ - + ]: 3 : ereturn(escontext, (Datum) 0,
270 : : (errcode(ERRCODE_UNDEFINED_FUNCTION),
271 : : errmsg("function \"%s\" does not exist", pro_name_or_oid)));
272 : :
273 : 38 : result = clist->oid;
274 : :
275 : 38 : PG_RETURN_OID(result);
276 : 44 : }
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 : 5 : to_regprocedure(PG_FUNCTION_ARGS)
285 : : {
286 : 5 : char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
287 : 5 : Datum result;
288 : 5 : ErrorSaveContext escontext = {T_ErrorSaveContext};
289 : :
290 [ + + ]: 5 : if (!DirectInputFunctionCallSafe(regprocedurein, pro_name,
291 : : InvalidOid, -1,
292 : : (Node *) &escontext,
293 : : &result))
294 : 2 : PG_RETURN_NULL();
295 : 3 : PG_RETURN_DATUM(result);
296 : 5 : }
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 : 1298 : format_procedure(Oid procedure_oid)
306 : : {
307 : 1298 : return format_procedure_extended(procedure_oid, 0);
308 : : }
309 : :
310 : : char *
311 : 0 : format_procedure_qualified(Oid procedure_oid)
312 : : {
313 : 0 : return format_procedure_extended(procedure_oid, FORMAT_PROC_FORCE_QUALIFY);
314 : : }
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 : 1548 : format_procedure_extended(Oid procedure_oid, bits16 flags)
333 : : {
334 : 1548 : char *result;
335 : 1548 : HeapTuple proctup;
336 : :
337 : 1548 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
338 : :
339 [ + + ]: 1548 : if (HeapTupleIsValid(proctup))
340 : : {
341 : 1545 : Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
342 : 1545 : char *proname = NameStr(procform->proname);
343 : 1545 : int nargs = procform->pronargs;
344 : 1545 : int i;
345 : 1545 : char *nspname;
346 : 1545 : StringInfoData buf;
347 : :
348 : : /* XXX no support here for bootstrap mode */
349 [ + - ]: 1545 : Assert(!IsBootstrapProcessingMode());
350 : :
351 : 1545 : 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 [ + + + + ]: 1545 : if ((flags & FORMAT_PROC_FORCE_QUALIFY) == 0 &&
358 : 1506 : FunctionIsVisible(procedure_oid))
359 : 1479 : nspname = NULL;
360 : : else
361 : 66 : nspname = get_namespace_name(procform->pronamespace);
362 : :
363 : 1545 : appendStringInfo(&buf, "%s(",
364 : 1545 : quote_qualified_identifier(nspname, proname));
365 [ + + ]: 2978 : for (i = 0; i < nargs; i++)
366 : : {
367 : 1433 : Oid thisargtype = procform->proargtypes.values[i];
368 : :
369 [ + + ]: 1433 : if (i > 0)
370 : 565 : appendStringInfoChar(&buf, ',');
371 : 1433 : appendStringInfoString(&buf,
372 [ + + ]: 1433 : (flags & FORMAT_PROC_FORCE_QUALIFY) != 0 ?
373 : 47 : format_type_be_qualified(thisargtype) :
374 : 1386 : format_type_be(thisargtype));
375 : 1433 : }
376 : 1545 : appendStringInfoChar(&buf, ')');
377 : :
378 : 1545 : result = buf.data;
379 : :
380 : 1545 : ReleaseSysCache(proctup);
381 : 1545 : }
382 [ + - ]: 3 : else if ((flags & FORMAT_PROC_INVALID_AS_NULL) != 0)
383 : : {
384 : : /* If object is undefined, return NULL as wanted by caller */
385 : 3 : result = NULL;
386 : 3 : }
387 : : else
388 : : {
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 : : }
393 : :
394 : 3096 : return result;
395 : 1548 : }
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 : 19 : format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs,
405 : : bool missing_ok)
406 : : {
407 : 19 : HeapTuple proctup;
408 : 19 : Form_pg_proc procform;
409 : 19 : int nargs;
410 : 19 : int i;
411 : :
412 : 19 : proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
413 : :
414 [ + - ]: 19 : if (!HeapTupleIsValid(proctup))
415 : : {
416 [ # # ]: 0 : if (!missing_ok)
417 [ # # # # ]: 0 : elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
418 : 0 : return;
419 : : }
420 : :
421 : 19 : procform = (Form_pg_proc) GETSTRUCT(proctup);
422 : 19 : nargs = procform->pronargs;
423 : :
424 : 19 : *objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
425 : : pstrdup(NameStr(procform->proname)));
426 : 19 : *objargs = NIL;
427 [ + + ]: 36 : for (i = 0; i < nargs; i++)
428 : : {
429 : 17 : Oid thisargtype = procform->proargtypes.values[i];
430 : :
431 : 17 : *objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
432 : 17 : }
433 : :
434 : 19 : ReleaseSysCache(proctup);
435 [ - + ]: 19 : }
436 : :
437 : : /*
438 : : * regprocedureout - converts proc OID to "pro_name(args)"
439 : : */
440 : : Datum
441 : 370 : regprocedureout(PG_FUNCTION_ARGS)
442 : : {
443 : 370 : RegProcedure proid = PG_GETARG_OID(0);
444 : 370 : char *result;
445 : :
446 [ + - ]: 370 : if (proid == InvalidOid)
447 : 0 : result = pstrdup("-");
448 : : else
449 : 370 : result = format_procedure(proid);
450 : :
451 : 740 : PG_RETURN_CSTRING(result);
452 : 370 : }
453 : :
454 : : /*
455 : : * regprocedurerecv - converts external binary format to regprocedure
456 : : */
457 : : Datum
458 : 0 : regprocedurerecv(PG_FUNCTION_ARGS)
459 : : {
460 : : /* Exactly the same as oidrecv, so share code */
461 : 0 : return oidrecv(fcinfo);
462 : : }
463 : :
464 : : /*
465 : : * regproceduresend - converts regprocedure to binary format
466 : : */
467 : : Datum
468 : 0 : regproceduresend(PG_FUNCTION_ARGS)
469 : : {
470 : : /* Exactly the same as oidsend, so share code */
471 : 0 : return oidsend(fcinfo);
472 : : }
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 : 8 : regoperin(PG_FUNCTION_ARGS)
485 : : {
486 : 8 : char *opr_name_or_oid = PG_GETARG_CSTRING(0);
487 : 8 : Node *escontext = fcinfo->context;
488 : 8 : Oid result;
489 : 8 : List *names;
490 : 8 : FuncCandidateList clist;
491 : 8 : int fgc_flags;
492 : :
493 : : /* Handle "0" or numeric OID */
494 [ - + ]: 8 : 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 [ + - ]: 8 : 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 : 8 : names = stringToQualifiedNameList(opr_name_or_oid, escontext);
508 [ + - ]: 8 : if (names == NIL)
509 : 0 : PG_RETURN_NULL();
510 : :
511 : 8 : clist = OpernameGetCandidates(names, '\0', true, &fgc_flags);
512 : :
513 [ + + ]: 8 : if (clist == NULL)
514 [ - + ]: 3 : ereturn(escontext, (Datum) 0,
515 : : (errcode(ERRCODE_UNDEFINED_FUNCTION),
516 : : errmsg("operator does not exist: %s", opr_name_or_oid)));
517 [ + + ]: 5 : else if (clist->next != NULL)
518 [ - + ]: 1 : ereturn(escontext, (Datum) 0,
519 : : (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
520 : : errmsg("more than one operator named %s",
521 : : opr_name_or_oid)));
522 : :
523 : 4 : result = clist->oid;
524 : :
525 : 4 : PG_RETURN_OID(result);
526 : 8 : }
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 : 4 : to_regoper(PG_FUNCTION_ARGS)
535 : : {
536 : 4 : char *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
537 : 4 : Datum result;
538 : 4 : ErrorSaveContext escontext = {T_ErrorSaveContext};
539 : :
540 [ + + ]: 4 : if (!DirectInputFunctionCallSafe(regoperin, opr_name,
541 : : InvalidOid, -1,
542 : : (Node *) &escontext,
543 : : &result))
544 : 2 : PG_RETURN_NULL();
545 : 2 : PG_RETURN_DATUM(result);
546 : 4 : }
547 : :
548 : : /*
549 : : * regoperout - converts operator OID to "opr_name"
550 : : */
551 : : Datum
552 : 4 : regoperout(PG_FUNCTION_ARGS)
553 : : {
554 : 4 : Oid oprid = PG_GETARG_OID(0);
555 : 4 : char *result;
556 : 4 : HeapTuple opertup;
557 : :
558 [ + - ]: 4 : if (oprid == InvalidOid)
559 : : {
560 : 0 : result = pstrdup("0");
561 : 0 : PG_RETURN_CSTRING(result);
562 : : }
563 : :
564 : 4 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
565 : :
566 [ + - ]: 4 : if (HeapTupleIsValid(opertup))
567 : : {
568 : 4 : Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
569 : 4 : 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 [ + - ]: 4 : if (IsBootstrapProcessingMode())
577 : 0 : result = pstrdup(oprname);
578 : : else
579 : : {
580 : 4 : FuncCandidateList clist;
581 : 4 : int fgc_flags;
582 : :
583 : : /*
584 : : * Would this oper be found (uniquely!) by regoperin? If not,
585 : : * qualify it.
586 : : */
587 : 4 : clist = OpernameGetCandidates(list_make1(makeString(oprname)),
588 : : '\0', false, &fgc_flags);
589 [ + - + - : 4 : if (clist != NULL && clist->next == NULL &&
- + ]
590 : 4 : clist->oid == oprid)
591 : 4 : result = pstrdup(oprname);
592 : : else
593 : : {
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 : 4 : }
602 : :
603 : 4 : ReleaseSysCache(opertup);
604 : 4 : }
605 : : else
606 : : {
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 : : }
613 : :
614 : 4 : PG_RETURN_CSTRING(result);
615 : 4 : }
616 : :
617 : : /*
618 : : * regoperrecv - converts external binary format to regoper
619 : : */
620 : : Datum
621 : 0 : regoperrecv(PG_FUNCTION_ARGS)
622 : : {
623 : : /* Exactly the same as oidrecv, so share code */
624 : 0 : return oidrecv(fcinfo);
625 : : }
626 : :
627 : : /*
628 : : * regopersend - converts regoper to binary format
629 : : */
630 : : Datum
631 : 0 : regopersend(PG_FUNCTION_ARGS)
632 : : {
633 : : /* Exactly the same as oidsend, so share code */
634 : 0 : return oidsend(fcinfo);
635 : : }
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 : 12 : regoperatorin(PG_FUNCTION_ARGS)
648 : : {
649 : 12 : char *opr_name_or_oid = PG_GETARG_CSTRING(0);
650 : 12 : Node *escontext = fcinfo->context;
651 : 12 : Oid result;
652 : 12 : List *names;
653 : 12 : int nargs;
654 : 12 : Oid argtypes[FUNC_MAX_ARGS];
655 : :
656 : : /* Handle "0" or numeric OID */
657 [ - + ]: 12 : 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 [ + - ]: 12 : 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 [ + + + + ]: 24 : if (!parseNameAndArgTypes(opr_name_or_oid, true,
671 : 12 : &names, &nargs, argtypes,
672 : 12 : escontext))
673 : 1 : PG_RETURN_NULL();
674 : :
675 [ + - ]: 11 : if (nargs == 1)
676 [ # # ]: 0 : ereturn(escontext, (Datum) 0,
677 : : (errcode(ERRCODE_UNDEFINED_PARAMETER),
678 : : errmsg("missing argument"),
679 : : errhint("Use NONE to denote the missing argument of a unary operator.")));
680 [ + - ]: 11 : if (nargs != 2)
681 [ # # ]: 0 : ereturn(escontext, (Datum) 0,
682 : : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
683 : : errmsg("too many arguments"),
684 : : errhint("Provide two argument types for operator.")));
685 : :
686 : 11 : result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
687 : :
688 [ + + ]: 11 : if (!OidIsValid(result))
689 [ - + ]: 3 : ereturn(escontext, (Datum) 0,
690 : : (errcode(ERRCODE_UNDEFINED_FUNCTION),
691 : : errmsg("operator does not exist: %s", opr_name_or_oid)));
692 : :
693 : 8 : PG_RETURN_OID(result);
694 : 12 : }
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 : 3 : to_regoperator(PG_FUNCTION_ARGS)
703 : : {
704 : 3 : char *opr_name_or_oid = text_to_cstring(PG_GETARG_TEXT_PP(0));
705 : 3 : Datum result;
706 : 3 : ErrorSaveContext escontext = {T_ErrorSaveContext};
707 : :
708 [ + + ]: 3 : if (!DirectInputFunctionCallSafe(regoperatorin, opr_name_or_oid,
709 : : InvalidOid, -1,
710 : : (Node *) &escontext,
711 : : &result))
712 : 2 : PG_RETURN_NULL();
713 : 1 : PG_RETURN_DATUM(result);
714 : 3 : }
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 : 101 : format_operator_extended(Oid operator_oid, bits16 flags)
731 : : {
732 : 101 : char *result;
733 : 101 : HeapTuple opertup;
734 : :
735 : 101 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
736 : :
737 [ + + ]: 101 : if (HeapTupleIsValid(opertup))
738 : : {
739 : 98 : Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
740 : 98 : char *oprname = NameStr(operform->oprname);
741 : 98 : char *nspname;
742 : 98 : StringInfoData buf;
743 : :
744 : : /* XXX no support here for bootstrap mode */
745 [ + - ]: 98 : Assert(!IsBootstrapProcessingMode());
746 : :
747 : 98 : 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 [ + + + + ]: 98 : if ((flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ||
754 : 91 : !OperatorIsVisible(operator_oid))
755 : : {
756 : 10 : nspname = get_namespace_name(operform->oprnamespace);
757 : 10 : appendStringInfo(&buf, "%s.",
758 : 10 : quote_identifier(nspname));
759 : 10 : }
760 : :
761 : 98 : appendStringInfo(&buf, "%s(", oprname);
762 : :
763 [ + - ]: 98 : if (operform->oprleft)
764 : 98 : appendStringInfo(&buf, "%s,",
765 [ + + ]: 98 : (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
766 : 7 : format_type_be_qualified(operform->oprleft) :
767 : 91 : format_type_be(operform->oprleft));
768 : : else
769 : 0 : appendStringInfoString(&buf, "NONE,");
770 : :
771 [ + - ]: 98 : if (operform->oprright)
772 : 98 : appendStringInfo(&buf, "%s)",
773 [ + + ]: 98 : (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
774 : 7 : format_type_be_qualified(operform->oprright) :
775 : 91 : format_type_be(operform->oprright));
776 : : else
777 : 0 : appendStringInfoString(&buf, "NONE)");
778 : :
779 : 98 : result = buf.data;
780 : :
781 : 98 : ReleaseSysCache(opertup);
782 : 98 : }
783 [ + - ]: 3 : else if ((flags & FORMAT_OPERATOR_INVALID_AS_NULL) != 0)
784 : : {
785 : : /* If object is undefined, return NULL as wanted by caller */
786 : 3 : result = NULL;
787 : 3 : }
788 : : else
789 : : {
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 : : }
796 : :
797 : 202 : return result;
798 : 101 : }
799 : :
800 : : char *
801 : 82 : format_operator(Oid operator_oid)
802 : : {
803 : 82 : return format_operator_extended(operator_oid, 0);
804 : : }
805 : :
806 : : char *
807 : 0 : format_operator_qualified(Oid operator_oid)
808 : : {
809 : 0 : return format_operator_extended(operator_oid,
810 : : FORMAT_OPERATOR_FORCE_QUALIFY);
811 : : }
812 : :
813 : : void
814 : 1 : format_operator_parts(Oid operator_oid, List **objnames, List **objargs,
815 : : bool missing_ok)
816 : : {
817 : 1 : HeapTuple opertup;
818 : 1 : Form_pg_operator oprForm;
819 : :
820 : 1 : opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
821 [ + - ]: 1 : if (!HeapTupleIsValid(opertup))
822 : : {
823 [ # # ]: 0 : if (!missing_ok)
824 [ # # # # ]: 0 : elog(ERROR, "cache lookup failed for operator with OID %u",
825 : : operator_oid);
826 : 0 : return;
827 : : }
828 : :
829 : 1 : oprForm = (Form_pg_operator) GETSTRUCT(opertup);
830 : 1 : *objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
831 : : pstrdup(NameStr(oprForm->oprname)));
832 : 1 : *objargs = NIL;
833 [ - + ]: 1 : if (oprForm->oprleft)
834 : 2 : *objargs = lappend(*objargs,
835 : 1 : format_type_be_qualified(oprForm->oprleft));
836 [ - + ]: 1 : if (oprForm->oprright)
837 : 2 : *objargs = lappend(*objargs,
838 : 1 : format_type_be_qualified(oprForm->oprright));
839 : :
840 : 1 : ReleaseSysCache(opertup);
841 [ - + ]: 1 : }
842 : :
843 : : /*
844 : : * regoperatorout - converts operator OID to "opr_name(args)"
845 : : */
846 : : Datum
847 : 31 : regoperatorout(PG_FUNCTION_ARGS)
848 : : {
849 : 31 : Oid oprid = PG_GETARG_OID(0);
850 : 31 : char *result;
851 : :
852 [ + - ]: 31 : if (oprid == InvalidOid)
853 : 0 : result = pstrdup("0");
854 : : else
855 : 31 : result = format_operator(oprid);
856 : :
857 : 62 : PG_RETURN_CSTRING(result);
858 : 31 : }
859 : :
860 : : /*
861 : : * regoperatorrecv - converts external binary format to regoperator
862 : : */
863 : : Datum
864 : 0 : regoperatorrecv(PG_FUNCTION_ARGS)
865 : : {
866 : : /* Exactly the same as oidrecv, so share code */
867 : 0 : return oidrecv(fcinfo);
868 : : }
869 : :
870 : : /*
871 : : * regoperatorsend - converts regoperator to binary format
872 : : */
873 : : Datum
874 : 0 : regoperatorsend(PG_FUNCTION_ARGS)
875 : : {
876 : : /* Exactly the same as oidsend, so share code */
877 : 0 : return oidsend(fcinfo);
878 : : }
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 : 3647 : regclassin(PG_FUNCTION_ARGS)
891 : : {
892 : 3647 : char *class_name_or_oid = PG_GETARG_CSTRING(0);
893 : 3647 : Node *escontext = fcinfo->context;
894 : 3647 : Oid result;
895 : 3647 : List *names;
896 : :
897 : : /* Handle "-" or numeric OID */
898 [ + + ]: 3647 : if (parseDashOrOid(class_name_or_oid, &result, escontext))
899 : 2561 : 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 [ + - ]: 1086 : 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 : 1086 : names = stringToQualifiedNameList(class_name_or_oid, escontext);
912 [ + - ]: 1086 : if (names == NIL)
913 : 0 : PG_RETURN_NULL();
914 : :
915 : : /* We might not even have permissions on this relation; don't lock it. */
916 : 1086 : result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
917 : :
918 [ + + ]: 1086 : if (!OidIsValid(result))
919 [ + + ]: 5 : ereturn(escontext, (Datum) 0,
920 : : (errcode(ERRCODE_UNDEFINED_TABLE),
921 : : errmsg("relation \"%s\" does not exist",
922 : : NameListToString(names))));
923 : :
924 : 1081 : PG_RETURN_OID(result);
925 : 3645 : }
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 : 5 : to_regclass(PG_FUNCTION_ARGS)
934 : : {
935 : 5 : char *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
936 : 5 : Datum result;
937 : 5 : ErrorSaveContext escontext = {T_ErrorSaveContext};
938 : :
939 [ + + ]: 5 : if (!DirectInputFunctionCallSafe(regclassin, class_name,
940 : : InvalidOid, -1,
941 : : (Node *) &escontext,
942 : : &result))
943 : 2 : PG_RETURN_NULL();
944 : 3 : PG_RETURN_DATUM(result);
945 : 5 : }
946 : :
947 : : /*
948 : : * regclassout - converts class OID to "class_name"
949 : : */
950 : : Datum
951 : 34968 : regclassout(PG_FUNCTION_ARGS)
952 : : {
953 : 34968 : Oid classid = PG_GETARG_OID(0);
954 : 34968 : char *result;
955 : 34968 : HeapTuple classtup;
956 : :
957 [ + + ]: 34968 : if (classid == InvalidOid)
958 : : {
959 : 89 : result = pstrdup("-");
960 : 89 : PG_RETURN_CSTRING(result);
961 : : }
962 : :
963 : 34879 : classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
964 : :
965 [ + + ]: 34879 : if (HeapTupleIsValid(classtup))
966 : : {
967 : 34800 : Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
968 : 34800 : 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 [ + - ]: 34800 : if (IsBootstrapProcessingMode())
976 : 0 : result = pstrdup(classname);
977 : : else
978 : : {
979 : 34800 : char *nspname;
980 : :
981 : : /*
982 : : * Would this class be found by regclassin? If not, qualify it.
983 : : */
984 [ + + ]: 34800 : if (RelationIsVisible(classid))
985 : 22854 : nspname = NULL;
986 : : else
987 : 11946 : nspname = get_namespace_name(classform->relnamespace);
988 : :
989 : 34800 : result = quote_qualified_identifier(nspname, classname);
990 : 34800 : }
991 : :
992 : 34800 : ReleaseSysCache(classtup);
993 : 34800 : }
994 : : else
995 : : {
996 : : /* If OID doesn't match any pg_class entry, return it numerically */
997 : 79 : result = (char *) palloc(NAMEDATALEN);
998 : 79 : snprintf(result, NAMEDATALEN, "%u", classid);
999 : : }
1000 : :
1001 : 34879 : PG_RETURN_CSTRING(result);
1002 : 34968 : }
1003 : :
1004 : : /*
1005 : : * regclassrecv - converts external binary format to regclass
1006 : : */
1007 : : Datum
1008 : 0 : regclassrecv(PG_FUNCTION_ARGS)
1009 : : {
1010 : : /* Exactly the same as oidrecv, so share code */
1011 : 0 : return oidrecv(fcinfo);
1012 : : }
1013 : :
1014 : : /*
1015 : : * regclasssend - converts regclass to binary format
1016 : : */
1017 : : Datum
1018 : 0 : regclasssend(PG_FUNCTION_ARGS)
1019 : : {
1020 : : /* Exactly the same as oidsend, so share code */
1021 : 0 : return oidsend(fcinfo);
1022 : : }
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 : 9 : regcollationin(PG_FUNCTION_ARGS)
1035 : : {
1036 : 9 : char *collation_name_or_oid = PG_GETARG_CSTRING(0);
1037 : 9 : Node *escontext = fcinfo->context;
1038 : 9 : Oid result;
1039 : 9 : List *names;
1040 : :
1041 : : /* Handle "-" or numeric OID */
1042 [ + + ]: 9 : if (parseDashOrOid(collation_name_or_oid, &result, escontext))
1043 : 2 : 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 [ + - ]: 7 : 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 : 7 : names = stringToQualifiedNameList(collation_name_or_oid, escontext);
1056 [ + - ]: 7 : if (names == NIL)
1057 : 0 : PG_RETURN_NULL();
1058 : :
1059 : 7 : result = get_collation_oid(names, true);
1060 : :
1061 [ + + ]: 7 : if (!OidIsValid(result))
1062 [ + + ]: 3 : ereturn(escontext, (Datum) 0,
1063 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
1064 : : errmsg("collation \"%s\" for encoding \"%s\" does not exist",
1065 : : NameListToString(names), GetDatabaseEncodingName())));
1066 : :
1067 : 4 : PG_RETURN_OID(result);
1068 : 9 : }
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 : 5 : to_regcollation(PG_FUNCTION_ARGS)
1077 : : {
1078 : 5 : char *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1079 : 5 : Datum result;
1080 : 5 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1081 : :
1082 [ + + ]: 5 : if (!DirectInputFunctionCallSafe(regcollationin, collation_name,
1083 : : InvalidOid, -1,
1084 : : (Node *) &escontext,
1085 : : &result))
1086 : 2 : PG_RETURN_NULL();
1087 : 3 : PG_RETURN_DATUM(result);
1088 : 5 : }
1089 : :
1090 : : /*
1091 : : * regcollationout - converts collation OID to "collation_name"
1092 : : */
1093 : : Datum
1094 : 4 : regcollationout(PG_FUNCTION_ARGS)
1095 : : {
1096 : 4 : Oid collationid = PG_GETARG_OID(0);
1097 : 4 : char *result;
1098 : 4 : HeapTuple collationtup;
1099 : :
1100 [ + - ]: 4 : if (collationid == InvalidOid)
1101 : : {
1102 : 0 : result = pstrdup("-");
1103 : 0 : PG_RETURN_CSTRING(result);
1104 : : }
1105 : :
1106 : 4 : collationtup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationid));
1107 : :
1108 [ + - ]: 4 : if (HeapTupleIsValid(collationtup))
1109 : : {
1110 : 4 : Form_pg_collation collationform = (Form_pg_collation) GETSTRUCT(collationtup);
1111 : 4 : 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 [ + - ]: 4 : if (IsBootstrapProcessingMode())
1119 : 0 : result = pstrdup(collationname);
1120 : : else
1121 : : {
1122 : 4 : char *nspname;
1123 : :
1124 : : /*
1125 : : * Would this collation be found by regcollationin? If not,
1126 : : * qualify it.
1127 : : */
1128 [ + - ]: 4 : if (CollationIsVisible(collationid))
1129 : 4 : nspname = NULL;
1130 : : else
1131 : 0 : nspname = get_namespace_name(collationform->collnamespace);
1132 : :
1133 : 4 : result = quote_qualified_identifier(nspname, collationname);
1134 : 4 : }
1135 : :
1136 : 4 : ReleaseSysCache(collationtup);
1137 : 4 : }
1138 : : else
1139 : : {
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 : : }
1144 : :
1145 : 4 : PG_RETURN_CSTRING(result);
1146 : 4 : }
1147 : :
1148 : : /*
1149 : : * regcollationrecv - converts external binary format to regcollation
1150 : : */
1151 : : Datum
1152 : 0 : regcollationrecv(PG_FUNCTION_ARGS)
1153 : : {
1154 : : /* Exactly the same as oidrecv, so share code */
1155 : 0 : return oidrecv(fcinfo);
1156 : : }
1157 : :
1158 : : /*
1159 : : * regcollationsend - converts regcollation to binary format
1160 : : */
1161 : : Datum
1162 : 0 : regcollationsend(PG_FUNCTION_ARGS)
1163 : : {
1164 : : /* Exactly the same as oidsend, so share code */
1165 : 0 : return oidsend(fcinfo);
1166 : : }
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 : 182 : regtypein(PG_FUNCTION_ARGS)
1185 : : {
1186 : 182 : char *typ_name_or_oid = PG_GETARG_CSTRING(0);
1187 : 182 : Node *escontext = fcinfo->context;
1188 : 182 : Oid result;
1189 : 182 : int32 typmod;
1190 : :
1191 : : /* Handle "-" or numeric OID */
1192 [ + + ]: 182 : if (parseDashOrOid(typ_name_or_oid, &result, escontext))
1193 : 2 : 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 [ + - ]: 180 : 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 : 180 : (void) parseTypeString(typ_name_or_oid, &result, &typmod, escontext);
1207 : :
1208 : 180 : PG_RETURN_OID(result);
1209 : 182 : }
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 : 8 : to_regtype(PG_FUNCTION_ARGS)
1218 : : {
1219 : 8 : char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1220 : 8 : Datum result;
1221 : 8 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1222 : :
1223 [ + + ]: 8 : if (!DirectInputFunctionCallSafe(regtypein, typ_name,
1224 : : InvalidOid, -1,
1225 : : (Node *) &escontext,
1226 : : &result))
1227 : 2 : PG_RETURN_NULL();
1228 : 6 : PG_RETURN_DATUM(result);
1229 : 8 : }
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 : 6 : to_regtypemod(PG_FUNCTION_ARGS)
1238 : : {
1239 : 6 : char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1240 : 6 : Oid typid;
1241 : 6 : int32 typmod;
1242 : 6 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1243 : :
1244 : : /* We rely on parseTypeString to parse the input. */
1245 [ + + ]: 6 : if (!parseTypeString(typ_name, &typid, &typmod, (Node *) &escontext))
1246 : 1 : PG_RETURN_NULL();
1247 : :
1248 : 5 : PG_RETURN_INT32(typmod);
1249 : 6 : }
1250 : :
1251 : : /*
1252 : : * regtypeout - converts type OID to "typ_name"
1253 : : */
1254 : : Datum
1255 : 284 : regtypeout(PG_FUNCTION_ARGS)
1256 : : {
1257 : 284 : Oid typid = PG_GETARG_OID(0);
1258 : 284 : char *result;
1259 : 284 : HeapTuple typetup;
1260 : :
1261 [ + - ]: 284 : if (typid == InvalidOid)
1262 : : {
1263 : 0 : result = pstrdup("-");
1264 : 0 : PG_RETURN_CSTRING(result);
1265 : : }
1266 : :
1267 : 284 : typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
1268 : :
1269 [ + - ]: 284 : if (HeapTupleIsValid(typetup))
1270 : : {
1271 : 284 : 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 [ + - ]: 284 : if (IsBootstrapProcessingMode())
1279 : : {
1280 : 0 : char *typname = NameStr(typeform->typname);
1281 : :
1282 : 0 : result = pstrdup(typname);
1283 : 0 : }
1284 : : else
1285 : 284 : result = format_type_be(typid);
1286 : :
1287 : 284 : ReleaseSysCache(typetup);
1288 : 284 : }
1289 : : else
1290 : : {
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 : : }
1295 : :
1296 : 284 : PG_RETURN_CSTRING(result);
1297 : 284 : }
1298 : :
1299 : : /*
1300 : : * regtyperecv - converts external binary format to regtype
1301 : : */
1302 : : Datum
1303 : 0 : regtyperecv(PG_FUNCTION_ARGS)
1304 : : {
1305 : : /* Exactly the same as oidrecv, so share code */
1306 : 0 : return oidrecv(fcinfo);
1307 : : }
1308 : :
1309 : : /*
1310 : : * regtypesend - converts regtype to binary format
1311 : : */
1312 : : Datum
1313 : 0 : regtypesend(PG_FUNCTION_ARGS)
1314 : : {
1315 : : /* Exactly the same as oidsend, so share code */
1316 : 0 : return oidsend(fcinfo);
1317 : : }
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 : 319 : regconfigin(PG_FUNCTION_ARGS)
1330 : : {
1331 : 319 : char *cfg_name_or_oid = PG_GETARG_CSTRING(0);
1332 : 319 : Node *escontext = fcinfo->context;
1333 : 319 : Oid result;
1334 : 319 : List *names;
1335 : :
1336 : : /* Handle "-" or numeric OID */
1337 [ + + ]: 319 : if (parseDashOrOid(cfg_name_or_oid, &result, escontext))
1338 : 1 : PG_RETURN_OID(result);
1339 : :
1340 : : /* The rest of this wouldn't work in bootstrap mode */
1341 [ + - ]: 318 : 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 : 318 : names = stringToQualifiedNameList(cfg_name_or_oid, escontext);
1349 [ + - ]: 318 : if (names == NIL)
1350 : 0 : PG_RETURN_NULL();
1351 : :
1352 : 318 : result = get_ts_config_oid(names, true);
1353 : :
1354 [ + + ]: 318 : if (!OidIsValid(result))
1355 [ - + ]: 1 : ereturn(escontext, (Datum) 0,
1356 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
1357 : : errmsg("text search configuration \"%s\" does not exist",
1358 : : NameListToString(names))));
1359 : :
1360 : 317 : PG_RETURN_OID(result);
1361 : 319 : }
1362 : :
1363 : : /*
1364 : : * regconfigout - converts tsconfig OID to "tsconfigname"
1365 : : */
1366 : : Datum
1367 : 0 : regconfigout(PG_FUNCTION_ARGS)
1368 : : {
1369 : 0 : Oid cfgid = PG_GETARG_OID(0);
1370 : 0 : char *result;
1371 : 0 : HeapTuple cfgtup;
1372 : :
1373 [ # # ]: 0 : if (cfgid == InvalidOid)
1374 : : {
1375 : 0 : result = pstrdup("-");
1376 : 0 : PG_RETURN_CSTRING(result);
1377 : : }
1378 : :
1379 : 0 : cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
1380 : :
1381 [ # # ]: 0 : if (HeapTupleIsValid(cfgtup))
1382 : : {
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 : : 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 : : else
1400 : : {
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 : : }
1405 : :
1406 : 0 : PG_RETURN_CSTRING(result);
1407 : 0 : }
1408 : :
1409 : : /*
1410 : : * regconfigrecv - converts external binary format to regconfig
1411 : : */
1412 : : Datum
1413 : 0 : regconfigrecv(PG_FUNCTION_ARGS)
1414 : : {
1415 : : /* Exactly the same as oidrecv, so share code */
1416 : 0 : return oidrecv(fcinfo);
1417 : : }
1418 : :
1419 : : /*
1420 : : * regconfigsend - converts regconfig to binary format
1421 : : */
1422 : : Datum
1423 : 0 : regconfigsend(PG_FUNCTION_ARGS)
1424 : : {
1425 : : /* Exactly the same as oidsend, so share code */
1426 : 0 : return oidsend(fcinfo);
1427 : : }
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 : 75 : regdictionaryin(PG_FUNCTION_ARGS)
1440 : : {
1441 : 75 : char *dict_name_or_oid = PG_GETARG_CSTRING(0);
1442 : 75 : Node *escontext = fcinfo->context;
1443 : 75 : Oid result;
1444 : 75 : List *names;
1445 : :
1446 : : /* Handle "-" or numeric OID */
1447 [ + + ]: 75 : if (parseDashOrOid(dict_name_or_oid, &result, escontext))
1448 : 1 : PG_RETURN_OID(result);
1449 : :
1450 : : /* The rest of this wouldn't work in bootstrap mode */
1451 [ + - ]: 74 : 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 : 74 : names = stringToQualifiedNameList(dict_name_or_oid, escontext);
1459 [ + - ]: 74 : if (names == NIL)
1460 : 0 : PG_RETURN_NULL();
1461 : :
1462 : 74 : result = get_ts_dict_oid(names, true);
1463 : :
1464 [ + + ]: 74 : if (!OidIsValid(result))
1465 [ - + ]: 1 : ereturn(escontext, (Datum) 0,
1466 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
1467 : : errmsg("text search dictionary \"%s\" does not exist",
1468 : : NameListToString(names))));
1469 : :
1470 : 73 : PG_RETURN_OID(result);
1471 : 75 : }
1472 : :
1473 : : /*
1474 : : * regdictionaryout - converts tsdictionary OID to "tsdictionaryname"
1475 : : */
1476 : : Datum
1477 : 34 : regdictionaryout(PG_FUNCTION_ARGS)
1478 : : {
1479 : 34 : Oid dictid = PG_GETARG_OID(0);
1480 : 34 : char *result;
1481 : 34 : HeapTuple dicttup;
1482 : :
1483 [ + - ]: 34 : if (dictid == InvalidOid)
1484 : : {
1485 : 0 : result = pstrdup("-");
1486 : 0 : PG_RETURN_CSTRING(result);
1487 : : }
1488 : :
1489 : 34 : dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
1490 : :
1491 [ + - ]: 34 : if (HeapTupleIsValid(dicttup))
1492 : : {
1493 : 34 : Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
1494 : 34 : char *dictname = NameStr(dictform->dictname);
1495 : 34 : char *nspname;
1496 : :
1497 : : /*
1498 : : * Would this dictionary be found by regdictionaryin? If not, qualify
1499 : : * it.
1500 : : */
1501 [ + - ]: 34 : if (TSDictionaryIsVisible(dictid))
1502 : 34 : nspname = NULL;
1503 : : else
1504 : 0 : nspname = get_namespace_name(dictform->dictnamespace);
1505 : :
1506 : 34 : result = quote_qualified_identifier(nspname, dictname);
1507 : :
1508 : 34 : ReleaseSysCache(dicttup);
1509 : 34 : }
1510 : : else
1511 : : {
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 : : }
1516 : :
1517 : 34 : PG_RETURN_CSTRING(result);
1518 : 34 : }
1519 : :
1520 : : /*
1521 : : * regdictionaryrecv - converts external binary format to regdictionary
1522 : : */
1523 : : Datum
1524 : 0 : regdictionaryrecv(PG_FUNCTION_ARGS)
1525 : : {
1526 : : /* Exactly the same as oidrecv, so share code */
1527 : 0 : return oidrecv(fcinfo);
1528 : : }
1529 : :
1530 : : /*
1531 : : * regdictionarysend - converts regdictionary to binary format
1532 : : */
1533 : : Datum
1534 : 0 : regdictionarysend(PG_FUNCTION_ARGS)
1535 : : {
1536 : : /* Exactly the same as oidsend, so share code */
1537 : 0 : return oidsend(fcinfo);
1538 : : }
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 : 34 : regrolein(PG_FUNCTION_ARGS)
1550 : : {
1551 : 34 : char *role_name_or_oid = PG_GETARG_CSTRING(0);
1552 : 34 : Node *escontext = fcinfo->context;
1553 : 34 : Oid result;
1554 : 34 : List *names;
1555 : :
1556 : : /* Handle "-" or numeric OID */
1557 [ + + ]: 34 : if (parseDashOrOid(role_name_or_oid, &result, escontext))
1558 : 2 : PG_RETURN_OID(result);
1559 : :
1560 : : /* The rest of this wouldn't work in bootstrap mode */
1561 [ + - ]: 32 : 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 : 32 : names = stringToQualifiedNameList(role_name_or_oid, escontext);
1566 [ + - ]: 32 : if (names == NIL)
1567 : 0 : PG_RETURN_NULL();
1568 : :
1569 [ + + ]: 32 : if (list_length(names) != 1)
1570 [ + + ]: 2 : ereturn(escontext, (Datum) 0,
1571 : : (errcode(ERRCODE_INVALID_NAME),
1572 : : errmsg("invalid name syntax")));
1573 : :
1574 : 30 : result = get_role_oid(strVal(linitial(names)), true);
1575 : :
1576 [ + + ]: 30 : if (!OidIsValid(result))
1577 [ - + ]: 5 : ereturn(escontext, (Datum) 0,
1578 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
1579 : : errmsg("role \"%s\" does not exist",
1580 : : strVal(linitial(names)))));
1581 : :
1582 : 25 : PG_RETURN_OID(result);
1583 : 34 : }
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 : 9 : to_regrole(PG_FUNCTION_ARGS)
1592 : : {
1593 : 9 : char *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1594 : 9 : Datum result;
1595 : 9 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1596 : :
1597 [ + + ]: 9 : if (!DirectInputFunctionCallSafe(regrolein, role_name,
1598 : : InvalidOid, -1,
1599 : : (Node *) &escontext,
1600 : : &result))
1601 : 6 : PG_RETURN_NULL();
1602 : 3 : PG_RETURN_DATUM(result);
1603 : 9 : }
1604 : :
1605 : : /*
1606 : : * regroleout - converts role OID to "role_name"
1607 : : */
1608 : : Datum
1609 : 14 : regroleout(PG_FUNCTION_ARGS)
1610 : : {
1611 : 14 : Oid roleoid = PG_GETARG_OID(0);
1612 : 14 : char *result;
1613 : :
1614 [ + - ]: 14 : if (roleoid == InvalidOid)
1615 : : {
1616 : 0 : result = pstrdup("-");
1617 : 0 : PG_RETURN_CSTRING(result);
1618 : : }
1619 : :
1620 : 14 : result = GetUserNameFromId(roleoid, true);
1621 : :
1622 [ + - ]: 14 : if (result)
1623 : : {
1624 : : /* pstrdup is not really necessary, but it avoids a compiler warning */
1625 : 14 : result = pstrdup(quote_identifier(result));
1626 : 14 : }
1627 : : else
1628 : : {
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 : : }
1633 : :
1634 : 14 : PG_RETURN_CSTRING(result);
1635 : 14 : }
1636 : :
1637 : : /*
1638 : : * regrolerecv - converts external binary format to regrole
1639 : : */
1640 : : Datum
1641 : 0 : regrolerecv(PG_FUNCTION_ARGS)
1642 : : {
1643 : : /* Exactly the same as oidrecv, so share code */
1644 : 0 : return oidrecv(fcinfo);
1645 : : }
1646 : :
1647 : : /*
1648 : : * regrolesend - converts regrole to binary format
1649 : : */
1650 : : Datum
1651 : 0 : regrolesend(PG_FUNCTION_ARGS)
1652 : : {
1653 : : /* Exactly the same as oidsend, so share code */
1654 : 0 : return oidsend(fcinfo);
1655 : : }
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 : 16 : regnamespacein(PG_FUNCTION_ARGS)
1667 : : {
1668 : 16 : char *nsp_name_or_oid = PG_GETARG_CSTRING(0);
1669 : 16 : Node *escontext = fcinfo->context;
1670 : 16 : Oid result;
1671 : 16 : List *names;
1672 : :
1673 : : /* Handle "-" or numeric OID */
1674 [ + + ]: 16 : if (parseDashOrOid(nsp_name_or_oid, &result, escontext))
1675 : 2 : PG_RETURN_OID(result);
1676 : :
1677 : : /* The rest of this wouldn't work in bootstrap mode */
1678 [ + - ]: 14 : 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 : 14 : names = stringToQualifiedNameList(nsp_name_or_oid, escontext);
1683 [ + - ]: 14 : if (names == NIL)
1684 : 0 : PG_RETURN_NULL();
1685 : :
1686 [ + + ]: 14 : if (list_length(names) != 1)
1687 [ - + ]: 1 : ereturn(escontext, (Datum) 0,
1688 : : (errcode(ERRCODE_INVALID_NAME),
1689 : : errmsg("invalid name syntax")));
1690 : :
1691 : 13 : result = get_namespace_oid(strVal(linitial(names)), true);
1692 : :
1693 [ + + ]: 13 : if (!OidIsValid(result))
1694 [ - + ]: 3 : ereturn(escontext, (Datum) 0,
1695 : : (errcode(ERRCODE_UNDEFINED_SCHEMA),
1696 : : errmsg("schema \"%s\" does not exist",
1697 : : strVal(linitial(names)))));
1698 : :
1699 : 10 : PG_RETURN_OID(result);
1700 : 16 : }
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 : 6 : to_regnamespace(PG_FUNCTION_ARGS)
1709 : : {
1710 : 6 : char *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1711 : 6 : Datum result;
1712 : 6 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1713 : :
1714 [ + + ]: 6 : if (!DirectInputFunctionCallSafe(regnamespacein, nsp_name,
1715 : : InvalidOid, -1,
1716 : : (Node *) &escontext,
1717 : : &result))
1718 : 3 : PG_RETURN_NULL();
1719 : 3 : PG_RETURN_DATUM(result);
1720 : 6 : }
1721 : :
1722 : : /*
1723 : : * regnamespaceout - converts namespace OID to "nsp_name"
1724 : : */
1725 : : Datum
1726 : 427 : regnamespaceout(PG_FUNCTION_ARGS)
1727 : : {
1728 : 427 : Oid nspid = PG_GETARG_OID(0);
1729 : 427 : char *result;
1730 : :
1731 [ + - ]: 427 : if (nspid == InvalidOid)
1732 : : {
1733 : 0 : result = pstrdup("-");
1734 : 0 : PG_RETURN_CSTRING(result);
1735 : : }
1736 : :
1737 : 427 : result = get_namespace_name(nspid);
1738 : :
1739 [ + - ]: 427 : if (result)
1740 : : {
1741 : : /* pstrdup is not really necessary, but it avoids a compiler warning */
1742 : 427 : result = pstrdup(quote_identifier(result));
1743 : 427 : }
1744 : : else
1745 : : {
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 : : }
1750 : :
1751 : 427 : PG_RETURN_CSTRING(result);
1752 : 427 : }
1753 : :
1754 : : /*
1755 : : * regnamespacerecv - converts external binary format to regnamespace
1756 : : */
1757 : : Datum
1758 : 0 : regnamespacerecv(PG_FUNCTION_ARGS)
1759 : : {
1760 : : /* Exactly the same as oidrecv, so share code */
1761 : 0 : return oidrecv(fcinfo);
1762 : : }
1763 : :
1764 : : /*
1765 : : * regnamespacesend - converts regnamespace to binary format
1766 : : */
1767 : : Datum
1768 : 0 : regnamespacesend(PG_FUNCTION_ARGS)
1769 : : {
1770 : : /* Exactly the same as oidsend, so share code */
1771 : 0 : return oidsend(fcinfo);
1772 : : }
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 : 12 : regdatabasein(PG_FUNCTION_ARGS)
1784 : : {
1785 : 12 : char *db_name_or_oid = PG_GETARG_CSTRING(0);
1786 : 12 : Node *escontext = fcinfo->context;
1787 : 12 : Oid result;
1788 : 12 : List *names;
1789 : :
1790 : : /* Handle "-" or numeric OID */
1791 [ + + ]: 12 : if (parseDashOrOid(db_name_or_oid, &result, escontext))
1792 : 2 : PG_RETURN_OID(result);
1793 : :
1794 : : /* The rest of this wouldn't work in bootstrap mode */
1795 [ + - ]: 10 : 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 : 10 : names = stringToQualifiedNameList(db_name_or_oid, escontext);
1800 [ + - ]: 10 : if (names == NIL)
1801 : 0 : PG_RETURN_NULL();
1802 : :
1803 [ + + ]: 10 : if (list_length(names) != 1)
1804 [ - + ]: 1 : ereturn(escontext, (Datum) 0,
1805 : : (errcode(ERRCODE_INVALID_NAME),
1806 : : errmsg("invalid name syntax")));
1807 : :
1808 : 9 : result = get_database_oid(strVal(linitial(names)), true);
1809 : :
1810 [ + + ]: 9 : if (!OidIsValid(result))
1811 [ - + ]: 3 : ereturn(escontext, (Datum) 0,
1812 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
1813 : : errmsg("database \"%s\" does not exist",
1814 : : strVal(linitial(names)))));
1815 : :
1816 : 6 : PG_RETURN_OID(result);
1817 : 12 : }
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 : 6 : to_regdatabase(PG_FUNCTION_ARGS)
1826 : : {
1827 : 6 : char *db_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
1828 : 6 : Datum result;
1829 : 6 : ErrorSaveContext escontext = {T_ErrorSaveContext};
1830 : :
1831 [ + + ]: 6 : if (!DirectInputFunctionCallSafe(regdatabasein, db_name,
1832 : : InvalidOid, -1,
1833 : : (Node *) &escontext,
1834 : : &result))
1835 : 3 : PG_RETURN_NULL();
1836 : 3 : PG_RETURN_DATUM(result);
1837 : 6 : }
1838 : :
1839 : : /*
1840 : : * regdatabaseout - converts database OID to database name
1841 : : */
1842 : : Datum
1843 : 4 : regdatabaseout(PG_FUNCTION_ARGS)
1844 : : {
1845 : 4 : Oid dboid = PG_GETARG_OID(0);
1846 : 4 : char *result;
1847 : :
1848 [ + - ]: 4 : if (dboid == InvalidOid)
1849 : : {
1850 : 0 : result = pstrdup("-");
1851 : 0 : PG_RETURN_CSTRING(result);
1852 : : }
1853 : :
1854 : 4 : result = get_database_name(dboid);
1855 : :
1856 [ + - ]: 4 : if (result)
1857 : : {
1858 : : /* pstrdup is not really necessary, but it avoids a compiler warning */
1859 : 4 : result = pstrdup(quote_identifier(result));
1860 : 4 : }
1861 : : else
1862 : : {
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 : : }
1867 : :
1868 : 4 : PG_RETURN_CSTRING(result);
1869 : 4 : }
1870 : :
1871 : : /*
1872 : : * regdatabaserecv - converts external binary format to regdatabase
1873 : : */
1874 : : Datum
1875 : 0 : regdatabaserecv(PG_FUNCTION_ARGS)
1876 : : {
1877 : : /* Exactly the same as oidrecv, so share code */
1878 : 0 : return oidrecv(fcinfo);
1879 : : }
1880 : :
1881 : : /*
1882 : : * regdatabasesend - converts regdatabase to binary format
1883 : : */
1884 : : Datum
1885 : 0 : regdatabasesend(PG_FUNCTION_ARGS)
1886 : : {
1887 : : /* Exactly the same as oidsend, so share code */
1888 : 0 : return oidsend(fcinfo);
1889 : : }
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 : 9 : text_regclass(PG_FUNCTION_ARGS)
1900 : : {
1901 : 9 : text *relname = PG_GETARG_TEXT_PP(0);
1902 : 9 : Oid result;
1903 : 9 : RangeVar *rv;
1904 : :
1905 : 9 : rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
1906 : :
1907 : : /* We might not even have permissions on this relation; don't lock it. */
1908 : 9 : result = RangeVarGetRelid(rv, NoLock, false);
1909 : :
1910 : 18 : PG_RETURN_OID(result);
1911 : 9 : }
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 : 2668 : stringToQualifiedNameList(const char *string, Node *escontext)
1923 : : {
1924 : 2668 : char *rawname;
1925 : 2668 : List *result = NIL;
1926 : 2668 : List *namelist;
1927 : 2668 : ListCell *l;
1928 : :
1929 : : /* We need a modifiable copy of the input string. */
1930 : 2668 : rawname = pstrdup(string);
1931 : :
1932 [ + - ]: 2668 : if (!SplitIdentifierString(rawname, '.', &namelist))
1933 [ # # ]: 0 : ereturn(escontext, NIL,
1934 : : (errcode(ERRCODE_INVALID_NAME),
1935 : : errmsg("invalid name syntax")));
1936 : :
1937 [ + - ]: 2668 : if (namelist == NIL)
1938 [ # # ]: 0 : ereturn(escontext, NIL,
1939 : : (errcode(ERRCODE_INVALID_NAME),
1940 : : errmsg("invalid name syntax")));
1941 : :
1942 [ + - + + : 6595 : foreach(l, namelist)
+ + ]
1943 : : {
1944 : 3927 : char *curname = (char *) lfirst(l);
1945 : :
1946 : 3927 : result = lappend(result, makeString(pstrdup(curname)));
1947 : 3927 : }
1948 : :
1949 : 2668 : pfree(rawname);
1950 : 2668 : list_free(namelist);
1951 : :
1952 : 2668 : return result;
1953 : 2668 : }
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 : 12304 : parseNumericOid(char *string, Oid *result, Node *escontext)
1969 : : {
1970 [ + + + + : 12304 : if (string[0] >= '0' && string[0] <= '9' &&
- + ]
1971 : 10426 : strspn(string, "0123456789") == strlen(string))
1972 : : {
1973 : 10426 : Datum oid_datum;
1974 : :
1975 : : /* We need not care here whether oidin() fails or not. */
1976 : 20852 : (void) DirectInputFunctionCallSafe(oidin, string,
1977 : : InvalidOid, -1,
1978 : 10426 : escontext,
1979 : : &oid_datum);
1980 : 10426 : *result = DatumGetObjectId(oid_datum);
1981 : 10426 : return true;
1982 : 10426 : }
1983 : :
1984 : : /* Prevent uninitialized-variable warnings from stupider compilers. */
1985 : 1878 : *result = InvalidOid;
1986 : 1878 : return false;
1987 : 12304 : }
1988 : :
1989 : : /*
1990 : : * As above, but also accept "-" as meaning 0 (InvalidOid).
1991 : : */
1992 : : static bool
1993 : 14235 : parseDashOrOid(char *string, Oid *result, Node *escontext)
1994 : : {
1995 : : /* '-' ? */
1996 [ + + ]: 14235 : if (strcmp(string, "-") == 0)
1997 : : {
1998 : 1955 : *result = InvalidOid;
1999 : 1955 : return true;
2000 : : }
2001 : :
2002 : : /* Numeric OID? */
2003 : 12280 : return parseNumericOid(string, result, escontext);
2004 : 14235 : }
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 : 58 : parseNameAndArgTypes(const char *string, bool allowNone, List **names,
2021 : : int *nargs, Oid *argtypes,
2022 : : Node *escontext)
2023 : : {
2024 : 58 : char *rawname;
2025 : 58 : char *ptr;
2026 : 58 : char *ptr2;
2027 : 58 : char *typename;
2028 : 58 : bool in_quote;
2029 : 58 : bool had_comma;
2030 : 58 : int paren_count;
2031 : 58 : Oid typeid;
2032 : 58 : int32 typmod;
2033 : :
2034 : : /* We need a modifiable copy of the input string. */
2035 : 58 : rawname = pstrdup(string);
2036 : :
2037 : : /* Scan to find the expected left paren; mustn't be quoted */
2038 : 58 : in_quote = false;
2039 [ + + ]: 801 : for (ptr = rawname; *ptr; ptr++)
2040 : : {
2041 [ - + ]: 800 : if (*ptr == '"')
2042 : 0 : in_quote = !in_quote;
2043 [ + + - + ]: 800 : else if (*ptr == '(' && !in_quote)
2044 : 57 : break;
2045 : 743 : }
2046 [ + + ]: 58 : if (*ptr == '\0')
2047 [ - + ]: 1 : ereturn(escontext, false,
2048 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2049 : : errmsg("expected a left parenthesis")));
2050 : :
2051 : : /* Separate the name and parse it into a list */
2052 : 57 : *ptr++ = '\0';
2053 : 57 : *names = stringToQualifiedNameList(rawname, escontext);
2054 [ + - ]: 57 : if (*names == NIL)
2055 : 0 : return false;
2056 : :
2057 : : /* Check for the trailing right parenthesis and remove it */
2058 : 57 : ptr2 = ptr + strlen(ptr);
2059 [ + + ]: 57 : while (--ptr2 > ptr)
2060 : : {
2061 [ + - ]: 43 : if (!scanner_isspace(*ptr2))
2062 : 43 : break;
2063 : : }
2064 [ + + ]: 57 : if (*ptr2 != ')')
2065 [ - + ]: 1 : ereturn(escontext, false,
2066 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2067 : : errmsg("expected a right parenthesis")));
2068 : :
2069 : 56 : *ptr2 = '\0';
2070 : :
2071 : : /* Separate the remaining string into comma-separated type names */
2072 : 56 : *nargs = 0;
2073 : 56 : had_comma = false;
2074 : :
2075 : 111 : for (;;)
2076 : : {
2077 : : /* allow leading whitespace */
2078 [ - + ]: 111 : while (scanner_isspace(*ptr))
2079 : 0 : ptr++;
2080 [ + + ]: 111 : if (*ptr == '\0')
2081 : : {
2082 : : /* End of string. Okay unless we had a comma before. */
2083 [ + - ]: 56 : if (had_comma)
2084 [ # # ]: 0 : ereturn(escontext, false,
2085 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2086 : : errmsg("expected a type name")));
2087 : 56 : break;
2088 : : }
2089 : 55 : typename = ptr;
2090 : : /* Find end of type name --- end of string or comma */
2091 : : /* ... but not a quoted or parenthesized comma */
2092 : 55 : in_quote = false;
2093 : 55 : paren_count = 0;
2094 [ + + ]: 299 : for (; *ptr; ptr++)
2095 : : {
2096 [ - + ]: 257 : if (*ptr == '"')
2097 : 0 : in_quote = !in_quote;
2098 [ + + + - : 257 : else if (*ptr == ',' && !in_quote && paren_count == 0)
- + ]
2099 : 13 : break;
2100 [ - + ]: 244 : else if (!in_quote)
2101 : : {
2102 [ - - + ]: 244 : switch (*ptr)
2103 : : {
2104 : : case '(':
2105 : : case '[':
2106 : 0 : paren_count++;
2107 : 0 : break;
2108 : : case ')':
2109 : : case ']':
2110 : 0 : paren_count--;
2111 : 0 : break;
2112 : : }
2113 : 244 : }
2114 : 244 : }
2115 [ + - + - ]: 55 : if (in_quote || paren_count != 0)
2116 [ # # ]: 0 : ereturn(escontext, false,
2117 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
2118 : : errmsg("improper type name")));
2119 : :
2120 : 55 : ptr2 = ptr;
2121 [ + + ]: 55 : if (*ptr == ',')
2122 : : {
2123 : 13 : had_comma = true;
2124 : 13 : *ptr++ = '\0';
2125 : 13 : }
2126 : : else
2127 : : {
2128 : 42 : had_comma = false;
2129 [ - + ]: 42 : Assert(*ptr == '\0');
2130 : : }
2131 : : /* Lop off trailing whitespace */
2132 [ - + ]: 55 : while (--ptr2 >= typename)
2133 : : {
2134 [ + - ]: 55 : if (!scanner_isspace(*ptr2))
2135 : 55 : break;
2136 : 0 : *ptr2 = '\0';
2137 : : }
2138 : :
2139 [ + + + - ]: 55 : if (allowNone && pg_strcasecmp(typename, "none") == 0)
2140 : : {
2141 : : /* Special case for NONE */
2142 : 0 : typeid = InvalidOid;
2143 : 0 : typmod = -1;
2144 : 0 : }
2145 : : else
2146 : : {
2147 : : /* Use full parser to resolve the type name */
2148 [ + - ]: 55 : if (!parseTypeString(typename, &typeid, &typmod, escontext))
2149 : 0 : return false;
2150 : : }
2151 [ - + ]: 55 : if (*nargs >= FUNC_MAX_ARGS)
2152 [ # # ]: 0 : ereturn(escontext, false,
2153 : : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2154 : : errmsg("too many arguments")));
2155 : :
2156 : 55 : argtypes[*nargs] = typeid;
2157 : 55 : (*nargs)++;
2158 : : }
2159 : :
2160 : 56 : pfree(rawname);
2161 : :
2162 : 56 : return true;
2163 : 58 : }
|