diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2007-03-17 00:11:05 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2007-03-17 00:11:05 +0000 |
commit | 0f4ff460c479e9c9bff90e8208f0a5272b9925df (patch) | |
tree | f22187ef35d7284cbc42f9255c369378d16ffe07 /src/backend/utils/adt/ruleutils.c | |
parent | 51d7741db13332523708cd7ac75a8ca60c9d16a9 (diff) | |
download | postgresql-0f4ff460c479e9c9bff90e8208f0a5272b9925df.tar.gz postgresql-0f4ff460c479e9c9bff90e8208f0a5272b9925df.zip |
Fix up the remaining places where the expression node structure would lose
available information about the typmod of an expression; namely, Const,
ArrayRef, ArrayExpr, and EXPR and ARRAY SubLinks. In the ArrayExpr and
SubLink cases it wasn't really the data structure's fault, but exprTypmod()
being lazy. This seems like a good idea in view of the expected increase in
typmod usage from Teodor's work to allow user-defined types to have typmods.
In particular this responds to the concerns we had about eliminating the
special-purpose hack that exprTypmod() used to have for BPCHAR Consts.
We can now tell whether or not such a Const has been cast to a specific
length, and report or display properly if so.
initdb forced due to changes in stored rules.
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 112 |
1 files changed, 75 insertions, 37 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 9ec0aa56f0a..b1294b6d322 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.253 2007/03/15 23:12:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.254 2007/03/17 00:11:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -170,7 +170,11 @@ static void get_oper_expr(OpExpr *expr, deparse_context *context); static void get_func_expr(FuncExpr *expr, deparse_context *context, bool showimplicit); static void get_agg_expr(Aggref *aggref, deparse_context *context); -static void get_const_expr(Const *constval, deparse_context *context); +static void get_coercion_expr(Node *arg, deparse_context *context, + Oid resulttype, int32 resulttypmod, + Node *parentNode); +static void get_const_expr(Const *constval, deparse_context *context, + bool showtype); static void get_sublink_expr(SubLink *sublink, deparse_context *context); static void get_from_clause(Query *query, const char *prefix, deparse_context *context); @@ -3364,7 +3368,7 @@ get_rule_expr(Node *node, deparse_context *context, break; case T_Const: - get_const_expr((Const *) node, context); + get_const_expr((Const *) node, context, true); break; case T_Param: @@ -3576,14 +3580,10 @@ get_rule_expr(Node *node, deparse_context *context, } else { - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, false, node); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - appendStringInfo(buf, "::%s", - format_type_with_typemod(relabel->resulttype, - relabel->resulttypmod)); + get_coercion_expr(arg, context, + relabel->resulttype, + relabel->resulttypmod, + node); } } break; @@ -3601,13 +3601,9 @@ get_rule_expr(Node *node, deparse_context *context, } else { - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, false, node); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - appendStringInfo(buf, "::%s", - format_type_with_typemod(convert->resulttype, -1)); + get_coercion_expr(arg, context, + convert->resulttype, -1, + node); } } break; @@ -4070,14 +4066,10 @@ get_rule_expr(Node *node, deparse_context *context, } else { - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, false, node); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - appendStringInfo(buf, "::%s", - format_type_with_typemod(ctest->resulttype, - ctest->resulttypmod)); + get_coercion_expr(arg, context, + ctest->resulttype, + ctest->resulttypmod, + node); } } break; @@ -4213,13 +4205,9 @@ get_func_expr(FuncExpr *expr, deparse_context *context, /* Get the typmod if this is a length-coercion function */ (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, '('); - get_rule_expr_paren(arg, context, false, (Node *) expr); - if (!PRETTY_PAREN(context)) - appendStringInfoChar(buf, ')'); - appendStringInfo(buf, "::%s", - format_type_with_typemod(rettype, coercedTypmod)); + get_coercion_expr(arg, context, + rettype, coercedTypmod, + (Node *) expr); return; } @@ -4278,15 +4266,58 @@ get_agg_expr(Aggref *aggref, deparse_context *context) appendStringInfoChar(buf, ')'); } +/* ---------- + * get_coercion_expr + * + * Make a string representation of a value coerced to a specific type + * ---------- + */ +static void +get_coercion_expr(Node *arg, deparse_context *context, + Oid resulttype, int32 resulttypmod, + Node *parentNode) +{ + StringInfo buf = context->buf; + + /* + * Since parse_coerce.c doesn't immediately collapse application of + * length-coercion functions to constants, what we'll typically see + * in such cases is a Const with typmod -1 and a length-coercion + * function right above it. Avoid generating redundant output. + * However, beware of suppressing casts when the user actually wrote + * something like 'foo'::text::char(3). + */ + if (arg && IsA(arg, Const) && + ((Const *) arg)->consttype == resulttype && + ((Const *) arg)->consttypmod == -1) + { + /* Show the constant without normal ::typename decoration */ + get_const_expr((Const *) arg, context, false); + } + else + { + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, '('); + get_rule_expr_paren(arg, context, false, parentNode); + if (!PRETTY_PAREN(context)) + appendStringInfoChar(buf, ')'); + } + appendStringInfo(buf, "::%s", + format_type_with_typemod(resulttype, resulttypmod)); +} /* ---------- * get_const_expr * * Make a string representation of a Const + * + * Note: if showtype is false, the Const is the direct argument of a coercion + * operation with the same target type, and so we should suppress "::typename" + * to avoid redundant output. * ---------- */ static void -get_const_expr(Const *constval, deparse_context *context) +get_const_expr(Const *constval, deparse_context *context, bool showtype) { StringInfo buf = context->buf; Oid typoutput; @@ -4302,8 +4333,11 @@ get_const_expr(Const *constval, deparse_context *context) * Always label the type of a NULL constant to prevent misdecisions * about type when reparsing. */ - appendStringInfo(buf, "NULL::%s", - format_type_with_typemod(constval->consttype, -1)); + appendStringInfo(buf, "NULL"); + if (showtype) + appendStringInfo(buf, "::%s", + format_type_with_typemod(constval->consttype, + constval->consttypmod)); return; } @@ -4376,6 +4410,9 @@ get_const_expr(Const *constval, deparse_context *context) pfree(extval); + if (!showtype) + return; + /* * Append ::typename unless the constant will be implicitly typed as the * right type when it is read in. XXX this code has to be kept in sync @@ -4399,7 +4436,8 @@ get_const_expr(Const *constval, deparse_context *context) } if (needlabel) appendStringInfo(buf, "::%s", - format_type_with_typemod(constval->consttype, -1)); + format_type_with_typemod(constval->consttype, + constval->consttypmod)); } |