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 *
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)
947948appendStringInfo (buf ,sep );
948949sep = ", " ;
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 ... */
953955if (!IsA (tle -> expr ,Var ))
@@ -1486,16 +1488,16 @@ static void
14861488get_func_expr (Expr * expr ,deparse_context * context )
14871489{
14881490StringInfo buf = context -> buf ;
1491+ Func * func = (Func * ) (expr -> oper );
14891492HeapTuple proctup ;
14901493Form_pg_proc procStruct ;
1494+ char * proname ;
1495+ int32 coercedTypmod ;
14911496List * l ;
14921497char * sep ;
1493- Func * func = (Func * ) (expr -> oper );
1494- char * proname ;
14951498
1496- /* ----------
1499+ /*
14971500 * Get the functions pg_proc tuple
1498- * ----------
14991501 */
15001502proctup = SearchSysCacheTuple (PROCOID ,
15011503ObjectIdGetDatum (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 */
15341586appendStringInfo (buf ,"%s(" ,quote_identifier (proname ));
15351587sep = "" ;
@@ -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 */
15561616static void
15571617get_tle_expr (TargetEntry * tle ,deparse_context * context )
15581618{
15591619Expr * 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
16331631get_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