mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Improve the handling of result type coercions in SQL functions.
Use the parser's standard type coercion machinery to convert the output column(s) of a SQL function's final SELECT or RETURNING to the type(s) they should have according to the function's declared result type. We'll allow any case where an assignment-level coercion is available. Previously, we failed unless the required coercion was a binary-compatible one (and the documentation ignored this, falsely claiming that the types must match exactly). Notably, the coercion now accounts for typmods, so that cases where a SQL function is declared to return a composite type whose columns are typmod-constrained now behave as one would expect. Arguably this aspect is a bug fix, but the overall behavioral change here seems too large to consider back-patching. A nice side-effect is that functions can now be inlined in a few cases where we previously failed to do so because of type mismatches. Discussion: https://postgr.es/m/18929.1574895430@sss.pgh.pa.us
This commit is contained in:
@ -388,11 +388,15 @@ $$ LANGUAGE SQL;
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A <acronym>SQL</acronym> function must return exactly its declared
|
||||
result type. This may require inserting an explicit cast.
|
||||
If the final <literal>SELECT</literal> or <literal>RETURNING</literal>
|
||||
clause in a <acronym>SQL</acronym> function does not return exactly
|
||||
the function's declared result
|
||||
type, <productname>PostgreSQL</productname> will automatically cast
|
||||
the value to the required type, if that is possible with an implicit
|
||||
or assignment cast. Otherwise, you must write an explicit cast.
|
||||
For example, suppose we wanted the
|
||||
previous <function>add_em</function> function to return
|
||||
type <type>float8</type> instead. This won't work:
|
||||
type <type>float8</type> instead. It's sufficient to write
|
||||
|
||||
<programlisting>
|
||||
CREATE FUNCTION add_em(integer, integer) RETURNS float8 AS $$
|
||||
@ -400,16 +404,10 @@ CREATE FUNCTION add_em(integer, integer) RETURNS float8 AS $$
|
||||
$$ LANGUAGE SQL;
|
||||
</programlisting>
|
||||
|
||||
even though in other contexts <productname>PostgreSQL</productname>
|
||||
would be willing to insert an implicit cast to
|
||||
convert <type>integer</type> to <type>float8</type>.
|
||||
We need to write it as
|
||||
|
||||
<programlisting>
|
||||
CREATE FUNCTION add_em(integer, integer) RETURNS float8 AS $$
|
||||
SELECT ($1 + $2)::float8;
|
||||
$$ LANGUAGE SQL;
|
||||
</programlisting>
|
||||
since the <type>integer</type> sum can be implicitly cast
|
||||
to <type>float8</type>.
|
||||
(See <xref linkend="typeconv"/> or <xref linkend="sql-createcast"/>
|
||||
for more about casts.)
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
@ -503,23 +501,24 @@ $$ LANGUAGE SQL;
|
||||
<listitem>
|
||||
<para>
|
||||
The select list order in the query must be exactly the same as
|
||||
that in which the columns appear in the table associated
|
||||
with the composite type. (Naming the columns, as we did above,
|
||||
that in which the columns appear in the composite type.
|
||||
(Naming the columns, as we did above,
|
||||
is irrelevant to the system.)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
We must ensure each expression's type matches the corresponding
|
||||
column of the composite type, inserting a cast if necessary.
|
||||
We must ensure each expression's type can be cast to that of
|
||||
the corresponding column of the composite type.
|
||||
Otherwise we'll get errors like this:
|
||||
<screen>
|
||||
<computeroutput>
|
||||
ERROR: function declared to return emp returns varchar instead of text at column 1
|
||||
ERROR: return type mismatch in function declared to return emp
|
||||
DETAIL: Final statement returns text instead of point at column 4.
|
||||
</computeroutput>
|
||||
</screen>
|
||||
As with the base-type case, the function will not insert any casts
|
||||
automatically.
|
||||
As with the base-type case, the system will not insert explicit
|
||||
casts automatically, only implicit or assignment casts.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
@ -542,8 +541,7 @@ $$ LANGUAGE SQL;
|
||||
Another example is that if we are trying to write a function that
|
||||
returns a domain over composite, rather than a plain composite type,
|
||||
it is always necessary to write it as returning a single column,
|
||||
since there is no other way to produce a value that is exactly of
|
||||
the domain type.
|
||||
since there is no way to cause a coercion of the whole row result.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -1263,7 +1261,7 @@ SELECT make_array(1, 2) AS intarray, make_array('a'::text, 'b') AS textarray;
|
||||
Without the typecast, you will get errors like this:
|
||||
<screen>
|
||||
<computeroutput>
|
||||
ERROR: could not determine polymorphic type because input has type "unknown"
|
||||
ERROR: could not determine polymorphic type because input has type unknown
|
||||
</computeroutput>
|
||||
</screen>
|
||||
</para>
|
||||
|
Reference in New Issue
Block a user