<productname>PostgreSQL</productname> operator catalog has several
entries for the prefix operator <literal>@</literal>, all of which implement
absolute-value operations for various numeric data types. One of these
entries is for type <type>float8</type>, which is the preferred type in
the numeric category. Therefore, <productname>PostgreSQL</productname>
will use that entry when faced with an <type>unknown</type> input:
<screen>
SELECT @ '-4.5' AS "abs";
abs
-----
4.5
(1 row)
</screen>
Here the system has implicitly resolved the unknown-type literal as type
<type>float8</type> before applying the chosen operator. We can verify that
<type>float8</type> and not some other type was used:
<screen>
SELECT @ '-4.5e500' AS "abs";
ERROR: "-4.5e500" is out of range for type double precision
</screen>
</para>
<para>
On the other hand, the prefix operator <literal>~</literal> (bitwise negation)
is defined only for integer data types, not for <type>float8</type>. So, if we
try a similar case with <literal>~</literal>, we get:
<screen>
SELECT ~ '20' AS "negation";
ERROR: operator is not unique: ~ "unknown"
HINT: Could not choose a best candidate operator. You might need to add
explicit type casts.
</screen>
This happens because the system cannot decide which of the several
possible <literal>~</literal> operators should be preferred. We can help
it out with an explicit cast:
<screen>
SELECT ~ CAST('20' AS int8) AS "negation";
negation
----------
-21
(1 row)
</screen>
</para>
</example>
<example>
<title>Array Inclusion Operator Type Resolution</title>
<para>
Here is another example of resolving an operator with one known and one
unknown input:
<screen>
SELECT array[1,2] <@ '{1,2,3}' as "is subset";
is subset
-----------
t
(1 row)
</screen>
The <productname>PostgreSQL</productname> operator catalog has several
entries for the infix operator <literal><@</literal>, but the only two that
could possibly accept an integer array on the left-hand side are
array inclusion (<type>anyarray</type> <literal><@</literal> <type>anyarray</type>)
and range inclusion (<type>anyelement</type> <literal><@</literal> <type>anyrange</type>).
Since none of these polymorphic pseudo-types (see <xref
linkend="datatype-pseudo"/>) are considered preferred, the parser cannot
resolve the ambiguity on that basis.
However, <xref linkend="op-resol-last-unknown"/> tells
it to assume that the unknown-type literal is of the same type as the other
input, that is, integer array. Now only one of the two operators can match,
so array inclusion is selected. (Had range inclusion been selected, we would
have gotten an error, because the string does not have the right format to be
a range literal.)
</para>
</example>
<example>
<title>Custom Operator on a Domain Type</title>
<para>
Users sometimes try to declare operators applying just to a domain type.
This is possible but is not nearly as useful as it might seem, because the
operator resolution rules are designed to select operators applying to the
domain's base type. As an example consider
<screen>
CREATE DOMAIN mytext AS text CHECK(...);
CREATE FUNCTION mytext_eq_text (mytext, text) RETURNS boolean AS ...;
CREATE OPERATOR = (procedure=mytext_eq_text, leftarg=mytext, rightarg=text);
CREATE TABLE mytable (val mytext);
SELECT * FROM mytable WHERE val = 'foo';
</screen>
This query will not use the custom operator. The parser will first see if
there is a <type>mytext</type> <literal>=</literal> <type>mytext</type> operator
(<xref linkend="op-resol-exact-unknown"/>), which there is not;
then it will consider the domain's base type <type>text</type>, and see if
there is a <type>text</type> <literal>=</literal> <type>text</type> operator
(<xref linkend="op-resol-exact-domain"/>), which there is;
so it resolves the <type>unknown</type>-type literal as <type>text</type> and
uses the <type>text</type> <literal>=</literal> <type>text</type> operator.
The only way to get the custom operator to be used