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 */
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 */
7069Datum
7170format_type (PG_FUNCTION_ARGS )
@@ -74,17 +73,21 @@ format_type(PG_FUNCTION_ARGS)
7473int32 typemod ;
7574char * result ;
7675
76+ /* Since this function is not strict, we must test for null args */
7777if (PG_ARGISNULL (0 ))
7878PG_RETURN_NULL ();
7979
8080type_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+ }
8486else
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
8992PG_RETURN_DATUM (_textin (result ));
9093}
@@ -98,7 +101,7 @@ format_type(PG_FUNCTION_ARGS)
98101char *
99102format_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)
107110char *
108111format_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
115118static 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 );
119123HeapTuple tuple ;
120124Oid array_base_type ;
121125int16 typlen ;
@@ -140,7 +144,7 @@ format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid)
140144
141145array_base_type = ((Form_pg_type )GETSTRUCT (tuple ))-> typelem ;
142146typlen = ((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 */
146150ReleaseSysCache (tuple );
@@ -167,15 +171,17 @@ format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid)
167171if (with_typemod )
168172buf = psnprintf (5 + MAX_INT32_LEN + 1 ,"bit(%d)" ,
169173(int )typemod );
170- else
174+ else if ( typemod_given )
171175{
172176/*
173- * bit withno 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 */
177181buf = pstrdup ("\"bit\"" );
178182}
183+ else
184+ buf = pstrdup ("bit" );
179185break ;
180186
181187case BOOLOID :
@@ -186,15 +192,17 @@ format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid)
186192if (with_typemod )
187193buf = psnprintf (11 + MAX_INT32_LEN + 1 ,"character(%d)" ,
188194(int ) (typemod - VARHDRSZ ));
189- else
195+ else if ( typemod_given )
190196{
191197/*
192- * bpchar withno 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 */
196202buf = pstrdup ("bpchar" );
197203}
204+ else
205+ buf = pstrdup ("character" );
198206break ;
199207
200208case CHAROID :
@@ -352,6 +360,10 @@ format_type_internal(Oid type_oid, int32 typemod, bool allow_invalid)
352360
353361default :
354362name = 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+ */
355367if (strspn (name ,"abcdefghijklmnopqrstuvwxyz0123456789_" )!= strlen (name )
356368|| isdigit ((unsignedchar )name [0 ]))
357369buf = psnprintf (strlen (name )+ 3 ,"\"%s\"" ,name );
@@ -456,13 +468,15 @@ oidvectortypes(PG_FUNCTION_ARGS)
456468
457469for (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 ;
464478result = repalloc (result ,total );
465- left += strlen ( typename ) + 2 ;
479+ left += slen + 2 ;
466480}
467481
468482if (num > 0 )
@@ -471,8 +485,25 @@ oidvectortypes(PG_FUNCTION_ARGS)
471485left -= 2 ;
472486}
473487strcat (result ,typename );
474- left -= strlen ( typename ) ;
488+ left -= slen ;
475489}
476490
477491PG_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+ }