Commit 9bc15d49 authored by Tom Lane's avatar Tom Lane

Update examples of type coercion rules --- some of them no longer worked

as the example claimed, because of changes elsewhere in the system.
parent e3b3eb20
...@@ -23,7 +23,7 @@ using <emphasis>explicit</emphasis> type coercion. ...@@ -23,7 +23,7 @@ using <emphasis>explicit</emphasis> type coercion.
<para> <para>
This chapter introduces the <productname>PostgreSQL</productname> This chapter introduces the <productname>PostgreSQL</productname>
type conversion mechanisms and conventions. type conversion mechanisms and conventions.
Refer to the relevant sections in the <xref linkend="datatype"> and <xref linkend="functions"> Refer to the relevant sections in <xref linkend="datatype"> and <xref linkend="functions">
for more information on specific data types and allowed functions and for more information on specific data types and allowed functions and
operators. operators.
</para> </para>
...@@ -43,8 +43,8 @@ has an associated data type which determines its behavior and allowed usage. ...@@ -43,8 +43,8 @@ has an associated data type which determines its behavior and allowed usage.
<productname>PostgreSQL</productname> has an extensible type system that is <productname>PostgreSQL</productname> has an extensible type system that is
much more general and flexible than other <acronym>RDBMS</acronym> implementations. much more general and flexible than other <acronym>RDBMS</acronym> implementations.
Hence, most type conversion behavior in <productname>PostgreSQL</productname> Hence, most type conversion behavior in <productname>PostgreSQL</productname>
should be governed by general rules rather than by ad-hoc heuristics to allow should be governed by general rules rather than by ad-hoc heuristics, to allow
mixed-type expressions to be meaningful, even with user-defined types. mixed-type expressions to be meaningful even with user-defined types.
</para> </para>
<para> <para>
...@@ -64,8 +64,8 @@ tgl=> SELECT text 'Origin' AS "Label", point '(0,0)' AS "Value"; ...@@ -64,8 +64,8 @@ tgl=> SELECT text 'Origin' AS "Label", point '(0,0)' AS "Value";
(1 row) (1 row)
</screen> </screen>
has two strings, of type <type>text</type> and <type>point</type>. has two literal constants, of type <type>text</type> and <type>point</type>.
If a type is not specified for a string, then the placeholder type If a type is not specified for a string literal, then the placeholder type
<firstterm>unknown</firstterm> is assigned initially, to be resolved in later <firstterm>unknown</firstterm> is assigned initially, to be resolved in later
stages as described below. stages as described below.
</para> </para>
...@@ -218,7 +218,7 @@ should use this new function and will no longer do the implicit conversion using ...@@ -218,7 +218,7 @@ should use this new function and will no longer do the implicit conversion using
<para> <para>
The operand types of an operator invocation are resolved following The operand types of an operator invocation are resolved following
to the procedure below. Note that this procedure is indirectly affected the procedure below. Note that this procedure is indirectly affected
by the precedence of the involved operators. See <xref by the precedence of the involved operators. See <xref
linkend="sql-precedence"> for more information. linkend="sql-precedence"> for more information.
</para> </para>
...@@ -283,7 +283,7 @@ If only one candidate remains, use it; else continue to the next step. ...@@ -283,7 +283,7 @@ If only one candidate remains, use it; else continue to the next step.
<para> <para>
If any input arguments are <quote>unknown</quote>, check the type If any input arguments are <quote>unknown</quote>, check the type
categories accepted at those argument positions by the remaining categories accepted at those argument positions by the remaining
candidates. At each position, try the "string" category if any candidates. At each position, select the "string" category if any
candidate accepts that category (this bias towards string is appropriate candidate accepts that category (this bias towards string is appropriate
since an unknown-type literal does look like a string). Otherwise, if since an unknown-type literal does look like a string). Otherwise, if
all the remaining candidates accept the same type category, select that all the remaining candidates accept the same type category, select that
...@@ -366,7 +366,7 @@ Strings with unspecified type are matched with likely operator candidates. ...@@ -366,7 +366,7 @@ Strings with unspecified type are matched with likely operator candidates.
</para> </para>
<para> <para>
One unspecified argument: An example with one unspecified argument:
<screen> <screen>
tgl=> SELECT text 'abc' || 'def' AS "Text and Unknown"; tgl=> SELECT text 'abc' || 'def' AS "Text and Unknown";
Text and Unknown Text and Unknown
...@@ -405,34 +405,50 @@ type to resolve the unknown literals to. ...@@ -405,34 +405,50 @@ type to resolve the unknown literals to.
</example> </example>
<example> <example>
<title>Factorial Operator Type Resolution</title> <title>Absolute-Value and Factorial Operator Type Resolution</title>
<para> <para>
This example illustrates an interesting result. Traditionally, the The <productname>PostgreSQL</productname> operator catalog has several
factorial operator is defined for integers only. The <productname>PostgreSQL</productname> entries for the prefix operator <literal>@</>, all of which implement
operator catalog has only one entry for factorial, taking an integer operand. absolute-value operations for various numeric datatypes. One of these
If given a non-integer numeric argument, <productname>PostgreSQL</productname> entries is for type <type>float8</type>, which is the preferred type in
will try to convert that argument to an integer for evaluation of the the numeric category. Therefore, <productname>PostgreSQL</productname>
factorial. will use that entry when faced with a non-numeric input:
<screen> <screen>
tgl=> SELECT (4.3 !); tgl=> select @ text '-4.5' as "abs";
?column? abs
---------- -----
24 4.5
(1 row) (1 row)
</screen> </screen>
Here the system has performed an implicit text-to-float8 conversion
before applying the chosen operator. We can verify that float8 and
not some other type was used:
<screen>
tgl=> select @ text '-4.5e500' as "abs";
ERROR: Input '-4.5e500' is out of range for float8
</screen>
</para>
<note>
<para> <para>
Of course, this leads to a mathematically suspect result, On the other hand, the postfix operator <literal>!</> (factorial)
since in principle the factorial of a non-integer is not defined. is defined only for integer datatypes, not for float8. So, if we
However, the role of a database is not to teach mathematics, but try a similar case with <literal>!</>, we get:
to be a tool for data manipulation. If a user chooses to take the <screen>
factorial of a floating point number, <productname>PostgreSQL</productname> tgl=> select text '44' ! as "factorial";
will try to oblige. ERROR: Unable to identify a postfix operator '!' for type 'text'
</para> You may need to add parentheses or an explicit cast
</note> </screen>
This happens because the system can't decide which of the several
possible <literal>!</> operators should be preferred. We can help
it out with an explicit cast:
<screen>
tgl=> select cast(text '44' as int8) ! as "factorial";
factorial
---------------------
2673996885588443136
(1 row)
</screen>
</para> </para>
</example> </example>
...@@ -507,13 +523,14 @@ If only one candidate remains, use it; else continue to the next step. ...@@ -507,13 +523,14 @@ If only one candidate remains, use it; else continue to the next step.
<para> <para>
If any input arguments are <type>unknown</type>, check the type categories accepted If any input arguments are <type>unknown</type>, check the type categories accepted
at those argument positions by the remaining candidates. At each position, at those argument positions by the remaining candidates. At each position,
try the <type>string</type> category if any candidate accepts that category (this bias towards string select the <type>string</type> category if any candidate accepts that category
(this bias towards string
is appropriate since an unknown-type literal does look like a string). is appropriate since an unknown-type literal does look like a string).
Otherwise, if all the remaining candidates accept the same type category, Otherwise, if all the remaining candidates accept the same type category,
select that category; otherwise fail because select that category; otherwise fail because
the correct choice cannot be deduced without more clues. Also note whether the correct choice cannot be deduced without more clues. Also note whether
any of the candidates accept a preferred data type within the selected category. any of the candidates accept a preferred data type within the selected category.
Now discard operator candidates that do not accept the selected type category; Now discard candidates that do not accept the selected type category;
furthermore, if any candidate accepts a preferred type at a given argument furthermore, if any candidate accepts a preferred type at a given argument
position, discard candidates that accept non-preferred types for that position, discard candidates that accept non-preferred types for that
argument. argument.
...@@ -536,7 +553,8 @@ then fail. ...@@ -536,7 +553,8 @@ then fail.
<title>Factorial Function Argument Type Resolution</title> <title>Factorial Function Argument Type Resolution</title>
<para> <para>
There is only one factorial function defined in the <classname>pg_proc</classname> catalog. There is only one <function>int4fac</function> function defined in the
<classname>pg_proc</classname> catalog.
So the following query automatically converts the <type>int2</type> argument So the following query automatically converts the <type>int2</type> argument
to <type>int4</type>: to <type>int4</type>:
...@@ -619,7 +637,7 @@ tgl=> SELECT substr(1234, 3); ...@@ -619,7 +637,7 @@ tgl=> SELECT substr(1234, 3);
34 34
(1 row) (1 row)
</screen> </screen>
actually executes as which actually executes as
<screen> <screen>
tgl=> SELECT substr(text(1234), 3); tgl=> SELECT substr(text(1234), 3);
substr substr
...@@ -637,6 +655,12 @@ system catalog. ...@@ -637,6 +655,12 @@ system catalog.
<sect1 id="typeconv-query"> <sect1 id="typeconv-query">
<title>Query Targets</title> <title>Query Targets</title>
<para>
Values to be inserted into a table are coerced to the destination
column's datatype according to the
following steps.
</para>
<procedure> <procedure>
<title>Query Target Type Resolution</title> <title>Query Target Type Resolution</title>
...@@ -666,33 +690,36 @@ passing the column's declared length as the second parameter. ...@@ -666,33 +690,36 @@ passing the column's declared length as the second parameter.
</procedure> </procedure>
<example> <example>
<title><type>varchar</type> Storage Type Conversion</title> <title><type>character</type> Storage Type Conversion</title>
<para> <para>
For a target column declared as <type>varchar(4)</type> the following query For a target column declared as <type>character(20)</type> the following query
ensures that the target is sized correctly: ensures that the target is sized correctly:
<screen> <screen>
tgl=> CREATE TABLE vv (v varchar(4)); tgl=> CREATE TABLE vv (v character(20));
CREATE CREATE
tgl=> INSERT INTO vv SELECT 'abc' || 'def'; tgl=> INSERT INTO vv SELECT 'abc' || 'def';
INSERT 392905 1 INSERT 392905 1
tgl=> SELECT * FROM vv; tgl=> SELECT v, length(v) FROM vv;
v v | length
------ ----------------------+--------
abcd abcdef | 20
(1 row) (1 row)
</screen> </screen>
What has really happened here is that the two unknown literals are resolved What has really happened here is that the two unknown literals are resolved
to <type>text</type> by default, allowing the <literal>||</literal> operator to be to <type>text</type> by default, allowing the <literal>||</literal> operator
resolved as <type>text</type> concatenation. Then the <type>text</type> result of the operator to be resolved as <type>text</type> concatenation. Then the <type>text</type>
is coerced to <type>varchar</type> to match the target column type. (But, since the result of the operator is coerced to <type>bpchar</type> (<quote>blank-padded
parser knows that <type>text</type> and <type>varchar</type> are binary-compatible, this coercion char</>, the internal name of the character datatype) to match the target
is implicit and does not insert any real function call.) Finally, the column type. (Since the parser knows that <type>text</type> and
sizing function <literal>varchar(varchar, integer)</literal> is found in the system <type>bpchar</type> are binary-compatible, this coercion is implicit and does
catalogs and applied to the operator's result and the stored column length. not insert any real function call.) Finally, the sizing function
This type-specific function performs the desired truncation. <literal>bpchar(bpchar, integer)</literal> is found in the system catalogs
and applied to the operator's result and the stored column length. This
type-specific function performs the required length check and addition of
padding spaces.
</para> </para>
</example> </example>
</sect1> </sect1>
...@@ -701,10 +728,13 @@ This type-specific function performs the desired truncation. ...@@ -701,10 +728,13 @@ This type-specific function performs the desired truncation.
<title><literal>UNION</> and <literal>CASE</> Constructs</title> <title><literal>UNION</> and <literal>CASE</> Constructs</title>
<para> <para>
The <literal>UNION</> and <literal>CASE</> constructs must match up possibly dissimilar types to SQL <literal>UNION</> constructs must match up possibly dissimilar types to
become a single result set. The resolution algorithm is applied separately to become a single result set. The resolution algorithm is applied separately
each output column of a union. <literal>CASE</> uses the identical algorithm to match to each output column of a union query. The <literal>INTERSECT</> and
up its result expressions. <literal>EXCEPT</> constructs resolve dissimilar types in the same way as
<literal>UNION</>.
A <literal>CASE</> construct also uses the identical algorithm to match up its
component expressions and select a result datatype.
</para> </para>
<procedure> <procedure>
<title><literal>UNION</> and <literal>CASE</> Type Resolution</title> <title><literal>UNION</> and <literal>CASE</> Type Resolution</title>
...@@ -768,6 +798,8 @@ tgl=> SELECT 1.2 AS "Double" UNION SELECT 1; ...@@ -768,6 +798,8 @@ tgl=> SELECT 1.2 AS "Double" UNION SELECT 1;
1.2 1.2
(2 rows) (2 rows)
</screen> </screen>
The literal <literal>1.2</> is of type <type>double precision</>,
the preferred type in the numeric category, so that type is used.
</para> </para>
</example> </example>
...@@ -776,7 +808,7 @@ tgl=> SELECT 1.2 AS "Double" UNION SELECT 1; ...@@ -776,7 +808,7 @@ tgl=> SELECT 1.2 AS "Double" UNION SELECT 1;
<para> <para>
Here the output type of the union is forced to match the type of Here the output type of the union is forced to match the type of
the first/top clause in the union: the first clause in the union:
<screen> <screen>
tgl=> SELECT 1 AS "All integers" tgl=> SELECT 1 AS "All integers"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment