1 /*-------------------------------------------------------------------------
4 * handle type operations for parser
6 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.85 2006/10/04 00:29:56 momjian Exp $
13 *-------------------------------------------------------------------------
17 #include "catalog/namespace.h"
18 #include "catalog/pg_type.h"
19 #include "lib/stringinfo.h"
20 #include "nodes/makefuncs.h"
21 #include "parser/parser.h"
22 #include "parser/parse_type.h"
23 #include "utils/builtins.h"
24 #include "utils/lsyscache.h"
25 #include "utils/syscache.h"
30 * Given a TypeName object, get the OID of the referenced type.
31 * Returns InvalidOid if no such type can be found.
33 * NB: even if the returned OID is not InvalidOid, the type might be
34 * just a shell. Caller should check typisdefined before using the type.
36 * pstate is only used for error location info, and may be NULL.
39 LookupTypeName(ParseState *pstate, const TypeName *typename)
43 /* Easy if it's an internally generated TypeName */
44 if (typename->names == NIL)
45 return typename->typeid;
47 if (typename->pct_type)
49 /* Handle %TYPE reference to type of an existing field */
50 RangeVar *rel = makeRangeVar(NULL, NULL);
55 /* deconstruct the name list */
56 switch (list_length(typename->names))
60 (errcode(ERRCODE_SYNTAX_ERROR),
61 errmsg("improper %%TYPE reference (too few dotted names): %s",
62 NameListToString(typename->names)),
63 parser_errposition(pstate, typename->location)));
66 rel->relname = strVal(linitial(typename->names));
67 field = strVal(lsecond(typename->names));
70 rel->schemaname = strVal(linitial(typename->names));
71 rel->relname = strVal(lsecond(typename->names));
72 field = strVal(lthird(typename->names));
75 rel->catalogname = strVal(linitial(typename->names));
76 rel->schemaname = strVal(lsecond(typename->names));
77 rel->relname = strVal(lthird(typename->names));
78 field = strVal(lfourth(typename->names));
82 (errcode(ERRCODE_SYNTAX_ERROR),
83 errmsg("improper %%TYPE reference (too many dotted names): %s",
84 NameListToString(typename->names)),
85 parser_errposition(pstate, typename->location)));
89 /* look up the field */
90 relid = RangeVarGetRelid(rel, false);
91 attnum = get_attnum(relid, field);
92 if (attnum == InvalidAttrNumber)
94 (errcode(ERRCODE_UNDEFINED_COLUMN),
95 errmsg("column \"%s\" of relation \"%s\" does not exist",
97 parser_errposition(pstate, typename->location)));
98 restype = get_atttype(relid, attnum);
100 /* this construct should never have an array indicator */
101 Assert(typename->arrayBounds == NIL);
103 /* emit nuisance notice */
105 (errmsg("type reference %s converted to %s",
106 TypeNameToString(typename),
107 format_type_be(restype))));
111 /* Normal reference to a type name */
115 /* deconstruct the name list */
116 DeconstructQualifiedName(typename->names, &schemaname, &typname);
118 /* If an array reference, look up the array type instead */
119 if (typename->arrayBounds != NIL)
120 typname = makeArrayTypeName(typname);
124 /* Look in specific schema only */
127 namespaceId = LookupExplicitNamespace(schemaname);
128 restype = GetSysCacheOid(TYPENAMENSP,
129 PointerGetDatum(typname),
130 ObjectIdGetDatum(namespaceId),
135 /* Unqualified type name, so search the search path */
136 restype = TypenameGetTypid(typname);
144 * appendTypeNameToBuffer
145 * Append a string representing the name of a TypeName to a StringInfo.
146 * This is the shared guts of TypeNameToString and TypeNameListToString.
148 * NB: this must work on TypeNames that do not describe any actual type;
149 * it is mostly used for reporting lookup errors.
152 appendTypeNameToBuffer(const TypeName *typename, StringInfo string)
154 if (typename->names != NIL)
156 /* Emit possibly-qualified name as-is */
159 foreach(l, typename->names)
161 if (l != list_head(typename->names))
162 appendStringInfoChar(string, '.');
163 appendStringInfoString(string, strVal(lfirst(l)));
168 /* Look up internally-specified type */
169 appendStringInfoString(string, format_type_be(typename->typeid));
173 * Add decoration as needed, but only for fields considered by
176 if (typename->pct_type)
177 appendStringInfoString(string, "%TYPE");
179 if (typename->arrayBounds != NIL)
180 appendStringInfoString(string, "[]");
185 * Produce a string representing the name of a TypeName.
187 * NB: this must work on TypeNames that do not describe any actual type;
188 * it is mostly used for reporting lookup errors.
191 TypeNameToString(const TypeName *typename)
193 StringInfoData string;
195 initStringInfo(&string);
196 appendTypeNameToBuffer(typename, &string);
201 * TypeNameListToString
202 * Produce a string representing the name(s) of a List of TypeNames
205 TypeNameListToString(List *typenames)
207 StringInfoData string;
210 initStringInfo(&string);
211 foreach(l, typenames)
213 TypeName *typename = (TypeName *) lfirst(l);
215 Assert(IsA(typename, TypeName));
216 if (l != list_head(typenames))
217 appendStringInfoChar(&string, ',');
218 appendTypeNameToBuffer(typename, &string);
224 * typenameTypeId - given a TypeName, return the type's OID
226 * This is equivalent to LookupTypeName, except that this will report
227 * a suitable error message if the type cannot be found or is not defined.
230 typenameTypeId(ParseState *pstate, const TypeName *typename)
234 typoid = LookupTypeName(pstate, typename);
235 if (!OidIsValid(typoid))
237 (errcode(ERRCODE_UNDEFINED_OBJECT),
238 errmsg("type \"%s\" does not exist",
239 TypeNameToString(typename)),
240 parser_errposition(pstate, typename->location)));
242 if (!get_typisdefined(typoid))
244 (errcode(ERRCODE_UNDEFINED_OBJECT),
245 errmsg("type \"%s\" is only a shell",
246 TypeNameToString(typename)),
247 parser_errposition(pstate, typename->location)));
252 * typenameType - given a TypeName, return a Type structure
254 * This is equivalent to typenameTypeId + syscache fetch of Type tuple.
255 * NB: caller must ReleaseSysCache the type tuple when done with it.
258 typenameType(ParseState *pstate, const TypeName *typename)
263 typoid = LookupTypeName(pstate, typename);
264 if (!OidIsValid(typoid))
266 (errcode(ERRCODE_UNDEFINED_OBJECT),
267 errmsg("type \"%s\" does not exist",
268 TypeNameToString(typename)),
269 parser_errposition(pstate, typename->location)));
270 tup = SearchSysCache(TYPEOID,
271 ObjectIdGetDatum(typoid),
273 if (!HeapTupleIsValid(tup)) /* should not happen */
274 elog(ERROR, "cache lookup failed for type %u", typoid);
275 if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
277 (errcode(ERRCODE_UNDEFINED_OBJECT),
278 errmsg("type \"%s\" is only a shell",
279 TypeNameToString(typename)),
280 parser_errposition(pstate, typename->location)));
284 /* return a Type structure, given a type id */
285 /* NB: caller must ReleaseSysCache the type tuple when done with it */
291 tup = SearchSysCache(TYPEOID,
292 ObjectIdGetDatum(id),
294 if (!HeapTupleIsValid(tup))
295 elog(ERROR, "cache lookup failed for type %u", id);
299 /* given type (as type struct), return the type OID */
303 if (tp == NULL) /* probably useless */
304 elog(ERROR, "typeTypeId() called with NULL type struct");
305 return HeapTupleGetOid(tp);
308 /* given type (as type struct), return the length of type */
314 typ = (Form_pg_type) GETSTRUCT(t);
318 /* given type (as type struct), return the value of its 'byval' attribute.*/
324 typ = (Form_pg_type) GETSTRUCT(t);
325 return typ->typbyval;
328 /* given type (as type struct), return the value of its 'typtype' attribute.*/
334 typ = (Form_pg_type) GETSTRUCT(t);
338 /* given type (as type struct), return the name of type */
344 typ = (Form_pg_type) GETSTRUCT(t);
345 /* pstrdup here because result may need to outlive the syscache entry */
346 return pstrdup(NameStr(typ->typname));
350 typeTypeRelid(Type typ)
354 typtup = (Form_pg_type) GETSTRUCT(typ);
356 return typtup->typrelid;
360 * Given a type structure and a string, returns the internal representation
361 * of that string. The "string" can be NULL to perform conversion of a NULL
362 * (which might result in failure, if the input function rejects NULLs).
365 stringTypeDatum(Type tp, char *string, int32 atttypmod)
370 typinput = ((Form_pg_type) GETSTRUCT(tp))->typinput;
371 typioparam = getTypeIOParam(tp);
372 return OidInputFunctionCall(typinput, string,
373 typioparam, atttypmod);
376 /* given a typeid, return the type's typrelid (associated relation, if any) */
378 typeidTypeRelid(Oid type_id)
384 typeTuple = SearchSysCache(TYPEOID,
385 ObjectIdGetDatum(type_id),
387 if (!HeapTupleIsValid(typeTuple))
388 elog(ERROR, "cache lookup failed for type %u", type_id);
390 type = (Form_pg_type) GETSTRUCT(typeTuple);
391 result = type->typrelid;
392 ReleaseSysCache(typeTuple);
397 * error context callback for parse failure during parseTypeString()
400 pts_error_callback(void *arg)
402 const char *str = (const char *) arg;
404 errcontext("invalid type name \"%s\"", str);
407 * Currently we just suppress any syntax error position report, rather
408 * than transforming to an "internal query" error. It's unlikely that a
409 * type name is complex enough to need positioning.
415 * Given a string that is supposed to be a SQL-compatible type declaration,
416 * such as "int4" or "integer" or "character varying(32)", parse
417 * the string and convert it to a type OID and type modifier.
420 parseTypeString(const char *str, Oid *type_id, int32 *typmod)
423 List *raw_parsetree_list;
425 ResTarget *restarget;
428 ErrorContextCallback ptserrcontext;
430 /* make sure we give useful error for empty input */
431 if (strspn(str, " \t\n\r\f") == strlen(str))
434 initStringInfo(&buf);
435 appendStringInfo(&buf, "SELECT NULL::%s", str);
438 * Setup error traceback support in case of ereport() during parse
440 ptserrcontext.callback = pts_error_callback;
441 ptserrcontext.arg = (void *) str;
442 ptserrcontext.previous = error_context_stack;
443 error_context_stack = &ptserrcontext;
445 raw_parsetree_list = raw_parser(buf.data);
447 error_context_stack = ptserrcontext.previous;
450 * Make sure we got back exactly what we expected and no more; paranoia is
451 * justified since the string might contain anything.
453 if (list_length(raw_parsetree_list) != 1)
455 stmt = (SelectStmt *) linitial(raw_parsetree_list);
457 !IsA(stmt, SelectStmt) ||
458 stmt->distinctClause != NIL ||
459 stmt->into != NULL ||
460 stmt->fromClause != NIL ||
461 stmt->whereClause != NULL ||
462 stmt->groupClause != NIL ||
463 stmt->havingClause != NULL ||
464 stmt->valuesLists != NIL ||
465 stmt->sortClause != NIL ||
466 stmt->limitOffset != NULL ||
467 stmt->limitCount != NULL ||
468 stmt->lockingClause != NIL ||
469 stmt->op != SETOP_NONE)
471 if (list_length(stmt->targetList) != 1)
473 restarget = (ResTarget *) linitial(stmt->targetList);
474 if (restarget == NULL ||
475 !IsA(restarget, ResTarget) ||
476 restarget->name != NULL ||
477 restarget->indirection != NIL)
479 typecast = (TypeCast *) restarget->val;
480 if (typecast == NULL ||
481 !IsA(typecast, TypeCast) ||
482 typecast->arg == NULL ||
483 !IsA(typecast->arg, A_Const))
485 typename = typecast->typename;
486 if (typename == NULL ||
487 !IsA(typename, TypeName))
492 *type_id = typenameTypeId(NULL, typename);
493 *typmod = typename->typmod;
501 (errcode(ERRCODE_SYNTAX_ERROR),
502 errmsg("invalid type name \"%s\"", str)));