Skip to content

Commit baeef0e

Browse files
committed
Change rule dumper to produce reasonable output for casts that assign
a specific length or precision, such as foo::char(8). Remove erroneous removal of user-written casts at the top level of a SELECT target item.
1 parent 7173c48 commit baeef0e

File tree

1 file changed

+82
-92
lines changed

1 file changed

+82
-92
lines changed

src/backend/utils/adt/ruleutils.c

+82-92
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* out of its tuple
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.43 2000/02/21 20:18:10 tgl Exp $
6+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.44 2000/02/26 21:13:18 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -49,6 +49,7 @@
4949
#include "optimizer/clauses.h"
5050
#include "optimizer/tlist.h"
5151
#include "parser/keywords.h"
52+
#include "parser/parse_expr.h"
5253
#include "parser/parsetree.h"
5354
#include "utils/builtins.h"
5455
#include "utils/lsyscache.h"
@@ -947,7 +948,8 @@ get_select_query_def(Query *query, deparse_context *context)
947948
appendStringInfo(buf, sep);
948949
sep = ", ";
949950

950-
get_tle_expr(tle, context);
951+
/* Do NOT use get_tle_expr here; see its comments! */
952+
get_rule_expr(tle->expr, context);
951953

952954
/* Check if we must say AS ... */
953955
if (! IsA(tle->expr, Var))
@@ -1486,16 +1488,16 @@ static void
14861488
get_func_expr(Expr *expr, deparse_context *context)
14871489
{
14881490
StringInfo buf = context->buf;
1491+
Func *func = (Func *) (expr->oper);
14891492
HeapTuple proctup;
14901493
Form_pg_proc procStruct;
1494+
char *proname;
1495+
int32 coercedTypmod;
14911496
List *l;
14921497
char *sep;
1493-
Func *func = (Func *) (expr->oper);
1494-
char *proname;
14951498

1496-
/* ----------
1499+
/*
14971500
* Get the functions pg_proc tuple
1498-
* ----------
14991501
*/
15001502
proctup = SearchSysCacheTuple(PROCOID,
15011503
ObjectIdGetDatum(func->funcid),
@@ -1527,9 +1529,59 @@ get_func_expr(Expr *expr, deparse_context *context)
15271529
}
15281530
}
15291531

1530-
/* ----------
1531-
* Build a string of proname(args)
1532-
* ----------
1532+
/*
1533+
* Check to see if function is a length-coercion function for some
1534+
* datatype. If so, display the operation as a type cast.
1535+
*/
1536+
if (exprIsLengthCoercion((Node *) expr, &coercedTypmod))
1537+
{
1538+
Node *arg = lfirst(expr->args);
1539+
1540+
/*
1541+
* Strip off any RelabelType on the input, so we don't print
1542+
* redundancies like x::bpchar::char(8).
1543+
* XXX Are there any cases where this is a bad idea?
1544+
*/
1545+
if (IsA(arg, RelabelType))
1546+
arg = ((RelabelType *) arg)->arg;
1547+
appendStringInfoChar(buf, '(');
1548+
get_rule_expr(arg, context);
1549+
appendStringInfo(buf, ")::");
1550+
/*
1551+
* Show typename with appropriate length decoration.
1552+
* Note that since exprIsLengthCoercion succeeded, the function
1553+
* name is the same as its output type name.
1554+
*/
1555+
if (strcmp(proname, "bpchar") == 0)
1556+
{
1557+
if (coercedTypmod > VARHDRSZ)
1558+
appendStringInfo(buf, "char(%d)", coercedTypmod - VARHDRSZ);
1559+
else
1560+
appendStringInfo(buf, "char");
1561+
}
1562+
else if (strcmp(proname, "varchar") == 0)
1563+
{
1564+
if (coercedTypmod > VARHDRSZ)
1565+
appendStringInfo(buf, "varchar(%d)", coercedTypmod - VARHDRSZ);
1566+
else
1567+
appendStringInfo(buf, "varchar");
1568+
}
1569+
else if (strcmp(proname, "numeric") == 0)
1570+
{
1571+
if (coercedTypmod >= VARHDRSZ)
1572+
appendStringInfo(buf, "numeric(%d,%d)",
1573+
((coercedTypmod - VARHDRSZ) >> 16) & 0xffff,
1574+
(coercedTypmod - VARHDRSZ) & 0xffff);
1575+
else
1576+
appendStringInfo(buf, "numeric");
1577+
}
1578+
else
1579+
appendStringInfo(buf, "%s", quote_identifier(proname));
1580+
return;
1581+
}
1582+
1583+
/*
1584+
* Normal function: display as proname(args)
15331585
*/
15341586
appendStringInfo(buf, "%s(", quote_identifier(proname));
15351587
sep = "";
@@ -1546,99 +1598,37 @@ get_func_expr(Expr *expr, deparse_context *context)
15461598
/* ----------
15471599
* get_tle_expr
15481600
*
1549-
* A target list expression is a bit different from a normal expression.
1550-
* If the target column has an atttypmod, the parser usually puts a
1551-
* padding-/cut-function call around the expression itself.
1552-
* We must get rid of it, otherwise dump/reload/dump... would blow up
1553-
* the expressions.
1601+
* In an INSERT or UPDATE targetlist item, the parser may have inserted
1602+
* a length-coercion function call to coerce the value to the right
1603+
* length for the target column. We want to suppress the output of
1604+
* that function call, otherwise dump/reload/dump... would blow up the
1605+
* expression by adding more and more layers of length-coercion calls.
1606+
*
1607+
* As of 7.0, this hack is no longer absolutely essential, because the parser
1608+
* is now smart enough not to add a redundant length coercion function call.
1609+
* But we still suppress the function call just for neatness of displayed
1610+
* rules.
1611+
*
1612+
* Note that this hack must NOT be applied to SELECT targetlist items;
1613+
* any length coercion appearing there is something the user actually wrote.
15541614
* ----------
15551615
*/
15561616
static void
15571617
get_tle_expr(TargetEntry *tle, deparse_context *context)
15581618
{
15591619
Expr *expr = (Expr *) (tle->expr);
1560-
Func *func;
1561-
HeapTuple tup;
1562-
Form_pg_proc procStruct;
1563-
Form_pg_type typeStruct;
1564-
Const *second_arg;
1565-
1566-
/* ----------
1567-
* Check if the result has an atttypmod and if the
1568-
* expression in the targetlist entry is a function call
1569-
* ----------
1570-
*/
1571-
if (tle->resdom->restypmod < 0 ||
1572-
! IsA(expr, Expr) ||
1573-
expr->opType != FUNC_EXPR)
1574-
{
1575-
get_rule_expr(tle->expr, context);
1576-
return;
1577-
}
1578-
1579-
func = (Func *) (expr->oper);
1580-
1581-
/* ----------
1582-
* Get the functions pg_proc tuple
1583-
* ----------
1584-
*/
1585-
tup = SearchSysCacheTuple(PROCOID,
1586-
ObjectIdGetDatum(func->funcid), 0, 0, 0);
1587-
if (!HeapTupleIsValid(tup))
1588-
elog(ERROR, "cache lookup for proc %u failed", func->funcid);
1589-
procStruct = (Form_pg_proc) GETSTRUCT(tup);
1590-
1591-
/* ----------
1592-
* It must be a function with two arguments where the first
1593-
* is of the same type as the return value and the second is
1594-
* an int4.
1595-
* ----------
1596-
*/
1597-
if (procStruct->pronargs != 2 ||
1598-
procStruct->prorettype != procStruct->proargtypes[0] ||
1599-
procStruct->proargtypes[1] != INT4OID)
1600-
{
1601-
get_rule_expr(tle->expr, context);
1602-
return;
1603-
}
1620+
int32 coercedTypmod;
16041621

16051622
/*
1606-
* Furthermore, the name of the function must be the same
1607-
* as the argument/result type name.
1608-
*/
1609-
tup = SearchSysCacheTuple(TYPEOID,
1610-
ObjectIdGetDatum(procStruct->prorettype),
1611-
0, 0, 0);
1612-
if (!HeapTupleIsValid(tup))
1613-
elog(ERROR, "cache lookup for type %u failed",
1614-
procStruct->prorettype);
1615-
typeStruct = (Form_pg_type) GETSTRUCT(tup);
1616-
if (strncmp(NameStr(procStruct->proname),
1617-
NameStr(typeStruct->typname),
1618-
NAMEDATALEN) != 0)
1619-
{
1620-
get_rule_expr(tle->expr, context);
1621-
return;
1622-
}
1623-
1624-
/* ----------
1625-
* Finally (to be totally safe) the second argument must be a
1626-
* const and match the value in the results atttypmod.
1627-
* ----------
1623+
* If top level is a length coercion to the correct length, suppress it;
1624+
* else dump the expression normally.
16281625
*/
1629-
second_arg = (Const *) lsecond(expr->args);
1630-
if (! IsA(second_arg, Const) ||
1631-
DatumGetInt32(second_arg->constvalue) != tle->resdom->restypmod)
1632-
{
1626+
if (tle->resdom->restypmod >= 0 &&
1627+
exprIsLengthCoercion((Node *) expr, &coercedTypmod) &&
1628+
coercedTypmod == tle->resdom->restypmod)
1629+
get_rule_expr((Node *) lfirst(expr->args), context);
1630+
else
16331631
get_rule_expr(tle->expr, context);
1634-
return;
1635-
}
1636-
1637-
/* ----------
1638-
* Whow - got it. Now get rid of the padding function
1639-
* ----------
1640-
*/
1641-
get_rule_expr((Node *) lfirst(expr->args), context);
16421632
}
16431633

16441634

0 commit comments

Comments
 (0)