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