Skip to content

Commit ed1ff84

Browse files
committed
Tweak format_type so that we get good behavior for both column type
display (with a typemod) and function arg/result type display (without a typemod).
1 parent 40015cd commit ed1ff84

File tree

2 files changed

+78
-49
lines changed

2 files changed

+78
-49
lines changed

src/backend/utils/adt/format_type.c

Lines changed: 74 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.22 2001/11/12 21:04:46 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.23 2001/11/19 19:51:20 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -27,29 +27,17 @@
2727
#include "mb/pg_wchar.h"
2828
#endif
2929

30+
3031
#define MASK(b) (1 << (b))
3132

3233
#define MAX_INT32_LEN 11
3334
#define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))
3435

35-
36-
static char *format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid);
37-
38-
39-
static char *
40-
psnprintf(size_t len, const char *fmt,...)
41-
{
42-
va_list ap;
43-
char *buf;
44-
45-
buf = palloc(len);
46-
47-
va_start(ap, fmt);
48-
vsnprintf(buf, len, fmt, ap);
49-
va_end(ap);
50-
51-
return buf;
52-
}
36+
static char *format_type_internal(Oid type_oid, int32 typemod,
37+
bool typemod_given, bool allow_invalid);
38+
static char *psnprintf(size_t len, const char *fmt, ...)
39+
/* This lets gcc check the format string for consistency. */
40+
__attribute__((format(printf, 2, 3)));
5341

5442

5543
/*
@@ -61,11 +49,22 @@ psnprintf(size_t len, const char *fmt,...)
6149
* a standard type. Otherwise you just get pg_type.typname back,
6250
* double quoted if it contains funny characters.
6351
*
64-
* If typemod is null (in the SQL sense) then you won't get any
65-
* "..(x)" type qualifiers. The result is not technically correct,
66-
* because the various types interpret missing type modifiers
67-
* differently, but it can be used as a convenient way to format
68-
* system catalogs, e.g., pg_aggregate, in psql.
52+
* If typemod is NULL then we are formatting a type name in a context where
53+
* no typemod is available, eg a function argument or result type. This
54+
* yields a slightly different result from specifying typemod = -1 in some
55+
* cases. Given typemod = -1 we feel compelled to produce an output that
56+
* the parser will interpret as having typemod -1, so that pg_dump will
57+
* produce CREATE TABLE commands that recreate the original state. But
58+
* given NULL typemod, we assume that the parser's interpretation of
59+
* typemod doesn't matter, and so we are willing to output a slightly
60+
* "prettier" representation of the same type. For example, type = bpchar
61+
* and typemod = NULL gets you "character", whereas typemod = -1 gets you
62+
* "bpchar" --- the former will be interpreted as character(1) by the
63+
* parser, which does not yield typemod -1.
64+
*
65+
* XXX encoding a meaning in typemod = NULL is ugly; it'd have been
66+
* cleaner to make two functions of one and two arguments respectively.
67+
* Not worth changing it now, however.
6968
*/
7069
Datum
7170
format_type(PG_FUNCTION_ARGS)
@@ -74,17 +73,21 @@ format_type(PG_FUNCTION_ARGS)
7473
int32 typemod;
7574
char *result;
7675

76+
/* Since this function is not strict, we must test for null args */
7777
if (PG_ARGISNULL(0))
7878
PG_RETURN_NULL();
7979

8080
type_oid = PG_GETARG_OID(0);
8181

82-
if (!PG_ARGISNULL(1))
83-
typemod = PG_GETARG_INT32(1);
82+
if (PG_ARGISNULL(1))
83+
{
84+
result = format_type_internal(type_oid, -1, false, true);
85+
}
8486
else
85-
typemod = -1; /* default typmod */
86-
87-
result = format_type_internal(type_oid, typemod, true);
87+
{
88+
typemod = PG_GETARG_INT32(1);
89+
result = format_type_internal(type_oid, typemod, true, true);
90+
}
8891

8992
PG_RETURN_DATUM(_textin(result));
9093
}
@@ -98,7 +101,7 @@ format_type(PG_FUNCTION_ARGS)
98101
char *
99102
format_type_be(Oid type_oid)
100103
{
101-
return format_type_internal(type_oid, -1, false);
104+
return format_type_internal(type_oid, -1, false, false);
102105
}
103106

104107
/*
@@ -107,15 +110,16 @@ format_type_be(Oid type_oid)
107110
char *
108111
format_type_with_typemod(Oid type_oid, int32 typemod)
109112
{
110-
return format_type_internal(type_oid, typemod, false);
113+
return format_type_internal(type_oid, typemod, true, false);
111114
}
112115

113116

114117

115118
static char *
116-
format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid)
119+
format_type_internal(Oid type_oid, int32 typemod,
120+
bool typemod_given, bool allow_invalid)
117121
{
118-
bool with_typemod = (typemod >= 0);
122+
bool with_typemod = typemod_given && (typemod >= 0);
119123
HeapTuple tuple;
120124
Oid array_base_type;
121125
int16 typlen;
@@ -140,7 +144,7 @@ format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid)
140144

141145
array_base_type = ((Form_pg_type) GETSTRUCT(tuple))->typelem;
142146
typlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
143-
if (array_base_type != 0 && typlen < 0)
147+
if (array_base_type != InvalidOid && typlen < 0)
144148
{
145149
/* Switch our attention to the array element type */
146150
ReleaseSysCache(tuple);
@@ -167,15 +171,17 @@ format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid)
167171
if (with_typemod)
168172
buf = psnprintf(5 + MAX_INT32_LEN + 1, "bit(%d)",
169173
(int) typemod);
170-
else
174+
else if (typemod_given)
171175
{
172176
/*
173-
* bit with no typmod is not the same as BIT, which means
177+
* bit with typmod -1 is not the same as BIT, which means
174178
* BIT(1) per SQL spec. Report it as the quoted typename
175179
* so that parser will not assign a bogus typmod.
176180
*/
177181
buf = pstrdup("\"bit\"");
178182
}
183+
else
184+
buf = pstrdup("bit");
179185
break;
180186

181187
case BOOLOID:
@@ -186,15 +192,17 @@ format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid)
186192
if (with_typemod)
187193
buf = psnprintf(11 + MAX_INT32_LEN + 1, "character(%d)",
188194
(int) (typemod - VARHDRSZ));
189-
else
195+
else if (typemod_given)
190196
{
191197
/*
192-
* bpchar with no typmod is not the same as CHARACTER,
198+
* bpchar with typmod -1 is not the same as CHARACTER,
193199
* which means CHARACTER(1) per SQL spec. Report it as
194200
* bpchar so that parser will not assign a bogus typmod.
195201
*/
196202
buf = pstrdup("bpchar");
197203
}
204+
else
205+
buf = pstrdup("character");
198206
break;
199207

200208
case CHAROID:
@@ -352,6 +360,10 @@ format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid)
352360

353361
default:
354362
name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname);
363+
/*
364+
* Double-quote the name if it's not a standard identifier.
365+
* Note this is *necessary* for ruleutils.c's use.
366+
*/
355367
if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name)
356368
|| isdigit((unsigned char) name[0]))
357369
buf = psnprintf(strlen(name) + 3, "\"%s\"", name);
@@ -456,13 +468,15 @@ oidvectortypes(PG_FUNCTION_ARGS)
456468

457469
for (num = 0; num < numargs; num++)
458470
{
459-
char *typename = format_type_internal(oidArray[num], -1, true);
471+
char *typename = format_type_internal(oidArray[num], -1,
472+
false, true);
473+
size_t slen = strlen(typename);
460474

461-
if (left < strlen(typename) + 2)
475+
if (left < (slen + 2))
462476
{
463-
total += strlen(typename) + 2;
477+
total += slen + 2;
464478
result = repalloc(result, total);
465-
left += strlen(typename) + 2;
479+
left += slen + 2;
466480
}
467481

468482
if (num > 0)
@@ -471,8 +485,25 @@ oidvectortypes(PG_FUNCTION_ARGS)
471485
left -= 2;
472486
}
473487
strcat(result, typename);
474-
left -= strlen(typename);
488+
left -= slen;
475489
}
476490

477491
PG_RETURN_DATUM(_textin(result));
478492
}
493+
494+
495+
/* snprintf into a palloc'd string */
496+
static char *
497+
psnprintf(size_t len, const char *fmt, ...)
498+
{
499+
va_list ap;
500+
char *buf;
501+
502+
buf = palloc(len);
503+
504+
va_start(ap, fmt);
505+
vsnprintf(buf, len, fmt, ap);
506+
va_end(ap);
507+
508+
return buf;
509+
}

src/backend/utils/adt/ruleutils.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* back to source text
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.86 2001/10/25 05:49:45 momjian Exp $
6+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.87 2001/11/19 19:51:20 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -2054,11 +2054,9 @@ get_func_expr(Expr *expr, deparse_context *context)
20542054
/*
20552055
* Show typename with appropriate length decoration. Note that
20562056
* since exprIsLengthCoercion succeeded, the function's output
2057-
* type is the right thing to use.
2058-
*
2059-
* XXX In general it is incorrect to quote the result of
2060-
* format_type_with_typemod, but are there any special cases where
2061-
* we should do so?
2057+
* type is the right thing to report. Also note we don't need
2058+
* to quote the result of format_type_with_typemod: it takes
2059+
* care of double-quoting any identifier that needs it.
20622060
*/
20632061
typdesc = format_type_with_typemod(procStruct->prorettype,
20642062
coercedTypmod);

0 commit comments

Comments
 (0)