Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc6b3c93

Browse files
committed
Make operator precedence follow the SQL standard more closely.
While the SQL standard is pretty vague on the overall topic of operatorprecedence (because it never presents a unified BNF for all expressions),it does seem reasonable to conclude from the spec for <boolean valueexpression> that OR has the lowest precedence, then AND, then NOT, then IStests, then the six standard comparison operators, then everything else(since any non-boolean operator in a WHERE clause would need to be anargument of one of these).We were only sort of on board with that: most notably, while "<" ">" and"=" had properly low precedence, "<=" ">=" and "<>" were treated as genericoperators and so had significantly higher precedence. And "IS" tests wereeven higher precedence than those, which is very clearly wrong per spec.Another problem was that "foo NOT SOMETHING bar" constructs, such as"x NOT LIKE y", were treated inconsistently because of a bisonimplementation artifact: they had the documented precedence with respectto operators to their right, but behaved like NOT (i.e., very low priority)with respect to operators to their left.Fixing the precedence issues is just a small matter of rearranging theprecedence declarations in gram.y, except for the NOT problem, whichrequires adding an additional lookahead case in base_yylex() so that wecan attach a different token precedence to NOT LIKE and allied two-wordoperators.The bulk of this patch is not the bug fix per se, but adding logic toparse_expr.c to allow giving warnings if an expression has changed meaningbecause of these precedence changes. These warnings are off by defaultand are enabled by the new GUC operator_precedence_warning. It's believedthat very few applications will be affected by these changes, but it wasagreed that a warning mechanism is essential to help debug any that are.
1 parent21dcda2 commitc6b3c93

File tree

18 files changed

+723
-95
lines changed

18 files changed

+723
-95
lines changed

‎doc/src/sgml/config.sgml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6816,6 +6816,29 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
68166816
</listitem>
68176817
</varlistentry>
68186818

6819+
<varlistentry id="guc-operator-precedence-warning" xreflabel="operator_precedence_warning">
6820+
<term><varname>operator_precedence_warning</varname> (<type>boolean</type>)
6821+
<indexterm>
6822+
<primary><varname>operator_precedence_warning</> configuration parameter</primary>
6823+
</indexterm>
6824+
</term>
6825+
<listitem>
6826+
<para>
6827+
When on, the parser will emit a warning for any construct that might
6828+
have changed meanings since <productname>PostgreSQL</> 9.4 as a result
6829+
of changes in operator precedence. This is useful for auditing
6830+
applications to see if precedence changes have broken anything; but it
6831+
is not meant to be kept turned on in production, since it will warn
6832+
about some perfectly valid, standard-compliant SQL code.
6833+
The default is <literal>off</>.
6834+
</para>
6835+
6836+
<para>
6837+
See <xref linkend="sql-precedence"> for more information.
6838+
</para>
6839+
</listitem>
6840+
</varlistentry>
6841+
68196842
<varlistentry id="guc-quote-all-identifiers" xreflabel="quote-all-identifiers">
68206843
<term><varname>quote_all_identifiers</varname> (<type>boolean</type>)
68216844
<indexterm>

‎doc/src/sgml/syntax.sgml

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -984,10 +984,11 @@ CAST ( '<replaceable>string</replaceable>' AS <replaceable>type</replaceable> )
984984
associativity of the operators in <productname>PostgreSQL</>.
985985
Most operators have the same precedence and are left-associative.
986986
The precedence and associativity of the operators is hard-wired
987-
into the parser. This can lead to non-intuitive behavior; for
988-
example the Boolean operators <literal>&lt;</> and
989-
<literal>&gt;</> have a different precedence than the Boolean
990-
operators <literal>&lt;=</> and <literal>&gt;=</>. Also, you will
987+
into the parser.
988+
</para>
989+
990+
<para>
991+
You will
991992
sometimes need to add parentheses when using combinations of
992993
binary and unary operators. For instance:
993994
<programlisting>
@@ -1008,7 +1009,7 @@ SELECT (5 !) - 6;
10081009
</para>
10091010

10101011
<table id="sql-precedence-table">
1011-
<title>Operator Precedence (decreasing)</title>
1012+
<title>Operator Precedence (highest to lowest)</title>
10121013

10131014
<tgroup cols="3">
10141015
<thead>
@@ -1063,63 +1064,35 @@ SELECT (5 !) - 6;
10631064
</row>
10641065

10651066
<row>
1066-
<entry><token>IS</token></entry>
1067-
<entry></entry>
1068-
<entry><literal>IS TRUE</>, <literal>IS FALSE</>, <literal>IS NULL</>, etc</entry>
1069-
</row>
1070-
1071-
<row>
1072-
<entry><token>ISNULL</token></entry>
1073-
<entry></entry>
1074-
<entry>test for null</entry>
1075-
</row>
1076-
1077-
<row>
1078-
<entry><token>NOTNULL</token></entry>
1079-
<entry></entry>
1080-
<entry>test for not null</entry>
1081-
</row>
1082-
1083-
<row>
1084-
<entry>(any other)</entry>
1067+
<entry>(any other operator)</entry>
10851068
<entry>left</entry>
10861069
<entry>all other native and user-defined operators</entry>
10871070
</row>
10881071

1089-
<row>
1090-
<entry><token>IN</token></entry>
1091-
<entry></entry>
1092-
<entry>set membership</entry>
1093-
</row>
1094-
1095-
<row>
1096-
<entry><token>BETWEEN</token></entry>
1097-
<entry></entry>
1098-
<entry>range containment</entry>
1099-
</row>
1100-
11011072
<row>
11021073
<entry><token>OVERLAPS</token></entry>
11031074
<entry></entry>
11041075
<entry>time interval overlap</entry>
11051076
</row>
11061077

11071078
<row>
1108-
<entry><token>LIKE</token> <token>ILIKE</token> <token>SIMILAR</token></entry>
1079+
<entry><token>BETWEEN</token> <token>IN</token> <token>LIKE</token> <token>ILIKE</token> <token>SIMILAR</token></entry>
11091080
<entry></entry>
1110-
<entry>string pattern matching</entry>
1081+
<entry>range containment, set membership, string matching</entry>
11111082
</row>
11121083

11131084
<row>
1114-
<entry><token>&lt;</token> <token>&gt;</token></entry>
1085+
<entry><token>&lt;</token> <token>&gt;</token> <token>=</token> <token>&lt;=</token> <token>&gt;=</token> <token>&lt;&gt;</token>
1086+
</entry>
11151087
<entry></entry>
1116-
<entry>less than, greater than</entry>
1088+
<entry>comparison operators</entry>
11171089
</row>
11181090

11191091
<row>
1120-
<entry><token>=</token></entry>
1121-
<entry>right</entry>
1122-
<entry>equality, assignment</entry>
1092+
<entry><token>IS</token> <token>ISNULL</token> <token>NOTNULL</token></entry>
1093+
<entry></entry>
1094+
<entry><literal>IS TRUE</>, <literal>IS FALSE</>, <literal>IS
1095+
NULL</>, <literal>IS DISTINCT FROM</>, etc</entry>
11231096
</row>
11241097

11251098
<row>
@@ -1159,9 +1132,32 @@ SELECT (5 !) - 6;
11591132
SELECT 3 OPERATOR(pg_catalog.+) 4;
11601133
</programlisting>
11611134
the <literal>OPERATOR</> construct is taken to have the default precedence
1162-
shown in <xref linkend="sql-precedence-table"> for <quote>any other</> operator. This is true no matter
1135+
shown in <xref linkend="sql-precedence-table"> for
1136+
<quote>any other operator</>. This is true no matter
11631137
which specific operator appears inside <literal>OPERATOR()</>.
11641138
</para>
1139+
1140+
<note>
1141+
<para>
1142+
<productname>PostgreSQL</> versions before 9.5 used slightly different
1143+
operator precedence rules. In particular, <token>&lt;=</token>
1144+
<token>&gt;=</token> and <token>&lt;&gt;</token> used to be treated as
1145+
generic operators; <literal>IS</> tests used to have higher priority;
1146+
and <literal>NOT BETWEEN</> and related constructs acted inconsistently,
1147+
being taken in some cases as having the precedence of <literal>NOT</>
1148+
rather than <literal>BETWEEN</>. These rules were changed for better
1149+
compliance with the SQL standard and to reduce confusion from
1150+
inconsistent treatment of logically equivalent constructs. In most
1151+
cases, these changes will result in no behavioral change, or perhaps
1152+
in <quote>no such operator</> failures which can be resolved by adding
1153+
parentheses. However there are corner cases in which a query might
1154+
change behavior without any parsing error being reported. If you are
1155+
concerned about whether these changes have silently broken something,
1156+
you can test your application with the configuration
1157+
parameter <xref linkend="guc-operator-precedence-warning"> turned on
1158+
to see if any warnings are logged.
1159+
</para>
1160+
</note>
11651161
</sect2>
11661162
</sect1>
11671163

‎src/backend/nodes/outfuncs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2546,6 +2546,9 @@ _outAExpr(StringInfo str, const A_Expr *node)
25462546
appendStringInfoString(str," NOT_BETWEEN_SYM ");
25472547
WRITE_NODE_FIELD(name);
25482548
break;
2549+
caseAEXPR_PAREN:
2550+
appendStringInfoString(str," PAREN");
2551+
break;
25492552
default:
25502553
appendStringInfoString(str," ??");
25512554
break;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp