|
| 1 | +/* $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.1 2000/07/07 19:24:37 petere Exp $ */ |
| 2 | + |
| 3 | +#include "postgres.h" |
| 4 | + |
| 5 | +#include <ctype.h> |
| 6 | +#include <stdarg.h> |
| 7 | + |
| 8 | +#include "fmgr.h" |
| 9 | +#include "catalog/pg_type.h" |
| 10 | +#include "utils/builtins.h" |
| 11 | +#include "utils/syscache.h" |
| 12 | + |
| 13 | +#define streq(a, b) (strcmp((a), (b))==0) |
| 14 | +#define MAX_INT32_LEN 11 |
| 15 | + |
| 16 | + |
| 17 | +static char * |
| 18 | +psnprintf(size_t len, const char * fmt, ...) |
| 19 | +{ |
| 20 | + va_list ap; |
| 21 | + char * buf; |
| 22 | + |
| 23 | + buf = palloc(len); |
| 24 | + |
| 25 | + va_start(ap, fmt); |
| 26 | + vsnprintf(buf, len, fmt, ap); |
| 27 | + va_end(ap); |
| 28 | + |
| 29 | + return buf; |
| 30 | +} |
| 31 | + |
| 32 | + |
| 33 | +#define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str)) |
| 34 | + |
| 35 | + |
| 36 | +/* |
| 37 | + * SQL function: format_type(type_oid, typemod) |
| 38 | + * |
| 39 | + * `type_oid' is from pg_type.oid, `typemod' is from |
| 40 | + * pg_attribute.atttypmod. This function will get the type name and |
| 41 | + * format it and the modifier to canonical SQL format, if the type is |
| 42 | + * a standard type. Otherwise you just get pg_type.typname back, |
| 43 | + * double quoted if it contains funny characters. |
| 44 | + * |
| 45 | + * If typemod is null (in the SQL sense) then you won't get any |
| 46 | + * "..(x)" type qualifiers. The result is not technically correct, |
| 47 | + * because the various types interpret missing type modifiers |
| 48 | + * differently, but it can be used as a convenient way to format |
| 49 | + * system catalogs, e.g., pg_aggregate, in psql. |
| 50 | + */ |
| 51 | +Datum |
| 52 | +format_type(PG_FUNCTION_ARGS) |
| 53 | +{ |
| 54 | + Oid type_oid; |
| 55 | + bool with_typemod; |
| 56 | + int32 typemod = 0; |
| 57 | + char * buf; |
| 58 | + char * name; |
| 59 | + Oid array_base_type; |
| 60 | + int16 typlen; |
| 61 | + bool is_array; |
| 62 | + HeapTuple tuple; |
| 63 | + |
| 64 | + if (PG_ARGISNULL(0)) |
| 65 | + PG_RETURN_NULL(); |
| 66 | + |
| 67 | + type_oid = DatumGetObjectId(PG_GETARG_DATUM(0)); |
| 68 | + |
| 69 | + with_typemod = !PG_ARGISNULL(1); |
| 70 | + if (with_typemod) |
| 71 | + typemod = PG_GETARG_INT32(1); |
| 72 | + |
| 73 | + tuple = SearchSysCacheTuple(TYPEOID, ObjectIdGetDatum(type_oid), |
| 74 | + 0, 0, 0); |
| 75 | + |
| 76 | + if (!HeapTupleIsValid(tuple)) |
| 77 | + PG_RETURN_TEXT_P(_textin("???")); |
| 78 | + |
| 79 | + array_base_type = ((Form_pg_type) GETSTRUCT(tuple))->typelem; |
| 80 | + typlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen; |
| 81 | + if (array_base_type != 0 && typlen < 0) |
| 82 | + { |
| 83 | + tuple = SearchSysCacheTuple(TYPEOID, |
| 84 | + ObjectIdGetDatum(array_base_type), |
| 85 | + 0, 0, 0); |
| 86 | + if (!HeapTupleIsValid(tuple)) |
| 87 | + PG_RETURN_TEXT_P(_textin("???[]")); |
| 88 | + is_array = true; |
| 89 | + } |
| 90 | + else |
| 91 | + is_array = false; |
| 92 | + |
| 93 | + |
| 94 | + name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname); |
| 95 | + |
| 96 | + if (streq(name, "bit")) |
| 97 | + { |
| 98 | + if (with_typemod) |
| 99 | + buf = psnprintf(5 + MAX_INT32_LEN + 1, "bit(%d)", (int) typemod - 4); |
| 100 | + else |
| 101 | + buf = pstrdup("bit"); |
| 102 | + } |
| 103 | + |
| 104 | + else if (streq(name, "bool")) |
| 105 | + buf = pstrdup("boolean"); |
| 106 | + |
| 107 | + else if (streq(name, "bpchar")) |
| 108 | + { |
| 109 | + if (with_typemod) |
| 110 | + buf = psnprintf(11 + MAX_INT32_LEN + 1, "character(%d)", (int) typemod - 4); |
| 111 | + else |
| 112 | + buf = pstrdup("character"); |
| 113 | + } |
| 114 | + |
| 115 | + /* This char type is the single-byte version. You have to |
| 116 | + * double-quote it to get at it in the parser. */ |
| 117 | + else if (streq(name, "char")) |
| 118 | + buf = pstrdup("\"char\""); |
| 119 | +#if 0 |
| 120 | + /* The parser has these backwards, so leave as is for now. */ |
| 121 | + else if (streq(name, "float4")) |
| 122 | + buf = pstrdup("real"); |
| 123 | + |
| 124 | + else if (streq(name, "float8")) |
| 125 | + buf = pstrdup("double precision"); |
| 126 | +#endif |
| 127 | + else if (streq(name, "int2")) |
| 128 | + buf = pstrdup("smallint"); |
| 129 | + |
| 130 | + else if (streq(name, "int4")) |
| 131 | + buf = pstrdup("integer"); |
| 132 | + |
| 133 | + else if (streq(name, "int8")) |
| 134 | + buf = pstrdup("bigint"); |
| 135 | + |
| 136 | + else if (streq(name, "numeric")) |
| 137 | + { |
| 138 | + if (with_typemod) |
| 139 | + buf = psnprintf(10 + 2 * MAX_INT32_LEN + 1, "numeric(%d,%d)", |
| 140 | + ((typemod - VARHDRSZ) >> 16) & 0xffff, |
| 141 | + (typemod - VARHDRSZ) & 0xffff); |
| 142 | + else |
| 143 | + buf = pstrdup("numeric"); |
| 144 | + } |
| 145 | + |
| 146 | + else if (streq(name, "timetz")) |
| 147 | + buf = pstrdup("time with time zone"); |
| 148 | + |
| 149 | + else if (streq(name, "varbit")) |
| 150 | + { |
| 151 | + if (with_typemod) |
| 152 | + buf = psnprintf(13 + MAX_INT32_LEN + 1, "bit varying(%d)", (int) typemod - 4); |
| 153 | + else |
| 154 | + buf = pstrdup("bit varying"); |
| 155 | + } |
| 156 | + |
| 157 | + else if (streq(name, "varchar")) |
| 158 | + { |
| 159 | + if (with_typemod) |
| 160 | + buf = psnprintf(19 + MAX_INT32_LEN + 1, "character varying(%d)", (int) typemod - 4); |
| 161 | + else |
| 162 | + buf = pstrdup("character varying"); |
| 163 | + } |
| 164 | + |
| 165 | + else |
| 166 | + { |
| 167 | + if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name) |
| 168 | + || isdigit((int) name[0])) |
| 169 | + buf = psnprintf(strlen(name) + 3, "\"%s\"", name); |
| 170 | + else |
| 171 | + buf = name; |
| 172 | + } |
| 173 | + |
| 174 | + if (is_array) |
| 175 | + { |
| 176 | + char * buf2 = psnprintf(strlen(buf) + 3, "%s[]", buf); |
| 177 | + buf = buf2; |
| 178 | + } |
| 179 | + |
| 180 | + PG_RETURN_TEXT_P(_textin(buf)); |
| 181 | +} |
0 commit comments