]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/format_type.c
pgindent run. Make it all clean.
[postgresql] / src / backend / utils / adt / format_type.c
1 /*-------------------------------------------------------------------------
2  *
3  * format_type.c
4  *        Display type names "nicely".
5  *
6  *
7  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.10 2001/03/22 03:59:50 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
18 #include <ctype.h>
19
20 #include "fmgr.h"
21 #include "catalog/pg_type.h"
22 #include "utils/builtins.h"
23 #include "utils/numeric.h"
24 #include "utils/syscache.h"
25
26 #define MAX_INT32_LEN 11
27 #define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))
28
29
30 static char *format_type_internal(Oid type_oid, int32 typemod);
31
32
33 static char *
34 psnprintf(size_t len, const char *fmt,...)
35 {
36         va_list         ap;
37         char       *buf;
38
39         buf = palloc(len);
40
41         va_start(ap, fmt);
42         vsnprintf(buf, len, fmt, ap);
43         va_end(ap);
44
45         return buf;
46 }
47
48
49 /*
50  * SQL function: format_type(type_oid, typemod)
51  *
52  * `type_oid' is from pg_type.oid, `typemod' is from
53  * pg_attribute.atttypmod. This function will get the type name and
54  * format it and the modifier to canonical SQL format, if the type is
55  * a standard type. Otherwise you just get pg_type.typname back,
56  * double quoted if it contains funny characters.
57  *
58  * If typemod is null (in the SQL sense) then you won't get any
59  * "..(x)" type qualifiers. The result is not technically correct,
60  * because the various types interpret missing type modifiers
61  * differently, but it can be used as a convenient way to format
62  * system catalogs, e.g., pg_aggregate, in psql.
63  */
64 Datum
65 format_type(PG_FUNCTION_ARGS)
66 {
67         Oid                     type_oid;
68         int32           typemod;
69         char       *result;
70
71         if (PG_ARGISNULL(0))
72                 PG_RETURN_NULL();
73
74         type_oid = PG_GETARG_OID(0);
75
76         if (!PG_ARGISNULL(1))
77                 typemod = PG_GETARG_INT32(1);
78         else
79                 typemod = -1;                   /* default typmod */
80
81         result = format_type_internal(type_oid, typemod);
82
83         PG_RETURN_DATUM(_textin(result));
84 }
85
86
87 static char *
88 format_type_internal(Oid type_oid, int32 typemod)
89 {
90         bool            with_typemod = (typemod >= 0);
91         HeapTuple       tuple;
92         Oid                     array_base_type;
93         int16           typlen;
94         bool            is_array;
95         char       *name;
96         char       *buf;
97
98         if (type_oid == InvalidOid)
99                 return pstrdup("-");
100
101         tuple = SearchSysCache(TYPEOID,
102                                                    ObjectIdGetDatum(type_oid),
103                                                    0, 0, 0);
104         if (!HeapTupleIsValid(tuple))
105                 return pstrdup("???");
106
107         array_base_type = ((Form_pg_type) GETSTRUCT(tuple))->typelem;
108         typlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
109         if (array_base_type != 0 && typlen < 0)
110         {
111                 /* Switch our attention to the array element type */
112                 ReleaseSysCache(tuple);
113                 tuple = SearchSysCache(TYPEOID,
114                                                            ObjectIdGetDatum(array_base_type),
115                                                            0, 0, 0);
116                 if (!HeapTupleIsValid(tuple))
117                         return pstrdup("???[]");
118                 is_array = true;
119                 type_oid = array_base_type;
120         }
121         else
122                 is_array = false;
123
124         switch (type_oid)
125         {
126                 case BOOLOID:
127                         buf = pstrdup("boolean");
128                         break;
129
130                 case BPCHAROID:
131                         if (with_typemod)
132                                 buf = psnprintf(11 + MAX_INT32_LEN + 1, "character(%d)",
133                                                                 (int) (typemod - VARHDRSZ));
134                         else
135                                 buf = pstrdup("character");
136                         break;
137
138                 case CHAROID:
139
140                         /*
141                          * This char type is the single-byte version. You have to
142                          * double-quote it to get at it in the parser.
143                          */
144                         buf = pstrdup("\"char\"");
145                         break;
146
147                 case FLOAT4OID:
148                         buf = pstrdup("real");
149                         break;
150
151                 case FLOAT8OID:
152                         buf = pstrdup("double precision");
153                         break;
154
155                 case INT2OID:
156                         buf = pstrdup("smallint");
157                         break;
158
159                 case INT4OID:
160                         buf = pstrdup("integer");
161                         break;
162
163                 case INT8OID:
164                         buf = pstrdup("bigint");
165                         break;
166
167                 case NUMERICOID:
168                         if (with_typemod)
169                                 buf = psnprintf(10 + 2 * MAX_INT32_LEN + 1, "numeric(%d,%d)",
170                                                                 ((typemod - VARHDRSZ) >> 16) & 0xffff,
171                                                                 (typemod - VARHDRSZ) & 0xffff);
172                         else
173                                 buf = pstrdup("numeric");
174                         break;
175
176                 case TIMETZOID:
177                         buf = pstrdup("time with time zone");
178                         break;
179
180                 case TIMESTAMPOID:
181                         buf = pstrdup("timestamp with time zone");
182                         break;
183
184                 case VARBITOID:
185                         if (with_typemod)
186                                 buf = psnprintf(13 + MAX_INT32_LEN + 1, "bit varying(%d)",
187                                                                 (int) typemod);
188                         else
189                                 buf = pstrdup("bit varying");
190                         break;
191
192                 case VARCHAROID:
193                         if (with_typemod)
194                                 buf = psnprintf(19 + MAX_INT32_LEN + 1,
195                                                                 "character varying(%d)",
196                                                                 (int) (typemod - VARHDRSZ));
197                         else
198                                 buf = pstrdup("character varying");
199                         break;
200
201                 case ZPBITOID:
202                         if (with_typemod)
203                                 buf = psnprintf(5 + MAX_INT32_LEN + 1, "bit(%d)",
204                                                                 (int) typemod);
205                         else
206                                 buf = pstrdup("bit");
207                         break;
208
209                 default:
210                         name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname);
211                         if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name)
212                                 || isdigit((unsigned char) name[0]))
213                                 buf = psnprintf(strlen(name) + 3, "\"%s\"", name);
214                         else
215                                 buf = pstrdup(name);
216                         break;
217         }
218
219         if (is_array)
220                 buf = psnprintf(strlen(buf) + 3, "%s[]", buf);
221
222         ReleaseSysCache(tuple);
223
224         return buf;
225 }
226
227
228 /*
229  * type_maximum_size --- determine maximum length of a varlena column
230  *
231  * If the max length is indeterminate, return -1.  In particular, we return
232  * -1 for any type not known to this routine.  We assume the caller has
233  * already determined that the type is a varlena type, so it's not
234  * necessary to look up the type's pg_type tuple here.
235  *
236  * This may appear unrelated to format_type(), but in fact the two routines
237  * share knowledge of the encoding of typmod for different types, so it's
238  * convenient to keep them together.
239  */
240 int32
241 type_maximum_size(Oid type_oid, int32 typemod)
242 {
243         if (typemod <= 0)
244                 return -1;
245
246         switch (type_oid)
247         {
248                 case BPCHAROID:
249                 case VARCHAROID:
250                         /* typemod includes varlena header */
251                         return typemod;
252
253                 case NUMERICOID:
254                         /* precision (ie, max # of digits) is in upper bits of typmod */
255                         if (typemod > VARHDRSZ)
256                         {
257                                 int                     precision = ((typemod - VARHDRSZ) >> 16) & 0xffff;
258
259                                 /* Numeric stores 2 decimal digits/byte, plus header */
260                                 return (precision + 1) / 2 + NUMERIC_HDRSZ;
261                         }
262                         break;
263
264                 case VARBITOID:
265                 case ZPBITOID:
266                         /* typemod is the (max) number of bits */
267                         return (typemod + (BITS_PER_BYTE - 1)) / BITS_PER_BYTE
268                                 + 2 * sizeof(int32);
269         }
270
271         /* Unknown type, or unlimited-length type such as 'text' */
272         return -1;
273 }
274
275
276 /*
277  * oidvectortypes                       - converts a vector of type OIDs to "typname" list
278  *
279  * The interface for this function is wrong: it should be told how many
280  * OIDs are significant in the input vector, so that trailing InvalidOid
281  * argument types can be recognized.
282  */
283 Datum
284 oidvectortypes(PG_FUNCTION_ARGS)
285 {
286         Oid                *oidArray = (Oid *) PG_GETARG_POINTER(0);
287         char       *result;
288         int                     numargs;
289         int                     num;
290         size_t          total;
291         size_t          left;
292
293         /* Try to guess how many args there are :-( */
294         numargs = 0;
295         for (num = 0; num < FUNC_MAX_ARGS; num++)
296         {
297                 if (oidArray[num] != InvalidOid)
298                         numargs = num + 1;
299         }
300
301         total = 20 * numargs + 1;
302         result = palloc(total);
303         result[0] = '\0';
304         left = total - 1;
305
306         for (num = 0; num < numargs; num++)
307         {
308                 char       *typename = format_type_internal(oidArray[num], -1);
309
310                 if (left < strlen(typename) + 2)
311                 {
312                         total += strlen(typename) + 2;
313                         result = repalloc(result, total);
314                         left += strlen(typename) + 2;
315                 }
316
317                 if (num > 0)
318                 {
319                         strcat(result, ", ");
320                         left -= 2;
321                 }
322                 strcat(result, typename);
323                 left -= strlen(typename);
324         }
325
326         PG_RETURN_DATUM(_textin(result));
327 }