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