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