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