]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/format_type.c
Rename BITSPERBYTE to BITS_PER_BYTE to avoid conflict with <values.h>
[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-2000, PostgreSQL, Inc
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.5 2000/08/26 21:53:41 tgl 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 = SearchSysCacheTuple(TYPEOID, ObjectIdGetDatum(type_oid),
102                                                                 0, 0, 0);
103
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                 tuple = SearchSysCacheTuple(TYPEOID,
112                                                                         ObjectIdGetDatum(array_base_type),
113                                                                         0, 0, 0);
114                 if (!HeapTupleIsValid(tuple))
115                         return pstrdup("???[]");
116                 is_array = true;
117                 type_oid = array_base_type;
118         }
119         else
120                 is_array = false;
121
122         switch (type_oid)
123         {
124                 case BOOLOID:
125                         buf = pstrdup("boolean");
126                         break;
127
128                 case BPCHAROID:
129                         if (with_typemod)
130                                 buf = psnprintf(11 + MAX_INT32_LEN + 1, "character(%d)",
131                                                                 (int) (typemod - VARHDRSZ));
132                         else
133                                 buf = pstrdup("character");
134                         break;
135
136                 case CHAROID:
137                         /* This char type is the single-byte version. You have to
138                          * double-quote it to get at it in the parser.
139                          */
140                         buf = pstrdup("\"char\"");
141                         break;
142
143                 case FLOAT4OID:
144                         buf = pstrdup("real");
145                         break;
146
147                 case FLOAT8OID:
148                         buf = pstrdup("double precision");
149                         break;
150
151                 case INT2OID:
152                         buf = pstrdup("smallint");
153                         break;
154
155                 case INT4OID:
156                         buf = pstrdup("integer");
157                         break;
158
159                 case INT8OID:
160                         buf = pstrdup("bigint");
161                         break;
162
163                 case NUMERICOID:
164                         if (with_typemod)
165                                 buf = psnprintf(10 + 2 * MAX_INT32_LEN + 1, "numeric(%d,%d)",
166                                                                 ((typemod - VARHDRSZ) >> 16) & 0xffff,
167                                                                 (typemod - VARHDRSZ) & 0xffff);
168                         else
169                                 buf = pstrdup("numeric");
170                         break;
171
172                 case TIMETZOID:
173                         buf = pstrdup("time with time zone");
174                         break;
175
176                 case VARBITOID:
177                         if (with_typemod)
178                                 buf = psnprintf(13 + MAX_INT32_LEN + 1, "bit varying(%d)",
179                                                                 (int) typemod);
180                         else
181                                 buf = pstrdup("bit varying");
182                         break;
183
184                 case VARCHAROID:
185                         if (with_typemod)
186                                 buf = psnprintf(19 + MAX_INT32_LEN + 1,
187                                                                 "character varying(%d)",
188                                                                 (int) (typemod - VARHDRSZ));
189                         else
190                                 buf = pstrdup("character varying");
191                         break;
192
193                 case ZPBITOID:
194                         if (with_typemod)
195                                 buf = psnprintf(5 + MAX_INT32_LEN + 1, "bit(%d)",
196                                                                 (int) typemod);
197                         else
198                                 buf = pstrdup("bit");
199                         break;
200
201                 default:
202                         name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname);
203                         if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name)
204                                 || isdigit((int) name[0]))
205                                 buf = psnprintf(strlen(name) + 3, "\"%s\"", name);
206                         else
207                                 buf = pstrdup(name);
208                         break;
209         }
210
211         if (is_array)
212                 buf = psnprintf(strlen(buf) + 3, "%s[]", buf);
213
214         return buf;
215 }
216
217
218 /*
219  * type_maximum_size --- determine maximum length of a varlena column
220  *
221  * If the max length is indeterminate, return -1.  In particular, we return
222  * -1 for any type not known to this routine.  We assume the caller has
223  * already determined that the type is a varlena type, so it's not
224  * necessary to look up the type's pg_type tuple here.
225  *
226  * This may appear unrelated to format_type(), but in fact the two routines
227  * share knowledge of the encoding of typmod for different types, so it's
228  * convenient to keep them together.
229  */
230 int32
231 type_maximum_size(Oid type_oid, int32 typemod)
232 {
233         if (typemod <= 0)
234                 return -1;
235
236         switch (type_oid)
237         {
238                 case BPCHAROID:
239                 case VARCHAROID:
240                         /* typemod includes varlena header */
241                         return typemod;
242
243                 case NUMERICOID:
244                         /* precision (ie, max # of digits) is in upper bits of typmod */
245                         if (typemod > VARHDRSZ)
246                         {
247                                 int             precision = ((typemod - VARHDRSZ) >> 16) & 0xffff;
248
249                                 /* Numeric stores 2 decimal digits/byte, plus header */
250                                 return (precision + 1) / 2 + NUMERIC_HDRSZ;
251                         }
252                         break;
253
254                 case VARBITOID:
255                 case ZPBITOID:
256                         /* typemod is the (max) number of bits */
257                         return (typemod + (BITS_PER_BYTE-1)) / BITS_PER_BYTE
258                                 + 2 * sizeof(int32);
259         }
260
261         /* Unknown type, or unlimited-length type such as 'text' */
262         return -1;
263 }
264
265
266 /*
267  * oidvectortypes                       - converts a vector of type OIDs to "typname" list
268  *
269  * The interface for this function is wrong: it should be told how many
270  * OIDs are significant in the input vector, so that trailing InvalidOid
271  * argument types can be recognized.
272  */
273 Datum
274 oidvectortypes(PG_FUNCTION_ARGS)
275 {
276         Oid                *oidArray = (Oid *) PG_GETARG_POINTER(0);
277         char       *result;
278         int                     numargs;
279         int                     num;
280         size_t          total;
281         size_t          left;
282
283         /* Try to guess how many args there are :-( */
284         numargs = 0;
285         for (num = 0; num < FUNC_MAX_ARGS; num++)
286         {
287                 if (oidArray[num] != InvalidOid)
288                         numargs = num + 1;
289         }
290
291         total = 20 * numargs + 1;
292         result = palloc(total);
293         result[0] = '\0';
294         left = total - 1;
295                                         
296         for (num = 0; num < numargs; num++)
297         {
298                 char * typename = format_type_internal(oidArray[num], -1);
299
300                 if (left < strlen(typename) + 2)
301                 {
302                         total += strlen(typename) + 2;
303                         result = repalloc(result, total);
304                         left += strlen(typename) + 2;
305                 }
306
307                 if (num > 0)
308                 {
309                         strcat(result, ", ");
310                         left -= 2;
311                 }
312                 strcat(result, typename);
313                 left -= strlen(typename);
314         }
315
316         PG_RETURN_DATUM(_textin(result));
317 }