mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
Add section explaining unspecified expression evaluation order.
This commit is contained in:
parent
1731048c12
commit
bf886d5baf
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/syntax.sgml,v 1.60 2002/04/25 20:14:43 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/syntax.sgml,v 1.61 2002/06/01 20:56:55 petere Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="sql-syntax">
|
<chapter id="sql-syntax">
|
||||||
@ -44,7 +44,6 @@ $Header: /cvsroot/pgsql/doc/src/sgml/syntax.sgml,v 1.60 2002/04/25 20:14:43 tgl
|
|||||||
whitespace.
|
whitespace.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<informalexample id="sql-syntax-ex-commands">
|
|
||||||
<para>
|
<para>
|
||||||
For example, the following is (syntactically) valid SQL input:
|
For example, the following is (syntactically) valid SQL input:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
@ -56,7 +55,6 @@ INSERT INTO MY_TABLE VALUES (3, 'hi there');
|
|||||||
is not required; more than one command can be on a line, and
|
is not required; more than one command can be on a line, and
|
||||||
commands can usefully be split across lines).
|
commands can usefully be split across lines).
|
||||||
</para>
|
</para>
|
||||||
</informalexample>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The SQL syntax is not very consistent regarding what tokens
|
The SQL syntax is not very consistent regarding what tokens
|
||||||
@ -328,7 +326,6 @@ SELECT 'foo' 'bar';
|
|||||||
characters embedded in the constant.
|
characters embedded in the constant.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<informalexample>
|
|
||||||
<para>
|
<para>
|
||||||
These are some examples of valid floating-point constants:
|
These are some examples of valid floating-point constants:
|
||||||
<literallayout>
|
<literallayout>
|
||||||
@ -339,7 +336,6 @@ SELECT 'foo' 'bar';
|
|||||||
1.925e-3
|
1.925e-3
|
||||||
</literallayout>
|
</literallayout>
|
||||||
</para>
|
</para>
|
||||||
</informalexample>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Floating-point constants are of type <type>DOUBLE
|
Floating-point constants are of type <type>DOUBLE
|
||||||
@ -621,6 +617,184 @@ CAST ( '<replaceable>string</replaceable>' AS <replaceable>type</replaceable> )
|
|||||||
analysis and is effectively replaced by whitespace.
|
analysis and is effectively replaced by whitespace.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="sql-precedence">
|
||||||
|
<title>Lexical Precedence</title>
|
||||||
|
|
||||||
|
<indexterm zone="sql-precedence">
|
||||||
|
<primary>operators</primary>
|
||||||
|
<secondary>precedence</secondary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The precedence and associativity of the operators is hard-wired
|
||||||
|
into the parser. Most operators have the same precedence and are
|
||||||
|
left-associative. This may lead to non-intuitive behavior; for
|
||||||
|
example the Boolean operators <literal><</> and <literal>></> have a different
|
||||||
|
precedence than the Boolean operators <literal><=</> and <literal>>=</>. Also,
|
||||||
|
you will sometimes need to add parentheses when using combinations
|
||||||
|
of binary and unary operators. For instance
|
||||||
|
<programlisting>
|
||||||
|
SELECT 5 ! - 6;
|
||||||
|
</programlisting>
|
||||||
|
will be parsed as
|
||||||
|
<programlisting>
|
||||||
|
SELECT 5 ! (- 6);
|
||||||
|
</programlisting>
|
||||||
|
because the parser has no idea -- until it is too late -- that
|
||||||
|
<token>!</token> is defined as a postfix operator, not an infix one.
|
||||||
|
To get the desired behavior in this case, you must write
|
||||||
|
<programlisting>
|
||||||
|
SELECT (5 !) - 6;
|
||||||
|
</programlisting>
|
||||||
|
This is the price one pays for extensibility.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<table tocentry="1">
|
||||||
|
<title>Operator Precedence (decreasing)</title>
|
||||||
|
|
||||||
|
<tgroup cols="3">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Operator/Element</entry>
|
||||||
|
<entry>Associativity</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry><token>.</token></entry>
|
||||||
|
<entry>left</entry>
|
||||||
|
<entry>table/column name separator</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>::</token></entry>
|
||||||
|
<entry>left</entry>
|
||||||
|
<entry><productname>PostgreSQL</productname>-style typecast</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>[</token> <token>]</token></entry>
|
||||||
|
<entry>left</entry>
|
||||||
|
<entry>array element selection</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>-</token></entry>
|
||||||
|
<entry>right</entry>
|
||||||
|
<entry>unary minus</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>^</token></entry>
|
||||||
|
<entry>left</entry>
|
||||||
|
<entry>exponentiation</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>*</token> <token>/</token> <token>%</token></entry>
|
||||||
|
<entry>left</entry>
|
||||||
|
<entry>multiplication, division, modulo</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>+</token> <token>-</token></entry>
|
||||||
|
<entry>left</entry>
|
||||||
|
<entry>addition, subtraction</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>IS</token></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>test for TRUE, FALSE, UNKNOWN, NULL</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>ISNULL</token></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>test for NULL</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>NOTNULL</token></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>test for NOT NULL</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>(any other)</entry>
|
||||||
|
<entry>left</entry>
|
||||||
|
<entry>all other native and user-defined operators</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>IN</token></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>set membership</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>BETWEEN</token></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>containment</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>OVERLAPS</token></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>time interval overlap</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>LIKE</token> <token>ILIKE</token></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>string pattern matching</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token><</token> <token>></token></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>less than, greater than</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>=</token></entry>
|
||||||
|
<entry>right</entry>
|
||||||
|
<entry>equality, assignment</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>NOT</token></entry>
|
||||||
|
<entry>right</entry>
|
||||||
|
<entry>logical negation</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>AND</token></entry>
|
||||||
|
<entry>left</entry>
|
||||||
|
<entry>logical conjunction</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><token>OR</token></entry>
|
||||||
|
<entry>left</entry>
|
||||||
|
<entry>logical disjunction</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Note that the operator precedence rules also apply to user-defined
|
||||||
|
operators that have the same names as the built-in operators
|
||||||
|
mentioned above. For example, if you define a
|
||||||
|
<quote>+</quote> operator for some custom data type it will have
|
||||||
|
the same precedence as the built-in <quote>+</quote> operator, no
|
||||||
|
matter what yours does.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="sql-naming">
|
<sect1 id="sql-naming">
|
||||||
@ -1256,185 +1430,38 @@ FROM states;
|
|||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
</sect1>
|
<sect2>
|
||||||
|
<title>Expression Evaluation</title>
|
||||||
|
|
||||||
<sect1 id="sql-precedence">
|
|
||||||
<title>Lexical Precedence</title>
|
|
||||||
|
|
||||||
<indexterm zone="sql-precedence">
|
|
||||||
<primary>operators</primary>
|
|
||||||
<secondary>precedence</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The precedence and associativity of the operators is hard-wired
|
The order of evaluation of subexpressions is not defined. In
|
||||||
into the parser. Most operators have the same precedence and are
|
particular, subexpressions are not necessarily evaluated
|
||||||
left-associative. This may lead to non-intuitive behavior; for
|
left-to-right, right-to-left, or according to the lexical
|
||||||
example the Boolean operators <literal><</> and <literal>></> have a different
|
precedence rules.
|
||||||
precedence than the Boolean operators <literal><=</> and <literal>>=</>. Also,
|
|
||||||
you will sometimes need to add parentheses when using combinations
|
|
||||||
of binary and unary operators. For instance
|
|
||||||
<programlisting>
|
|
||||||
SELECT 5 ! - 6;
|
|
||||||
</programlisting>
|
|
||||||
will be parsed as
|
|
||||||
<programlisting>
|
|
||||||
SELECT 5 ! (- 6);
|
|
||||||
</programlisting>
|
|
||||||
because the parser has no idea -- until it is too late -- that
|
|
||||||
<token>!</token> is defined as a postfix operator, not an infix one.
|
|
||||||
To get the desired behavior in this case, you must write
|
|
||||||
<programlisting>
|
|
||||||
SELECT (5 !) - 6;
|
|
||||||
</programlisting>
|
|
||||||
This is the price one pays for extensibility.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<table tocentry="1">
|
|
||||||
<title>Operator Precedence (decreasing)</title>
|
|
||||||
|
|
||||||
<tgroup cols="3">
|
|
||||||
<thead>
|
|
||||||
<row>
|
|
||||||
<entry>Operator/Element</entry>
|
|
||||||
<entry>Associativity</entry>
|
|
||||||
<entry>Description</entry>
|
|
||||||
</row>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
<row>
|
|
||||||
<entry><token>.</token></entry>
|
|
||||||
<entry>left</entry>
|
|
||||||
<entry>table/column name separator</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>::</token></entry>
|
|
||||||
<entry>left</entry>
|
|
||||||
<entry><productname>PostgreSQL</productname>-style typecast</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>[</token> <token>]</token></entry>
|
|
||||||
<entry>left</entry>
|
|
||||||
<entry>array element selection</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>-</token></entry>
|
|
||||||
<entry>right</entry>
|
|
||||||
<entry>unary minus</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>^</token></entry>
|
|
||||||
<entry>left</entry>
|
|
||||||
<entry>exponentiation</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>*</token> <token>/</token> <token>%</token></entry>
|
|
||||||
<entry>left</entry>
|
|
||||||
<entry>multiplication, division, modulo</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>+</token> <token>-</token></entry>
|
|
||||||
<entry>left</entry>
|
|
||||||
<entry>addition, subtraction</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>IS</token></entry>
|
|
||||||
<entry></entry>
|
|
||||||
<entry>test for TRUE, FALSE, UNKNOWN, NULL</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>ISNULL</token></entry>
|
|
||||||
<entry></entry>
|
|
||||||
<entry>test for NULL</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>NOTNULL</token></entry>
|
|
||||||
<entry></entry>
|
|
||||||
<entry>test for NOT NULL</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry>(any other)</entry>
|
|
||||||
<entry>left</entry>
|
|
||||||
<entry>all other native and user-defined operators</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>IN</token></entry>
|
|
||||||
<entry></entry>
|
|
||||||
<entry>set membership</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>BETWEEN</token></entry>
|
|
||||||
<entry></entry>
|
|
||||||
<entry>containment</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>OVERLAPS</token></entry>
|
|
||||||
<entry></entry>
|
|
||||||
<entry>time interval overlap</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>LIKE</token> <token>ILIKE</token></entry>
|
|
||||||
<entry></entry>
|
|
||||||
<entry>string pattern matching</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token><</token> <token>></token></entry>
|
|
||||||
<entry></entry>
|
|
||||||
<entry>less than, greater than</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>=</token></entry>
|
|
||||||
<entry>right</entry>
|
|
||||||
<entry>equality, assignment</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>NOT</token></entry>
|
|
||||||
<entry>right</entry>
|
|
||||||
<entry>logical negation</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>AND</token></entry>
|
|
||||||
<entry>left</entry>
|
|
||||||
<entry>logical conjunction</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><token>OR</token></entry>
|
|
||||||
<entry>left</entry>
|
|
||||||
<entry>logical disjunction</entry>
|
|
||||||
</row>
|
|
||||||
</tbody>
|
|
||||||
</tgroup>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Note that the operator precedence rules also apply to user-defined
|
Furthermore, if the result of an expression can be determined by
|
||||||
operators that have the same names as the built-in operators
|
evaluating only some parts of it, then some subexpressions
|
||||||
mentioned above. For example, if you define a
|
might not be evaluated at all. For instance, if one wrote
|
||||||
<quote>+</quote> operator for some custom data type it will have
|
<programlisting>
|
||||||
the same precedence as the built-in <quote>+</quote> operator, no
|
SELECT true OR somefunc();
|
||||||
matter what yours does.
|
</programlisting>
|
||||||
|
then <literal>somefunc()</literal> would (probably) not be called
|
||||||
|
at all. The same would be the case if one wrote
|
||||||
|
<programlisting>
|
||||||
|
SELECT somefunc() OR true;
|
||||||
|
</programlisting>
|
||||||
|
Note that this is not the same as the left-to-right
|
||||||
|
<quote>short-circuiting</quote> of Boolean operators that is found
|
||||||
|
in some programming languages.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As a consequence, it is unwise to use functions with side effects
|
||||||
|
as part of complex expressions.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user