3
3
* back to source text
4
4
*
5
5
* 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 $
7
7
*
8
8
* This software is copyrighted by Jan Wieck - Hamburg.
9
9
*
@@ -130,6 +130,7 @@ static bool find_alias_in_namespace(Node *nsnode, Node *expr,
130
130
static bool phony_equal (Node * expr1 , Node * expr2 , int levelsup );
131
131
static void get_rule_expr (Node * node , deparse_context * context );
132
132
static void get_func_expr (Expr * expr , deparse_context * context );
133
+ static Node * strip_type_coercion (Node * expr , Oid resultType );
133
134
static void get_tle_expr (TargetEntry * tle , deparse_context * context );
134
135
static void get_const_expr (Const * constval , deparse_context * context );
135
136
static void get_sublink_expr (Node * node , deparse_context * context );
@@ -2038,49 +2039,31 @@ get_func_expr(Expr *expr, deparse_context *context)
2038
2039
if (exprIsLengthCoercion ((Node * ) expr , & coercedTypmod ))
2039
2040
{
2040
2041
Node * arg = lfirst (expr -> args );
2042
+ char * typdesc ;
2041
2043
2042
2044
/*
2043
- * Strip off any RelabelType on the input, so we don't print
2044
- * redundancies like x::bpchar::char (8).
2045
+ * Strip off any type coercions on the input, so we don't print
2046
+ * redundancies like x::bpchar::character (8).
2045
2047
*
2046
2048
* XXX Are there any cases where this is a bad idea?
2047
2049
*/
2048
- if ( IsA ( arg , RelabelType ))
2049
- arg = (( RelabelType * ) arg ) -> arg ;
2050
+ arg = strip_type_coercion ( arg , procStruct -> prorettype );
2051
+
2050
2052
appendStringInfoChar (buf , '(' );
2051
2053
get_rule_expr (arg , context );
2052
- appendStringInfo (buf , ")::" );
2053
-
2054
2054
/*
2055
2055
* 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?
2058
2062
*/
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 );
2084
2067
2085
2068
ReleaseSysCache (proctup );
2086
2069
return ;
@@ -2103,6 +2086,79 @@ get_func_expr(Expr *expr, deparse_context *context)
2103
2086
}
2104
2087
2105
2088
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
+
2106
2162
/* ----------
2107
2163
* get_tle_expr
2108
2164
*
0 commit comments