OSDN Git Service

pgindent run for 8.2.
[pg-rex/syncrep.git] / src / backend / parser / parse_type.c
1 /*-------------------------------------------------------------------------
2  *
3  * parse_type.c
4  *              handle type operations for parser
5  *
6  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.85 2006/10/04 00:29:56 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
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"
26
27
28 /*
29  * LookupTypeName
30  *              Given a TypeName object, get the OID of the referenced type.
31  *              Returns InvalidOid if no such type can be found.
32  *
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.
35  *
36  * pstate is only used for error location info, and may be NULL.
37  */
38 Oid
39 LookupTypeName(ParseState *pstate, const TypeName *typename)
40 {
41         Oid                     restype;
42
43         /* Easy if it's an internally generated TypeName */
44         if (typename->names == NIL)
45                 return typename->typeid;
46
47         if (typename->pct_type)
48         {
49                 /* Handle %TYPE reference to type of an existing field */
50                 RangeVar   *rel = makeRangeVar(NULL, NULL);
51                 char       *field = NULL;
52                 Oid                     relid;
53                 AttrNumber      attnum;
54
55                 /* deconstruct the name list */
56                 switch (list_length(typename->names))
57                 {
58                         case 1:
59                                 ereport(ERROR,
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)));
64                                 break;
65                         case 2:
66                                 rel->relname = strVal(linitial(typename->names));
67                                 field = strVal(lsecond(typename->names));
68                                 break;
69                         case 3:
70                                 rel->schemaname = strVal(linitial(typename->names));
71                                 rel->relname = strVal(lsecond(typename->names));
72                                 field = strVal(lthird(typename->names));
73                                 break;
74                         case 4:
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));
79                                 break;
80                         default:
81                                 ereport(ERROR,
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)));
86                                 break;
87                 }
88
89                 /* look up the field */
90                 relid = RangeVarGetRelid(rel, false);
91                 attnum = get_attnum(relid, field);
92                 if (attnum == InvalidAttrNumber)
93                         ereport(ERROR,
94                                         (errcode(ERRCODE_UNDEFINED_COLUMN),
95                                          errmsg("column \"%s\" of relation \"%s\" does not exist",
96                                                         field, rel->relname),
97                                          parser_errposition(pstate, typename->location)));
98                 restype = get_atttype(relid, attnum);
99
100                 /* this construct should never have an array indicator */
101                 Assert(typename->arrayBounds == NIL);
102
103                 /* emit nuisance notice */
104                 ereport(NOTICE,
105                                 (errmsg("type reference %s converted to %s",
106                                                 TypeNameToString(typename),
107                                                 format_type_be(restype))));
108         }
109         else
110         {
111                 /* Normal reference to a type name */
112                 char       *schemaname;
113                 char       *typname;
114
115                 /* deconstruct the name list */
116                 DeconstructQualifiedName(typename->names, &schemaname, &typname);
117
118                 /* If an array reference, look up the array type instead */
119                 if (typename->arrayBounds != NIL)
120                         typname = makeArrayTypeName(typname);
121
122                 if (schemaname)
123                 {
124                         /* Look in specific schema only */
125                         Oid                     namespaceId;
126
127                         namespaceId = LookupExplicitNamespace(schemaname);
128                         restype = GetSysCacheOid(TYPENAMENSP,
129                                                                          PointerGetDatum(typname),
130                                                                          ObjectIdGetDatum(namespaceId),
131                                                                          0, 0);
132                 }
133                 else
134                 {
135                         /* Unqualified type name, so search the search path */
136                         restype = TypenameGetTypid(typname);
137                 }
138         }
139
140         return restype;
141 }
142
143 /*
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.
147  *
148  * NB: this must work on TypeNames that do not describe any actual type;
149  * it is mostly used for reporting lookup errors.
150  */
151 static void
152 appendTypeNameToBuffer(const TypeName *typename, StringInfo string)
153 {
154         if (typename->names != NIL)
155         {
156                 /* Emit possibly-qualified name as-is */
157                 ListCell   *l;
158
159                 foreach(l, typename->names)
160                 {
161                         if (l != list_head(typename->names))
162                                 appendStringInfoChar(string, '.');
163                         appendStringInfoString(string, strVal(lfirst(l)));
164                 }
165         }
166         else
167         {
168                 /* Look up internally-specified type */
169                 appendStringInfoString(string, format_type_be(typename->typeid));
170         }
171
172         /*
173          * Add decoration as needed, but only for fields considered by
174          * LookupTypeName
175          */
176         if (typename->pct_type)
177                 appendStringInfoString(string, "%TYPE");
178
179         if (typename->arrayBounds != NIL)
180                 appendStringInfoString(string, "[]");
181 }
182
183 /*
184  * TypeNameToString
185  *              Produce a string representing the name of a TypeName.
186  *
187  * NB: this must work on TypeNames that do not describe any actual type;
188  * it is mostly used for reporting lookup errors.
189  */
190 char *
191 TypeNameToString(const TypeName *typename)
192 {
193         StringInfoData string;
194
195         initStringInfo(&string);
196         appendTypeNameToBuffer(typename, &string);
197         return string.data;
198 }
199
200 /*
201  * TypeNameListToString
202  *              Produce a string representing the name(s) of a List of TypeNames
203  */
204 char *
205 TypeNameListToString(List *typenames)
206 {
207         StringInfoData string;
208         ListCell   *l;
209
210         initStringInfo(&string);
211         foreach(l, typenames)
212         {
213                 TypeName   *typename = (TypeName *) lfirst(l);
214
215                 Assert(IsA(typename, TypeName));
216                 if (l != list_head(typenames))
217                         appendStringInfoChar(&string, ',');
218                 appendTypeNameToBuffer(typename, &string);
219         }
220         return string.data;
221 }
222
223 /*
224  * typenameTypeId - given a TypeName, return the type's OID
225  *
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.
228  */
229 Oid
230 typenameTypeId(ParseState *pstate, const TypeName *typename)
231 {
232         Oid                     typoid;
233
234         typoid = LookupTypeName(pstate, typename);
235         if (!OidIsValid(typoid))
236                 ereport(ERROR,
237                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
238                                  errmsg("type \"%s\" does not exist",
239                                                 TypeNameToString(typename)),
240                                  parser_errposition(pstate, typename->location)));
241
242         if (!get_typisdefined(typoid))
243                 ereport(ERROR,
244                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
245                                  errmsg("type \"%s\" is only a shell",
246                                                 TypeNameToString(typename)),
247                                  parser_errposition(pstate, typename->location)));
248         return typoid;
249 }
250
251 /*
252  * typenameType - given a TypeName, return a Type structure
253  *
254  * This is equivalent to typenameTypeId + syscache fetch of Type tuple.
255  * NB: caller must ReleaseSysCache the type tuple when done with it.
256  */
257 Type
258 typenameType(ParseState *pstate, const TypeName *typename)
259 {
260         Oid                     typoid;
261         HeapTuple       tup;
262
263         typoid = LookupTypeName(pstate, typename);
264         if (!OidIsValid(typoid))
265                 ereport(ERROR,
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),
272                                                  0, 0, 0);
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)
276                 ereport(ERROR,
277                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
278                                  errmsg("type \"%s\" is only a shell",
279                                                 TypeNameToString(typename)),
280                                  parser_errposition(pstate, typename->location)));
281         return (Type) tup;
282 }
283
284 /* return a Type structure, given a type id */
285 /* NB: caller must ReleaseSysCache the type tuple when done with it */
286 Type
287 typeidType(Oid id)
288 {
289         HeapTuple       tup;
290
291         tup = SearchSysCache(TYPEOID,
292                                                  ObjectIdGetDatum(id),
293                                                  0, 0, 0);
294         if (!HeapTupleIsValid(tup))
295                 elog(ERROR, "cache lookup failed for type %u", id);
296         return (Type) tup;
297 }
298
299 /* given type (as type struct), return the type OID */
300 Oid
301 typeTypeId(Type tp)
302 {
303         if (tp == NULL)                         /* probably useless */
304                 elog(ERROR, "typeTypeId() called with NULL type struct");
305         return HeapTupleGetOid(tp);
306 }
307
308 /* given type (as type struct), return the length of type */
309 int16
310 typeLen(Type t)
311 {
312         Form_pg_type typ;
313
314         typ = (Form_pg_type) GETSTRUCT(t);
315         return typ->typlen;
316 }
317
318 /* given type (as type struct), return the value of its 'byval' attribute.*/
319 bool
320 typeByVal(Type t)
321 {
322         Form_pg_type typ;
323
324         typ = (Form_pg_type) GETSTRUCT(t);
325         return typ->typbyval;
326 }
327
328 /* given type (as type struct), return the value of its 'typtype' attribute.*/
329 char
330 typeTypType(Type t)
331 {
332         Form_pg_type typ;
333
334         typ = (Form_pg_type) GETSTRUCT(t);
335         return typ->typtype;
336 }
337
338 /* given type (as type struct), return the name of type */
339 char *
340 typeTypeName(Type t)
341 {
342         Form_pg_type typ;
343
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));
347 }
348
349 Oid
350 typeTypeRelid(Type typ)
351 {
352         Form_pg_type typtup;
353
354         typtup = (Form_pg_type) GETSTRUCT(typ);
355
356         return typtup->typrelid;
357 }
358
359 /*
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).
363  */
364 Datum
365 stringTypeDatum(Type tp, char *string, int32 atttypmod)
366 {
367         Oid                     typinput;
368         Oid                     typioparam;
369
370         typinput = ((Form_pg_type) GETSTRUCT(tp))->typinput;
371         typioparam = getTypeIOParam(tp);
372         return OidInputFunctionCall(typinput, string,
373                                                                 typioparam, atttypmod);
374 }
375
376 /* given a typeid, return the type's typrelid (associated relation, if any) */
377 Oid
378 typeidTypeRelid(Oid type_id)
379 {
380         HeapTuple       typeTuple;
381         Form_pg_type type;
382         Oid                     result;
383
384         typeTuple = SearchSysCache(TYPEOID,
385                                                            ObjectIdGetDatum(type_id),
386                                                            0, 0, 0);
387         if (!HeapTupleIsValid(typeTuple))
388                 elog(ERROR, "cache lookup failed for type %u", type_id);
389
390         type = (Form_pg_type) GETSTRUCT(typeTuple);
391         result = type->typrelid;
392         ReleaseSysCache(typeTuple);
393         return result;
394 }
395
396 /*
397  * error context callback for parse failure during parseTypeString()
398  */
399 static void
400 pts_error_callback(void *arg)
401 {
402         const char *str = (const char *) arg;
403
404         errcontext("invalid type name \"%s\"", str);
405
406         /*
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.
410          */
411         errposition(0);
412 }
413
414 /*
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.
418  */
419 void
420 parseTypeString(const char *str, Oid *type_id, int32 *typmod)
421 {
422         StringInfoData buf;
423         List       *raw_parsetree_list;
424         SelectStmt *stmt;
425         ResTarget  *restarget;
426         TypeCast   *typecast;
427         TypeName   *typename;
428         ErrorContextCallback ptserrcontext;
429
430         /* make sure we give useful error for empty input */
431         if (strspn(str, " \t\n\r\f") == strlen(str))
432                 goto fail;
433
434         initStringInfo(&buf);
435         appendStringInfo(&buf, "SELECT NULL::%s", str);
436
437         /*
438          * Setup error traceback support in case of ereport() during parse
439          */
440         ptserrcontext.callback = pts_error_callback;
441         ptserrcontext.arg = (void *) str;
442         ptserrcontext.previous = error_context_stack;
443         error_context_stack = &ptserrcontext;
444
445         raw_parsetree_list = raw_parser(buf.data);
446
447         error_context_stack = ptserrcontext.previous;
448
449         /*
450          * Make sure we got back exactly what we expected and no more; paranoia is
451          * justified since the string might contain anything.
452          */
453         if (list_length(raw_parsetree_list) != 1)
454                 goto fail;
455         stmt = (SelectStmt *) linitial(raw_parsetree_list);
456         if (stmt == NULL ||
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)
470                 goto fail;
471         if (list_length(stmt->targetList) != 1)
472                 goto fail;
473         restarget = (ResTarget *) linitial(stmt->targetList);
474         if (restarget == NULL ||
475                 !IsA(restarget, ResTarget) ||
476                 restarget->name != NULL ||
477                 restarget->indirection != NIL)
478                 goto fail;
479         typecast = (TypeCast *) restarget->val;
480         if (typecast == NULL ||
481                 !IsA(typecast, TypeCast) ||
482                 typecast->arg == NULL ||
483                 !IsA(typecast->arg, A_Const))
484                 goto fail;
485         typename = typecast->typename;
486         if (typename == NULL ||
487                 !IsA(typename, TypeName))
488                 goto fail;
489         if (typename->setof)
490                 goto fail;
491
492         *type_id = typenameTypeId(NULL, typename);
493         *typmod = typename->typmod;
494
495         pfree(buf.data);
496
497         return;
498
499 fail:
500         ereport(ERROR,
501                         (errcode(ERRCODE_SYNTAX_ERROR),
502                          errmsg("invalid type name \"%s\"", str)));
503 }