00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include <ctype.h>
00019
00020 #include "access/htup_details.h"
00021 #include "catalog/namespace.h"
00022 #include "catalog/pg_type.h"
00023 #include "utils/builtins.h"
00024 #include "utils/lsyscache.h"
00025 #include "utils/numeric.h"
00026 #include "utils/syscache.h"
00027 #include "mb/pg_wchar.h"
00028
00029 #define MAX_INT32_LEN 11
00030
00031 static char *format_type_internal(Oid type_oid, int32 typemod,
00032 bool typemod_given, bool allow_invalid,
00033 bool force_qualify);
00034 static char *printTypmod(const char *typname, int32 typmod, Oid typmodout);
00035 static char *
00036 psnprintf(size_t len, const char *fmt,...)
00037
00038 __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 Datum
00068 format_type(PG_FUNCTION_ARGS)
00069 {
00070 Oid type_oid;
00071 int32 typemod;
00072 char *result;
00073
00074
00075 if (PG_ARGISNULL(0))
00076 PG_RETURN_NULL();
00077
00078 type_oid = PG_GETARG_OID(0);
00079
00080 if (PG_ARGISNULL(1))
00081 result = format_type_internal(type_oid, -1, false, true, false);
00082 else
00083 {
00084 typemod = PG_GETARG_INT32(1);
00085 result = format_type_internal(type_oid, typemod, true, true, false);
00086 }
00087
00088 PG_RETURN_TEXT_P(cstring_to_text(result));
00089 }
00090
00091
00092
00093
00094
00095
00096
00097 char *
00098 format_type_be(Oid type_oid)
00099 {
00100 return format_type_internal(type_oid, -1, false, false, false);
00101 }
00102
00103 char *
00104 format_type_be_qualified(Oid type_oid)
00105 {
00106 return format_type_internal(type_oid, -1, false, false, true);
00107 }
00108
00109
00110
00111
00112 char *
00113 format_type_with_typemod(Oid type_oid, int32 typemod)
00114 {
00115 return format_type_internal(type_oid, typemod, true, false, false);
00116 }
00117
00118 static char *
00119 format_type_internal(Oid type_oid, int32 typemod,
00120 bool typemod_given, bool allow_invalid,
00121 bool force_qualify)
00122 {
00123 bool with_typemod = typemod_given && (typemod >= 0);
00124 HeapTuple tuple;
00125 Form_pg_type typeform;
00126 Oid array_base_type;
00127 bool is_array;
00128 char *buf;
00129
00130 if (type_oid == InvalidOid && allow_invalid)
00131 return pstrdup("-");
00132
00133 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
00134 if (!HeapTupleIsValid(tuple))
00135 {
00136 if (allow_invalid)
00137 return pstrdup("???");
00138 else
00139 elog(ERROR, "cache lookup failed for type %u", type_oid);
00140 }
00141 typeform = (Form_pg_type) GETSTRUCT(tuple);
00142
00143
00144
00145
00146
00147
00148
00149
00150 array_base_type = typeform->typelem;
00151
00152 if (array_base_type != InvalidOid &&
00153 typeform->typstorage != 'p')
00154 {
00155
00156 ReleaseSysCache(tuple);
00157 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_base_type));
00158 if (!HeapTupleIsValid(tuple))
00159 {
00160 if (allow_invalid)
00161 return pstrdup("???[]");
00162 else
00163 elog(ERROR, "cache lookup failed for type %u", type_oid);
00164 }
00165 typeform = (Form_pg_type) GETSTRUCT(tuple);
00166 type_oid = array_base_type;
00167 is_array = true;
00168 }
00169 else
00170 is_array = false;
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 buf = NULL;
00184
00185 switch (type_oid)
00186 {
00187 case BITOID:
00188 if (with_typemod)
00189 buf = printTypmod("bit", typemod, typeform->typmodout);
00190 else if (typemod_given)
00191 {
00192
00193
00194
00195
00196
00197 }
00198 else
00199 buf = pstrdup("bit");
00200 break;
00201
00202 case BOOLOID:
00203 buf = pstrdup("boolean");
00204 break;
00205
00206 case BPCHAROID:
00207 if (with_typemod)
00208 buf = printTypmod("character", typemod, typeform->typmodout);
00209 else if (typemod_given)
00210 {
00211
00212
00213
00214
00215
00216 }
00217 else
00218 buf = pstrdup("character");
00219 break;
00220
00221 case FLOAT4OID:
00222 buf = pstrdup("real");
00223 break;
00224
00225 case FLOAT8OID:
00226 buf = pstrdup("double precision");
00227 break;
00228
00229 case INT2OID:
00230 buf = pstrdup("smallint");
00231 break;
00232
00233 case INT4OID:
00234 buf = pstrdup("integer");
00235 break;
00236
00237 case INT8OID:
00238 buf = pstrdup("bigint");
00239 break;
00240
00241 case NUMERICOID:
00242 if (with_typemod)
00243 buf = printTypmod("numeric", typemod, typeform->typmodout);
00244 else
00245 buf = pstrdup("numeric");
00246 break;
00247
00248 case INTERVALOID:
00249 if (with_typemod)
00250 buf = printTypmod("interval", typemod, typeform->typmodout);
00251 else
00252 buf = pstrdup("interval");
00253 break;
00254
00255 case TIMEOID:
00256 if (with_typemod)
00257 buf = printTypmod("time", typemod, typeform->typmodout);
00258 else
00259 buf = pstrdup("time without time zone");
00260 break;
00261
00262 case TIMETZOID:
00263 if (with_typemod)
00264 buf = printTypmod("time", typemod, typeform->typmodout);
00265 else
00266 buf = pstrdup("time with time zone");
00267 break;
00268
00269 case TIMESTAMPOID:
00270 if (with_typemod)
00271 buf = printTypmod("timestamp", typemod, typeform->typmodout);
00272 else
00273 buf = pstrdup("timestamp without time zone");
00274 break;
00275
00276 case TIMESTAMPTZOID:
00277 if (with_typemod)
00278 buf = printTypmod("timestamp", typemod, typeform->typmodout);
00279 else
00280 buf = pstrdup("timestamp with time zone");
00281 break;
00282
00283 case VARBITOID:
00284 if (with_typemod)
00285 buf = printTypmod("bit varying", typemod, typeform->typmodout);
00286 else
00287 buf = pstrdup("bit varying");
00288 break;
00289
00290 case VARCHAROID:
00291 if (with_typemod)
00292 buf = printTypmod("character varying", typemod, typeform->typmodout);
00293 else
00294 buf = pstrdup("character varying");
00295 break;
00296 }
00297
00298 if (buf == NULL)
00299 {
00300
00301
00302
00303
00304
00305
00306 char *nspname;
00307 char *typname;
00308
00309 if (!force_qualify && TypeIsVisible(type_oid))
00310 nspname = NULL;
00311 else
00312 nspname = get_namespace_name(typeform->typnamespace);
00313
00314 typname = NameStr(typeform->typname);
00315
00316 buf = quote_qualified_identifier(nspname, typname);
00317
00318 if (with_typemod)
00319 buf = printTypmod(buf, typemod, typeform->typmodout);
00320 }
00321
00322 if (is_array)
00323 buf = psnprintf(strlen(buf) + 3, "%s[]", buf);
00324
00325 ReleaseSysCache(tuple);
00326
00327 return buf;
00328 }
00329
00330
00331
00332
00333
00334 static char *
00335 printTypmod(const char *typname, int32 typmod, Oid typmodout)
00336 {
00337 char *res;
00338
00339
00340 Assert(typmod >= 0);
00341
00342 if (typmodout == InvalidOid)
00343 {
00344
00345 res = psnprintf(strlen(typname) + MAX_INT32_LEN + 3, "%s(%d)",
00346 typname, (int) typmod);
00347 }
00348 else
00349 {
00350
00351 char *tmstr;
00352
00353 tmstr = DatumGetCString(OidFunctionCall1(typmodout,
00354 Int32GetDatum(typmod)));
00355 res = psnprintf(strlen(typname) + strlen(tmstr) + 1, "%s%s",
00356 typname, tmstr);
00357 }
00358
00359 return res;
00360 }
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 int32
00378 type_maximum_size(Oid type_oid, int32 typemod)
00379 {
00380 if (typemod < 0)
00381 return -1;
00382
00383 switch (type_oid)
00384 {
00385 case BPCHAROID:
00386 case VARCHAROID:
00387
00388
00389
00390 return (typemod - VARHDRSZ) *
00391 pg_encoding_max_length(GetDatabaseEncoding())
00392 + VARHDRSZ;
00393
00394 case NUMERICOID:
00395 return numeric_maximum_size(typemod);
00396
00397 case VARBITOID:
00398 case BITOID:
00399
00400 return (typemod + (BITS_PER_BYTE - 1)) / BITS_PER_BYTE
00401 + 2 * sizeof(int32);
00402 }
00403
00404
00405 return -1;
00406 }
00407
00408
00409
00410
00411
00412 Datum
00413 oidvectortypes(PG_FUNCTION_ARGS)
00414 {
00415 oidvector *oidArray = (oidvector *) PG_GETARG_POINTER(0);
00416 char *result;
00417 int numargs = oidArray->dim1;
00418 int num;
00419 size_t total;
00420 size_t left;
00421
00422 total = 20 * numargs + 1;
00423 result = palloc(total);
00424 result[0] = '\0';
00425 left = total - 1;
00426
00427 for (num = 0; num < numargs; num++)
00428 {
00429 char *typename = format_type_internal(oidArray->values[num], -1,
00430 false, true, false);
00431 size_t slen = strlen(typename);
00432
00433 if (left < (slen + 2))
00434 {
00435 total += slen + 2;
00436 result = repalloc(result, total);
00437 left += slen + 2;
00438 }
00439
00440 if (num > 0)
00441 {
00442 strcat(result, ", ");
00443 left -= 2;
00444 }
00445 strcat(result, typename);
00446 left -= slen;
00447 }
00448
00449 PG_RETURN_TEXT_P(cstring_to_text(result));
00450 }
00451
00452
00453
00454 static char *
00455 psnprintf(size_t len, const char *fmt,...)
00456 {
00457 va_list ap;
00458 char *buf;
00459
00460 buf = palloc(len);
00461
00462 va_start(ap, fmt);
00463 vsnprintf(buf, len, fmt, ap);
00464 va_end(ap);
00465
00466 return buf;
00467 }