mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
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.
This commit is contained in:
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user