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