aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-03-17 00:11:05 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-03-17 00:11:05 +0000
commit0f4ff460c479e9c9bff90e8208f0a5272b9925df (patch)
treef22187ef35d7284cbc42f9255c369378d16ffe07 /src/backend/utils/adt/ruleutils.c
parent51d7741db13332523708cd7ac75a8ca60c9d16a9 (diff)
downloadpostgresql-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.c112
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));
}