33 *back to source text
44 *
55 * IDENTIFICATION
6- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.84 2001/10/04 22:00:10 tgl Exp $
6+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.85 2001/10/08 19:55:07 tgl Exp $
77 *
88 * This software is copyrighted by Jan Wieck - Hamburg.
99 *
@@ -130,6 +130,7 @@ static bool find_alias_in_namespace(Node *nsnode, Node *expr,
130130static bool phony_equal (Node * expr1 ,Node * expr2 ,int levelsup );
131131static void get_rule_expr (Node * node ,deparse_context * context );
132132static void get_func_expr (Expr * expr ,deparse_context * context );
133+ static Node * strip_type_coercion (Node * expr ,Oid resultType );
133134static void get_tle_expr (TargetEntry * tle ,deparse_context * context );
134135static void get_const_expr (Const * constval ,deparse_context * context );
135136static void get_sublink_expr (Node * node ,deparse_context * context );
@@ -2038,49 +2039,31 @@ get_func_expr(Expr *expr, deparse_context *context)
20382039if (exprIsLengthCoercion ((Node * )expr ,& coercedTypmod ))
20392040{
20402041Node * arg = lfirst (expr -> args );
2042+ char * typdesc ;
20412043
20422044/*
2043- * Strip off anyRelabelType on the input, so we don't print
2044- * redundancies like x::bpchar::char (8).
2045+ * Strip off anytype coercions on the input, so we don't print
2046+ * redundancies like x::bpchar::character (8).
20452047 *
20462048 * XXX Are there any cases where this is a bad idea?
20472049 */
2048- if ( IsA ( arg ,RelabelType ))
2049- arg = (( RelabelType * ) arg ) -> arg ;
2050+ arg = strip_type_coercion ( arg ,procStruct -> prorettype );
2051+
20502052appendStringInfoChar (buf ,'(' );
20512053get_rule_expr (arg ,context );
2052- appendStringInfo (buf ,")::" );
2053-
20542054/*
20552055 * Show typename with appropriate length decoration. Note that
2056- * since exprIsLengthCoercion succeeded, the function name is the
2057- * same as its output type name.
2056+ * since exprIsLengthCoercion succeeded, the function's output
2057+ * type is the right thing to use.
2058+ *
2059+ * XXX In general it is incorrect to quote the result of
2060+ * format_type_with_typemod, but are there any special cases
2061+ * where we should do so?
20582062 */
2059- if (strcmp (proname ,"bpchar" )== 0 )
2060- {
2061- if (coercedTypmod > (int32 )VARHDRSZ )
2062- appendStringInfo (buf ,"char(%d)" ,coercedTypmod - VARHDRSZ );
2063- else
2064- appendStringInfo (buf ,"char" );
2065- }
2066- else if (strcmp (proname ,"varchar" )== 0 )
2067- {
2068- if (coercedTypmod > (int32 )VARHDRSZ )
2069- appendStringInfo (buf ,"varchar(%d)" ,coercedTypmod - VARHDRSZ );
2070- else
2071- appendStringInfo (buf ,"varchar" );
2072- }
2073- else if (strcmp (proname ,"numeric" )== 0 )
2074- {
2075- if (coercedTypmod >= (int32 )VARHDRSZ )
2076- appendStringInfo (buf ,"numeric(%d,%d)" ,
2077- ((coercedTypmod - VARHDRSZ ) >>16 )& 0xffff ,
2078- (coercedTypmod - VARHDRSZ )& 0xffff );
2079- else
2080- appendStringInfo (buf ,"numeric" );
2081- }
2082- else
2083- appendStringInfo (buf ,"%s" ,quote_identifier (proname ));
2063+ typdesc = format_type_with_typemod (procStruct -> prorettype ,
2064+ coercedTypmod );
2065+ appendStringInfo (buf ,")::%s" ,typdesc );
2066+ pfree (typdesc );
20842067
20852068ReleaseSysCache (proctup );
20862069return ;
@@ -2103,6 +2086,79 @@ get_func_expr(Expr *expr, deparse_context *context)
21032086}
21042087
21052088
2089+ /*
2090+ * strip_type_coercion
2091+ *Strip any type coercions at the top of the given expression tree,
2092+ *as long as they are coercions to the given datatype.
2093+ *
2094+ * A RelabelType node is always a type coercion. A function call is also
2095+ * considered a type coercion if it has one argument and the function name
2096+ * is the same as the (internal) name of its result type.
2097+ *
2098+ * XXX It'd be better if the parsetree retained some explicit indication
2099+ * of the coercion, so we didn't need these heuristics.
2100+ */
2101+ static Node *
2102+ strip_type_coercion (Node * expr ,Oid resultType )
2103+ {
2104+ if (expr == NULL || exprType (expr )!= resultType )
2105+ return expr ;
2106+
2107+ if (IsA (expr ,RelabelType ))
2108+ return strip_type_coercion (((RelabelType * )expr )-> arg ,resultType );
2109+
2110+ if (IsA (expr ,Expr )&& ((Expr * )expr )-> opType == FUNC_EXPR )
2111+ {
2112+ Func * func ;
2113+ HeapTuple procTuple ;
2114+ HeapTuple typeTuple ;
2115+ Form_pg_proc procStruct ;
2116+ Form_pg_type typeStruct ;
2117+
2118+ func = (Func * ) (((Expr * )expr )-> oper );
2119+ Assert (IsA (func ,Func ));
2120+ if (length (((Expr * )expr )-> args )!= 1 )
2121+ return expr ;
2122+ /* Lookup the function in pg_proc */
2123+ procTuple = SearchSysCache (PROCOID ,
2124+ ObjectIdGetDatum (func -> funcid ),
2125+ 0 ,0 ,0 );
2126+ if (!HeapTupleIsValid (procTuple ))
2127+ elog (ERROR ,"cache lookup for proc %u failed" ,func -> funcid );
2128+ procStruct = (Form_pg_proc )GETSTRUCT (procTuple );
2129+ /* Double-check func has one arg and correct result type */
2130+ if (procStruct -> pronargs != 1 ||
2131+ procStruct -> prorettype != resultType )
2132+ {
2133+ ReleaseSysCache (procTuple );
2134+ return expr ;
2135+ }
2136+ /* See if function has same name as its result type */
2137+ typeTuple = SearchSysCache (TYPEOID ,
2138+ ObjectIdGetDatum (procStruct -> prorettype ),
2139+ 0 ,0 ,0 );
2140+ if (!HeapTupleIsValid (typeTuple ))
2141+ elog (ERROR ,"cache lookup for type %u failed" ,
2142+ procStruct -> prorettype );
2143+ typeStruct = (Form_pg_type )GETSTRUCT (typeTuple );
2144+ if (strncmp (NameStr (procStruct -> proname ),
2145+ NameStr (typeStruct -> typname ),
2146+ NAMEDATALEN )!= 0 )
2147+ {
2148+ ReleaseSysCache (procTuple );
2149+ ReleaseSysCache (typeTuple );
2150+ return expr ;
2151+ }
2152+ /* Okay, it is indeed a type-coercion function */
2153+ ReleaseSysCache (procTuple );
2154+ ReleaseSysCache (typeTuple );
2155+ return strip_type_coercion (lfirst (((Expr * )expr )-> args ),resultType );
2156+ }
2157+
2158+ return expr ;
2159+ }
2160+
2161+
21062162/* ----------
21072163 * get_tle_expr
21082164 *