Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * parse_type.c
4 : * handle type operations for parser
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/parser/parse_type.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "access/htup_details.h"
18 : #include "catalog/namespace.h"
19 : #include "catalog/pg_type.h"
20 : #include "lib/stringinfo.h"
21 : #include "nodes/makefuncs.h"
22 : #include "parser/parse_type.h"
23 : #include "parser/parser.h"
24 : #include "utils/array.h"
25 : #include "utils/builtins.h"
26 : #include "utils/lsyscache.h"
27 : #include "utils/syscache.h"
28 :
29 : static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
30 : Type typ);
31 :
32 :
33 : /*
34 : * LookupTypeName
35 : * Wrapper for typical case.
36 : */
37 : Type
1343 noah 38 CBC 1002657 : LookupTypeName(ParseState *pstate, const TypeName *typeName,
39 : int32 *typmod_p, bool missing_ok)
40 : {
41 1002657 : return LookupTypeNameExtended(pstate,
42 : typeName, typmod_p, true, missing_ok);
43 : }
44 :
45 : /*
46 : * LookupTypeNameExtended
47 : * Given a TypeName object, lookup the pg_type syscache entry of the type.
48 : * Returns NULL if no such type can be found. If the type is found,
49 : * the typmod value represented in the TypeName struct is computed and
50 : * stored into *typmod_p.
51 : *
52 : * NB: on success, the caller must ReleaseSysCache the type tuple when done
53 : * with it.
54 : *
55 : * NB: direct callers of this function MUST check typisdefined before assuming
56 : * that the type is fully valid. Most code should go through typenameType
57 : * or typenameTypeId instead.
58 : *
59 : * typmod_p can be passed as NULL if the caller does not care to know the
60 : * typmod value, but the typmod decoration (if any) will be validated anyway,
61 : * except in the case where the type is not found. Note that if the type is
62 : * found but is a shell, and there is typmod decoration, an error will be
63 : * thrown --- this is intentional.
64 : *
65 : * If temp_ok is false, ignore types in the temporary namespace. Pass false
66 : * when the caller will decide, using goodness of fit criteria, whether the
67 : * typeName is actually a type or something else. If typeName always denotes
68 : * a type (or denotes nothing), pass true.
69 : *
70 : * pstate is only used for error location info, and may be NULL.
71 : */
72 : Type
73 1042170 : LookupTypeNameExtended(ParseState *pstate,
74 : const TypeName *typeName, int32 *typmod_p,
75 : bool temp_ok, bool missing_ok)
76 : {
77 : Oid typoid;
78 : HeapTuple tup;
79 : int32 typmod;
80 :
5015 peter_e 81 1042170 : if (typeName->names == NIL)
82 : {
83 : /* We have the OID already if it's an internally generated TypeName */
84 454328 : typoid = typeName->typeOid;
85 : }
86 587842 : else if (typeName->pct_type)
87 : {
88 : /* Handle %TYPE reference to type of an existing field */
89 12 : RangeVar *rel = makeRangeVar(NULL, NULL, typeName->location);
7681 tgl 90 12 : char *field = NULL;
91 : Oid relid;
92 : AttrNumber attnum;
93 :
94 : /* deconstruct the name list */
5015 peter_e 95 12 : switch (list_length(typeName->names))
96 : {
7681 tgl 97 UBC 0 : case 1:
7204 98 0 : ereport(ERROR,
99 : (errcode(ERRCODE_SYNTAX_ERROR),
100 : errmsg("improper %%TYPE reference (too few dotted names): %s",
101 : NameListToString(typeName->names)),
102 : parser_errposition(pstate, typeName->location)));
103 : break;
7681 tgl 104 CBC 12 : case 2:
5015 peter_e 105 12 : rel->relname = strVal(linitial(typeName->names));
106 12 : field = strVal(lsecond(typeName->names));
7681 tgl 107 12 : break;
7681 tgl 108 UBC 0 : case 3:
5015 peter_e 109 0 : rel->schemaname = strVal(linitial(typeName->names));
110 0 : rel->relname = strVal(lsecond(typeName->names));
111 0 : field = strVal(lthird(typeName->names));
7681 tgl 112 0 : break;
113 0 : case 4:
5015 peter_e 114 0 : rel->catalogname = strVal(linitial(typeName->names));
115 0 : rel->schemaname = strVal(lsecond(typeName->names));
116 0 : rel->relname = strVal(lthird(typeName->names));
117 0 : field = strVal(lfourth(typeName->names));
7681 tgl 118 0 : break;
119 0 : default:
7204 120 0 : ereport(ERROR,
121 : (errcode(ERRCODE_SYNTAX_ERROR),
122 : errmsg("improper %%TYPE reference (too many dotted names): %s",
123 : NameListToString(typeName->names)),
124 : parser_errposition(pstate, typeName->location)));
125 : break;
126 : }
127 :
128 : /*
129 : * Look up the field.
130 : *
131 : * XXX: As no lock is taken here, this might fail in the presence of
132 : * concurrent DDL. But taking a lock would carry a performance
133 : * penalty and would also require a permissions check.
134 : */
3363 alvherre 135 CBC 12 : relid = RangeVarGetRelid(rel, NoLock, missing_ok);
7681 tgl 136 12 : attnum = get_attnum(relid, field);
137 12 : if (attnum == InvalidAttrNumber)
138 : {
3363 alvherre 139 UBC 0 : if (missing_ok)
140 0 : typoid = InvalidOid;
141 : else
142 0 : ereport(ERROR,
143 : (errcode(ERRCODE_UNDEFINED_COLUMN),
144 : errmsg("column \"%s\" of relation \"%s\" does not exist",
145 : field, rel->relname),
146 : parser_errposition(pstate, typeName->location)));
147 : }
148 : else
149 : {
3363 alvherre 150 CBC 12 : typoid = get_atttype(relid, attnum);
151 :
152 : /* this construct should never have an array indicator */
153 12 : Assert(typeName->arrayBounds == NIL);
154 :
155 : /* emit nuisance notice (intentionally not errposition'd) */
156 12 : ereport(NOTICE,
157 : (errmsg("type reference %s converted to %s",
158 : TypeNameToString(typeName),
159 : format_type_be(typoid))));
160 : }
161 : }
162 : else
163 : {
164 : /* Normal reference to a type name */
165 : char *schemaname;
166 : char *typname;
167 :
168 : /* deconstruct the name list */
5015 peter_e 169 587830 : DeconstructQualifiedName(typeName->names, &schemaname, &typname);
170 :
7681 tgl 171 587824 : if (schemaname)
172 : {
173 : /* Look in specific schema only */
174 : Oid namespaceId;
175 : ParseCallbackState pcbstate;
176 :
2944 alvherre 177 137075 : setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
178 :
3363 179 137075 : namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
180 137072 : if (OidIsValid(namespaceId))
1601 andres 181 137024 : typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
182 : PointerGetDatum(typname),
183 : ObjectIdGetDatum(namespaceId));
184 : else
3363 alvherre 185 48 : typoid = InvalidOid;
186 :
2944 187 137072 : cancel_parser_errposition_callback(&pcbstate);
188 : }
189 : else
190 : {
191 : /* Unqualified type name, so search the search path */
1343 noah 192 450749 : typoid = TypenameGetTypidExtended(typname, temp_ok);
193 : }
194 :
195 : /* If an array reference, return the array type instead */
5015 peter_e 196 587821 : if (typeName->arrayBounds != NIL)
5628 tgl 197 10055 : typoid = get_array_type(typoid);
198 : }
199 :
200 1042161 : if (!OidIsValid(typoid))
201 : {
202 39388 : if (typmod_p)
203 19 : *typmod_p = -1;
204 39388 : return NULL;
205 : }
206 :
4802 rhaas 207 1002773 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
5628 tgl 208 1002773 : if (!HeapTupleIsValid(tup)) /* should not happen */
5628 tgl 209 UBC 0 : elog(ERROR, "cache lookup failed for type %u", typoid);
210 :
5015 peter_e 211 CBC 1002773 : typmod = typenameTypeMod(pstate, typeName, (Type) tup);
212 :
5628 tgl 213 1002767 : if (typmod_p)
214 809052 : *typmod_p = typmod;
215 :
216 1002767 : return (Type) tup;
217 : }
218 :
219 : /*
220 : * LookupTypeNameOid
221 : * Given a TypeName object, lookup the pg_type syscache entry of the type.
222 : * Returns InvalidOid if no such type can be found. If the type is found,
223 : * return its Oid.
224 : *
225 : * NB: direct callers of this function need to be aware that the type OID
226 : * returned may correspond to a shell type. Most code should go through
227 : * typenameTypeId instead.
228 : *
229 : * pstate is only used for error location info, and may be NULL.
230 : */
231 : Oid
3363 alvherre 232 26815 : LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
233 : {
234 : Oid typoid;
235 : Type tup;
236 :
237 26815 : tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
238 26815 : if (tup == NULL)
239 : {
240 90 : if (!missing_ok)
241 16 : ereport(ERROR,
242 : (errcode(ERRCODE_UNDEFINED_OBJECT),
243 : errmsg("type \"%s\" does not exist",
244 : TypeNameToString(typeName)),
245 : parser_errposition(pstate, typeName->location)));
246 :
247 74 : return InvalidOid;
248 : }
249 :
1601 andres 250 26725 : typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
3363 alvherre 251 26725 : ReleaseSysCache(tup);
252 :
253 26725 : return typoid;
254 : }
255 :
256 : /*
257 : * typenameType - given a TypeName, return a Type structure and typmod
258 : *
259 : * This is equivalent to LookupTypeName, except that this will report
260 : * a suitable error message if the type cannot be found or is not defined.
261 : * Callers of this can therefore assume the result is a fully valid type.
262 : */
263 : Type
4414 tgl 264 847159 : typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
265 : {
266 : Type tup;
267 :
3363 alvherre 268 847159 : tup = LookupTypeName(pstate, typeName, typmod_p, false);
5628 tgl 269 847156 : if (tup == NULL)
7204 270 16 : ereport(ERROR,
271 : (errcode(ERRCODE_UNDEFINED_OBJECT),
272 : errmsg("type \"%s\" does not exist",
273 : TypeNameToString(typeName)),
274 : parser_errposition(pstate, typeName->location)));
5628 275 847140 : if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
7204 276 3 : ereport(ERROR,
277 : (errcode(ERRCODE_UNDEFINED_OBJECT),
278 : errmsg("type \"%s\" is only a shell",
279 : TypeNameToString(typeName)),
280 : parser_errposition(pstate, typeName->location)));
5628 281 847137 : return tup;
282 : }
283 :
284 : /*
285 : * typenameTypeId - given a TypeName, return the type's OID
286 : *
287 : * This is similar to typenameType, but we only hand back the type OID
288 : * not the syscache entry.
289 : */
290 : Oid
4549 peter_e 291 4801 : typenameTypeId(ParseState *pstate, const TypeName *typeName)
292 : {
293 : Oid typoid;
294 : Type tup;
295 :
4414 tgl 296 4801 : tup = typenameType(pstate, typeName, NULL);
1601 andres 297 4794 : typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
5628 tgl 298 4794 : ReleaseSysCache(tup);
299 :
7681 300 4794 : return typoid;
301 : }
302 :
303 : /*
304 : * typenameTypeIdAndMod - given a TypeName, return the type's OID and typmod
305 : *
306 : * This is equivalent to typenameType, but we only hand back the type OID
307 : * and typmod, not the syscache entry.
308 : */
309 : void
4549 peter_e 310 804028 : typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
311 : Oid *typeid_p, int32 *typmod_p)
312 : {
313 : Type tup;
314 :
4414 tgl 315 804028 : tup = typenameType(pstate, typeName, typmod_p);
1601 andres 316 804026 : *typeid_p = ((Form_pg_type) GETSTRUCT(tup))->oid;
4549 peter_e 317 804026 : ReleaseSysCache(tup);
318 804026 : }
319 :
320 : /*
321 : * typenameTypeMod - given a TypeName, return the internal typmod value
322 : *
323 : * This will throw an error if the TypeName includes type modifiers that are
324 : * illegal for the data type.
325 : *
326 : * The actual type OID represented by the TypeName must already have been
327 : * looked up, and is passed as "typ".
328 : *
329 : * pstate is only used for error location info, and may be NULL.
330 : */
331 : static int32
5015 332 1002773 : typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
333 : {
334 : int32 result;
335 : Oid typmodin;
336 : Datum *datums;
337 : int n;
338 : ListCell *l;
339 : ArrayType *arrtypmod;
340 : ParseCallbackState pcbstate;
341 :
342 : /* Return prespecified typmod if no typmod expressions */
343 1002773 : if (typeName->typmods == NIL)
344 998395 : return typeName->typemod;
345 :
346 : /*
347 : * Else, type had better accept typmods. We give a special error message
348 : * for the shell-type case, since a shell couldn't possibly have a
349 : * typmodin function.
350 : */
5628 tgl 351 4378 : if (!((Form_pg_type) GETSTRUCT(typ))->typisdefined)
5628 tgl 352 UBC 0 : ereport(ERROR,
353 : (errcode(ERRCODE_SYNTAX_ERROR),
354 : errmsg("type modifier cannot be specified for shell type \"%s\"",
355 : TypeNameToString(typeName)),
356 : parser_errposition(pstate, typeName->location)));
357 :
5628 tgl 358 CBC 4378 : typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
359 :
5944 360 4378 : if (typmodin == InvalidOid)
5944 tgl 361 UBC 0 : ereport(ERROR,
362 : (errcode(ERRCODE_SYNTAX_ERROR),
363 : errmsg("type modifier is not allowed for type \"%s\"",
364 : TypeNameToString(typeName)),
365 : parser_errposition(pstate, typeName->location)));
366 :
367 : /*
368 : * Convert the list of raw-grammar-output expressions to a cstring array.
369 : * Currently, we allow simple numeric constants, string literals, and
370 : * identifiers; possibly this list could be extended.
371 : */
5015 peter_e 372 CBC 4378 : datums = (Datum *) palloc(list_length(typeName->typmods) * sizeof(Datum));
5944 tgl 373 4378 : n = 0;
5015 peter_e 374 9713 : foreach(l, typeName->typmods)
375 : {
5624 bruce 376 5335 : Node *tm = (Node *) lfirst(l);
377 5335 : char *cstr = NULL;
378 :
5777 tgl 379 5335 : if (IsA(tm, A_Const))
380 : {
5624 bruce 381 5335 : A_Const *ac = (A_Const *) tm;
382 :
5777 tgl 383 5335 : if (IsA(&ac->val, Integer))
384 : {
450 peter 385 5335 : cstr = psprintf("%ld", (long) intVal(&ac->val));
386 : }
577 peter 387 UBC 0 : else if (IsA(&ac->val, Float))
388 : {
389 : /* we can just use the string representation directly. */
450 390 0 : cstr = ac->val.fval.fval;
391 : }
577 392 0 : else if (IsA(&ac->val, String))
393 : {
394 : /* we can just use the string representation directly. */
450 395 0 : cstr = strVal(&ac->val);
396 : }
397 : }
5777 tgl 398 0 : else if (IsA(tm, ColumnRef))
399 : {
5624 bruce 400 0 : ColumnRef *cr = (ColumnRef *) tm;
401 :
5335 tgl 402 0 : if (list_length(cr->fields) == 1 &&
403 0 : IsA(linitial(cr->fields), String))
5777 404 0 : cstr = strVal(linitial(cr->fields));
405 : }
5777 tgl 406 CBC 5335 : if (!cstr)
5944 tgl 407 UBC 0 : ereport(ERROR,
408 : (errcode(ERRCODE_SYNTAX_ERROR),
409 : errmsg("type modifiers must be simple constants or identifiers"),
410 : parser_errposition(pstate, typeName->location)));
5777 tgl 411 CBC 5335 : datums[n++] = CStringGetDatum(cstr);
412 : }
413 :
282 peter 414 GNC 4378 : arrtypmod = construct_array_builtin(datums, n, CSTRINGOID);
5944 tgl 415 ECB :
416 : /* arrange to report location if type's typmodin function fails */
5015 peter_e 417 CBC 4378 : setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
418 :
5944 tgl 419 GIC 4378 : result = DatumGetInt32(OidFunctionCall1(typmodin,
5944 tgl 420 ECB : PointerGetDatum(arrtypmod)));
421 :
5333 tgl 422 CBC 4372 : cancel_parser_errposition_callback(&pcbstate);
5333 tgl 423 ECB :
5944 tgl 424 GIC 4372 : pfree(datums);
5944 tgl 425 CBC 4372 : pfree(arrtypmod);
426 :
5944 tgl 427 GIC 4372 : return result;
428 : }
429 :
430 : /*
431 : * appendTypeNameToBuffer
432 : * Append a string representing the name of a TypeName to a StringInfo.
433 : * This is the shared guts of TypeNameToString and TypeNameListToString.
434 : *
435 : * NB: this must work on TypeNames that do not describe any actual type;
436 : * it is mostly used for reporting lookup errors.
7681 tgl 437 ECB : */
438 : static void
5015 peter_e 439 CBC 14113 : appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
440 : {
5015 peter_e 441 GIC 14113 : if (typeName->names != NIL)
442 : {
443 : /* Emit possibly-qualified name as-is */
5628 tgl 444 ECB : ListCell *l;
445 :
5015 peter_e 446 CBC 28328 : foreach(l, typeName->names)
5628 tgl 447 ECB : {
5015 peter_e 448 CBC 14215 : if (l != list_head(typeName->names))
5628 tgl 449 GIC 102 : appendStringInfoChar(string, '.');
450 14215 : appendStringInfoString(string, strVal(lfirst(l)));
451 : }
452 : }
453 : else
5628 tgl 454 EUB : {
455 : /* Look up internally-specified type */
5015 peter_e 456 UIC 0 : appendStringInfoString(string, format_type_be(typeName->typeOid));
457 : }
458 :
459 : /*
460 : * Add decoration as needed, but only for fields considered by
5628 tgl 461 ECB : * LookupTypeName
462 : */
5015 peter_e 463 GIC 14113 : if (typeName->pct_type)
5628 tgl 464 CBC 12 : appendStringInfoString(string, "%TYPE");
5628 tgl 465 ECB :
5015 peter_e 466 CBC 14113 : if (typeName->arrayBounds != NIL)
5628 tgl 467 GIC 3 : appendStringInfoString(string, "[]");
468 14113 : }
469 :
470 : /*
471 : * TypeNameToString
472 : * Produce a string representing the name of a TypeName.
473 : *
474 : * NB: this must work on TypeNames that do not describe any actual type;
475 : * it is mostly used for reporting lookup errors.
5628 tgl 476 ECB : */
477 : char *
5015 peter_e 478 GIC 14101 : TypeNameToString(const TypeName *typeName)
479 : {
5628 tgl 480 ECB : StringInfoData string;
481 :
5628 tgl 482 CBC 14101 : initStringInfo(&string);
5015 peter_e 483 GIC 14101 : appendTypeNameToBuffer(typeName, &string);
5628 tgl 484 14101 : return string.data;
485 : }
486 :
487 : /*
488 : * TypeNameListToString
489 : * Produce a string representing the name(s) of a List of TypeNames
5628 tgl 490 ECB : */
491 : char *
5628 tgl 492 GIC 20 : TypeNameListToString(List *typenames)
493 : {
494 : StringInfoData string;
5628 tgl 495 ECB : ListCell *l;
496 :
5628 tgl 497 GIC 20 : initStringInfo(&string);
5628 tgl 498 CBC 32 : foreach(l, typenames)
499 : {
2190 500 12 : TypeName *typeName = lfirst_node(TypeName, l);
5628 tgl 501 ECB :
5628 tgl 502 CBC 12 : if (l != list_head(typenames))
5628 tgl 503 GIC 6 : appendStringInfoChar(&string, ',');
5015 peter_e 504 CBC 12 : appendTypeNameToBuffer(typeName, &string);
505 : }
5628 tgl 506 GIC 20 : return string.data;
507 : }
508 :
509 : /*
510 : * LookupCollation
511 : *
512 : * Look up collation by name, return OID, with support for error location.
4414 tgl 513 ECB : */
514 : Oid
4414 tgl 515 GIC 4115 : LookupCollation(ParseState *pstate, List *collnames, int location)
516 : {
517 : Oid colloid;
4414 tgl 518 ECB : ParseCallbackState pcbstate;
519 :
4414 tgl 520 GIC 4115 : if (pstate)
4414 tgl 521 CBC 3889 : setup_parser_errposition_callback(&pcbstate, pstate, location);
522 :
523 4115 : colloid = get_collation_oid(collnames, false);
4414 tgl 524 ECB :
4414 tgl 525 GIC 4103 : if (pstate)
4414 tgl 526 CBC 3877 : cancel_parser_errposition_callback(&pcbstate);
527 :
4414 tgl 528 GIC 4103 : return colloid;
529 : }
530 :
531 : /*
532 : * GetColumnDefCollation
533 : *
534 : * Get the collation to be used for a column being defined, given the
535 : * ColumnDef node and the previously-determined column type OID.
536 : *
537 : * pstate is only used for error location purposes, and can be NULL.
4414 tgl 538 ECB : */
539 : Oid
4414 tgl 540 GIC 490390 : GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
4414 tgl 541 ECB : {
542 : Oid result;
4414 tgl 543 GIC 490390 : Oid typcollation = get_typcollation(typeOid);
3426 tgl 544 CBC 490390 : int location = coldef->location;
545 :
4414 tgl 546 GIC 490390 : if (coldef->collClause)
4414 tgl 547 ECB : {
548 : /* We have a raw COLLATE clause, so look up the collation */
4414 tgl 549 GIC 226 : location = coldef->collClause->location;
4412 550 226 : result = LookupCollation(pstate, coldef->collClause->collname,
4414 tgl 551 ECB : location);
552 : }
4414 tgl 553 GIC 490164 : else if (OidIsValid(coldef->collOid))
4414 tgl 554 ECB : {
555 : /* Precooked collation spec, use that */
4414 tgl 556 GIC 255139 : result = coldef->collOid;
557 : }
558 : else
4414 tgl 559 ECB : {
560 : /* Use the type's default collation if any */
4414 tgl 561 GIC 235025 : result = typcollation;
562 : }
4414 tgl 563 ECB :
4414 tgl 564 EUB : /* Complain if COLLATE is applied to an uncollatable type */
4414 tgl 565 GIC 490390 : if (OidIsValid(result) && !OidIsValid(typcollation))
4414 tgl 566 UIC 0 : ereport(ERROR,
567 : (errcode(ERRCODE_DATATYPE_MISMATCH),
568 : errmsg("collations are not supported by type %s",
569 : format_type_be(typeOid)),
4414 tgl 570 ECB : parser_errposition(pstate, location)));
571 :
4414 tgl 572 GIC 490390 : return result;
573 : }
574 :
575 : /* return a Type structure, given a type id */
8179 tgl 576 ECB : /* NB: caller must ReleaseSysCache the type tuple when done with it */
577 : Type
9266 bruce 578 GIC 622937 : typeidType(Oid id)
579 : {
9266 bruce 580 ECB : HeapTuple tup;
581 :
4802 rhaas 582 GBC 622937 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(id));
8179 tgl 583 CBC 622937 : if (!HeapTupleIsValid(tup))
7204 tgl 584 UIC 0 : elog(ERROR, "cache lookup failed for type %u", id);
8986 bruce 585 GIC 622937 : return (Type) tup;
586 : }
587 :
8179 tgl 588 ECB : /* given type (as type struct), return the type OID */
589 : Oid
9266 bruce 590 CBC 127364 : typeTypeId(Type tp)
9266 bruce 591 EUB : {
7204 tgl 592 CBC 127364 : if (tp == NULL) /* probably useless */
9225 bruce 593 UIC 0 : elog(ERROR, "typeTypeId() called with NULL type struct");
1601 andres 594 GIC 127364 : return ((Form_pg_type) GETSTRUCT(tp))->oid;
595 : }
596 :
9266 bruce 597 ECB : /* given type (as type struct), return the length of type */
598 : int16
9266 bruce 599 GIC 596911 : typeLen(Type t)
600 : {
8986 bruce 601 ECB : Form_pg_type typ;
9266 602 :
8986 bruce 603 GIC 596911 : typ = (Form_pg_type) GETSTRUCT(t);
604 596911 : return typ->typlen;
605 : }
606 :
4384 tgl 607 ECB : /* given type (as type struct), return its 'byval' attribute */
608 : bool
9266 bruce 609 GIC 596911 : typeByVal(Type t)
610 : {
8986 bruce 611 ECB : Form_pg_type typ;
9266 612 :
8986 bruce 613 GIC 596911 : typ = (Form_pg_type) GETSTRUCT(t);
614 596911 : return typ->typbyval;
615 : }
616 :
4384 tgl 617 EUB : /* given type (as type struct), return the type's name */
618 : char *
9266 bruce 619 UIC 0 : typeTypeName(Type t)
620 : {
8986 bruce 621 EUB : Form_pg_type typ;
622 :
8986 bruce 623 UBC 0 : typ = (Form_pg_type) GETSTRUCT(t);
624 : /* pstrdup here because result may need to outlive the syscache entry */
8342 tgl 625 UIC 0 : return pstrdup(NameStr(typ->typname));
626 : }
627 :
4384 tgl 628 ECB : /* given type (as type struct), return its 'typrelid' attribute */
629 : Oid
8179 tgl 630 GIC 336 : typeTypeRelid(Type typ)
631 : {
8179 tgl 632 ECB : Form_pg_type typtup;
633 :
8179 tgl 634 GIC 336 : typtup = (Form_pg_type) GETSTRUCT(typ);
635 336 : return typtup->typrelid;
636 : }
637 :
4384 tgl 638 ECB : /* given type (as type struct), return its 'typcollation' attribute */
639 : Oid
4384 tgl 640 GIC 596911 : typeTypeCollation(Type typ)
641 : {
4384 tgl 642 ECB : Form_pg_type typtup;
643 :
4384 tgl 644 GIC 596911 : typtup = (Form_pg_type) GETSTRUCT(typ);
645 596911 : return typtup->typcollation;
646 : }
647 :
648 : /*
649 : * Given a type structure and a string, returns the internal representation
650 : * of that string. The "string" can be NULL to perform conversion of a NULL
651 : * (which might result in failure, if the input function rejects NULLs).
6881 tgl 652 ECB : */
653 : Datum
8648 tgl 654 CBC 596911 : stringTypeDatum(Type tp, char *string, int32 atttypmod)
9266 bruce 655 ECB : {
5476 tgl 656 CBC 596911 : Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
5476 tgl 657 GIC 596911 : Oid typinput = typform->typinput;
5476 tgl 658 CBC 596911 : Oid typioparam = getTypeIOParam(tp);
659 :
2635 tgl 660 GIC 596911 : return OidInputFunctionCall(typinput, string, typioparam, atttypmod);
661 : }
662 :
663 : /*
664 : * Given a typeid, return the type's typrelid (associated relation), if any.
665 : * Returns InvalidOid if type is not a composite type.
1991 tgl 666 ECB : */
667 : Oid
9266 bruce 668 GIC 6369 : typeidTypeRelid(Oid type_id)
669 : {
670 : HeapTuple typeTuple;
671 : Form_pg_type type;
8179 tgl 672 ECB : Oid result;
9266 bruce 673 :
4802 rhaas 674 GBC 6369 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
9266 bruce 675 CBC 6369 : if (!HeapTupleIsValid(typeTuple))
7204 tgl 676 LBC 0 : elog(ERROR, "cache lookup failed for type %u", type_id);
8986 bruce 677 CBC 6369 : type = (Form_pg_type) GETSTRUCT(typeTuple);
8179 tgl 678 6369 : result = type->typrelid;
8179 tgl 679 GIC 6369 : ReleaseSysCache(typeTuple);
1991 680 6369 : return result;
681 : }
682 :
683 : /*
684 : * Given a typeid, return the type's typrelid (associated relation), if any.
685 : * Returns InvalidOid if type is not a composite type or a domain over one.
686 : * This is the same as typeidTypeRelid(getBaseType(type_id)), but faster.
1991 tgl 687 ECB : */
688 : Oid
1991 tgl 689 GIC 1387112 : typeOrDomainTypeRelid(Oid type_id)
690 : {
691 : HeapTuple typeTuple;
692 : Form_pg_type type;
693 : Oid result;
694 :
1991 tgl 695 ECB : for (;;)
696 : {
1991 tgl 697 GBC 1554136 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
1991 tgl 698 CBC 1554136 : if (!HeapTupleIsValid(typeTuple))
1991 tgl 699 LBC 0 : elog(ERROR, "cache lookup failed for type %u", type_id);
1991 tgl 700 GIC 1554136 : type = (Form_pg_type) GETSTRUCT(typeTuple);
701 1554136 : if (type->typtype != TYPTYPE_DOMAIN)
1991 tgl 702 ECB : {
703 : /* Not a domain, so done looking through domains */
1991 tgl 704 GIC 1387112 : break;
1991 tgl 705 ECB : }
706 : /* It is a domain, so examine the base type instead */
1991 tgl 707 GIC 167024 : type_id = type->typbasetype;
1991 tgl 708 CBC 167024 : ReleaseSysCache(typeTuple);
1991 tgl 709 ECB : }
1991 tgl 710 CBC 1387112 : result = type->typrelid;
1991 tgl 711 GIC 1387112 : ReleaseSysCache(typeTuple);
8179 712 1387112 : return result;
713 : }
714 :
715 : /*
716 : * error context callback for parse failure during parseTypeString()
7111 tgl 717 ECB : */
718 : static void
7111 tgl 719 CBC 3 : pts_error_callback(void *arg)
720 : {
721 3 : const char *str = (const char *) arg;
7111 tgl 722 ECB :
7111 tgl 723 GIC 3 : errcontext("invalid type name \"%s\"", str);
724 3 : }
725 :
726 : /*
727 : * Given a string that is supposed to be a SQL-compatible type declaration,
728 : * such as "int4" or "integer" or "character varying(32)", parse
729 : * the string and return the result as a TypeName.
730 : *
731 : * If the string cannot be parsed as a type, an error is raised,
732 : * unless escontext is an ErrorSaveContext node, in which case we may
733 : * fill that and return NULL. But note that the ErrorSaveContext option
734 : * is mostly aspirational at present: errors detected by the main
735 : * grammar, rather than here, will still be thrown.
736 : */
737 : TypeName *
103 tgl 738 GNC 4552 : typeStringToTypeName(const char *str, Node *escontext)
739 : {
740 : List *raw_parsetree_list;
5015 peter_e 741 ECB : TypeName *typeName;
742 : ErrorContextCallback ptserrcontext;
743 :
744 : /* make sure we give useful error for empty input */
7111 tgl 745 GIC 4552 : if (strspn(str, " \t\n\r\f") == strlen(str))
7111 tgl 746 UIC 0 : goto fail;
747 :
7111 tgl 748 ECB : /*
7111 tgl 749 EUB : * Setup error traceback support in case of ereport() during parse
750 : */
7111 tgl 751 GIC 4552 : ptserrcontext.callback = pts_error_callback;
1531 peter 752 4552 : ptserrcontext.arg = unconstify(char *, str);
7111 tgl 753 4552 : ptserrcontext.previous = error_context_stack;
7111 tgl 754 CBC 4552 : error_context_stack = &ptserrcontext;
7852 tgl 755 ECB :
825 tgl 756 CBC 4552 : raw_parsetree_list = raw_parser(str, RAW_PARSE_TYPE_NAME);
7852 tgl 757 ECB :
7111 tgl 758 GIC 4549 : error_context_stack = ptserrcontext.previous;
7111 tgl 759 ECB :
760 : /* We should get back exactly one TypeName node. */
825 tgl 761 CBC 4549 : Assert(list_length(raw_parsetree_list) == 1);
825 tgl 762 GIC 4549 : typeName = linitial_node(TypeName, raw_parsetree_list);
763 :
825 tgl 764 ECB : /* The grammar allows SETOF in TypeName, but we don't want that here. */
5015 peter_e 765 CBC 4549 : if (typeName->setof)
6689 tgl 766 UIC 0 : goto fail;
767 :
3029 alvherre 768 CBC 4549 : return typeName;
3029 alvherre 769 EUB :
3029 alvherre 770 UIC 0 : fail:
103 tgl 771 UNC 0 : ereturn(escontext, NULL,
772 : (errcode(ERRCODE_SYNTAX_ERROR),
3029 alvherre 773 EUB : errmsg("invalid type name \"%s\"", str)));
774 : }
775 :
776 : /*
777 : * Given a string that is supposed to be a SQL-compatible type declaration,
778 : * such as "int4" or "integer" or "character varying(32)", parse
779 : * the string and convert it to a type OID and type modifier.
780 : *
781 : * If escontext is an ErrorSaveContext node, then errors are reported by
782 : * filling escontext and returning false, instead of throwing them.
783 : */
784 : bool
103 tgl 785 GNC 1591 : parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
786 : Node *escontext)
787 : {
788 : TypeName *typeName;
3029 alvherre 789 ECB : Type tup;
790 :
103 tgl 791 GNC 1591 : typeName = typeStringToTypeName(str, escontext);
792 1588 : if (typeName == NULL)
103 tgl 793 UNC 0 : return false;
794 :
103 tgl 795 GNC 1588 : tup = LookupTypeName(NULL, typeName, typmod_p,
796 1588 : (escontext && IsA(escontext, ErrorSaveContext)));
3288 rhaas 797 GIC 1576 : if (tup == NULL)
3288 rhaas 798 ECB : {
103 tgl 799 GNC 17 : ereturn(escontext, false,
800 : (errcode(ERRCODE_UNDEFINED_OBJECT),
801 : errmsg("type \"%s\" does not exist",
802 : TypeNameToString(typeName))));
3288 rhaas 803 ECB : }
804 : else
805 : {
1601 andres 806 GIC 1559 : Form_pg_type typ = (Form_pg_type) GETSTRUCT(tup);
807 :
808 1559 : if (!typ->typisdefined)
809 : {
103 tgl 810 UNC 0 : ReleaseSysCache(tup);
811 0 : ereturn(escontext, false,
3288 rhaas 812 ECB : (errcode(ERRCODE_UNDEFINED_OBJECT),
813 : errmsg("type \"%s\" is only a shell",
814 : TypeNameToString(typeName))));
815 : }
1601 andres 816 GBC 1559 : *typeid_p = typ->oid;
3288 rhaas 817 1559 : ReleaseSysCache(tup);
818 : }
819 :
103 tgl 820 GNC 1559 : return true;
821 : }
|