3
3
* out of its tuple
4
4
*
5
5
* 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 $
7
7
*
8
8
* This software is copyrighted by Jan Wieck - Hamburg.
9
9
*
49
49
#include "optimizer/clauses.h"
50
50
#include "optimizer/tlist.h"
51
51
#include "parser/keywords.h"
52
+ #include "parser/parse_expr.h"
52
53
#include "parser/parsetree.h"
53
54
#include "utils/builtins.h"
54
55
#include "utils/lsyscache.h"
@@ -947,7 +948,8 @@ get_select_query_def(Query *query, deparse_context *context)
947
948
appendStringInfo (buf , sep );
948
949
sep = ", " ;
949
950
950
- get_tle_expr (tle , context );
951
+ /* Do NOT use get_tle_expr here; see its comments! */
952
+ get_rule_expr (tle -> expr , context );
951
953
952
954
/* Check if we must say AS ... */
953
955
if (! IsA (tle -> expr , Var ))
@@ -1486,16 +1488,16 @@ static void
1486
1488
get_func_expr (Expr * expr , deparse_context * context )
1487
1489
{
1488
1490
StringInfo buf = context -> buf ;
1491
+ Func * func = (Func * ) (expr -> oper );
1489
1492
HeapTuple proctup ;
1490
1493
Form_pg_proc procStruct ;
1494
+ char * proname ;
1495
+ int32 coercedTypmod ;
1491
1496
List * l ;
1492
1497
char * sep ;
1493
- Func * func = (Func * ) (expr -> oper );
1494
- char * proname ;
1495
1498
1496
- /* ----------
1499
+ /*
1497
1500
* Get the functions pg_proc tuple
1498
- * ----------
1499
1501
*/
1500
1502
proctup = SearchSysCacheTuple (PROCOID ,
1501
1503
ObjectIdGetDatum (func -> funcid ),
@@ -1527,9 +1529,59 @@ get_func_expr(Expr *expr, deparse_context *context)
1527
1529
}
1528
1530
}
1529
1531
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)
1533
1585
*/
1534
1586
appendStringInfo (buf , "%s(" , quote_identifier (proname ));
1535
1587
sep = "" ;
@@ -1546,99 +1598,37 @@ get_func_expr(Expr *expr, deparse_context *context)
1546
1598
/* ----------
1547
1599
* get_tle_expr
1548
1600
*
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.
1554
1614
* ----------
1555
1615
*/
1556
1616
static void
1557
1617
get_tle_expr (TargetEntry * tle , deparse_context * context )
1558
1618
{
1559
1619
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 ;
1604
1621
1605
1622
/*
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.
1628
1625
*/
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
1633
1631
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 );
1642
1632
}
1643
1633
1644
1634
0 commit comments