Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 542320c

Browse files
committed
Be more careful about printing constants in ruleutils.c.
The previous coding in get_const_expr() tried to avoid quoting integer, float, and numeric literals if at all possible. While that looks nice, it means that dumped expressions might re-parse to something that's semantically equivalent but not the exact same parsetree; for example a FLOAT8 constant would re-parse as a NUMERIC constant with a cast to FLOAT8. Though the result would be the same after constant-folding, this is problematic in certain contexts. In particular, Jeff Davis pointed out that this could cause unexpected failures in ALTER INHERIT operations because of child tables having not-exactly-equivalent CHECK expressions. Therefore, favor correctness over legibility and dump such constants in quotes except in the limited cases where they'll be interpreted as the same type even without any casting. This results in assorted small changes in the regression test outputs, and will affect display of user-defined views and rules similarly. The odds of that causing problems in the field seem non-negligible; given the lack of previous complaints, it seems best not to change this in the back branches.
1 parent 701dcc9 commit 542320c

File tree

12 files changed

+114
-101
lines changed

12 files changed

+114
-101
lines changed

contrib/btree_gist/expected/float4.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
7878
----------------------------------------------------
7979
Limit
8080
-> Index Only Scan using float4idx on float4tmp
81-
Order By: (a <-> (-179)::real)
81+
Order By: (a <-> '-179'::real)
8282
(3 rows)
8383

8484
SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;

contrib/btree_gist/expected/float8.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
7878
-----------------------------------------------------
7979
Limit
8080
-> Index Only Scan using float8idx on float8tmp
81-
Order By: (a <-> (-1890)::double precision)
81+
Order By: (a <-> '-1890'::double precision)
8282
(3 rows)
8383

8484
SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;

contrib/btree_gist/expected/int2.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;
7878
------------------------------------------------
7979
Limit
8080
-> Index Only Scan using int2idx on int2tmp
81-
Order By: (a <-> 237::smallint)
81+
Order By: (a <-> '237'::smallint)
8282
(3 rows)
8383

8484
SELECT a, a <-> '237' FROM int2tmp ORDER BY a <-> '237' LIMIT 3;

contrib/btree_gist/expected/int8.out

+3-3
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,11 @@ SELECT count(*) FROM int8tmp WHERE a > 464571291354841::int8;
7474

7575
EXPLAIN (COSTS OFF)
7676
SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;
77-
QUERY PLAN
78-
---------------------------------------------------
77+
QUERY PLAN
78+
-----------------------------------------------------
7979
Limit
8080
-> Index Only Scan using int8idx on int8tmp
81-
Order By: (a <-> 464571291354841::bigint)
81+
Order By: (a <-> '464571291354841'::bigint)
8282
(3 rows)
8383

8484
SELECT a, a <-> '464571291354841' FROM int8tmp ORDER BY a <-> '464571291354841' LIMIT 3;

contrib/btree_gist/expected/numeric.out

+3-3
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,12 @@ SELECT count(*) FROM numerictmp WHERE a > 0 ;
190190
SET enable_bitmapscan=off;
191191
EXPLAIN (COSTS OFF)
192192
SELECT * FROM numerictmp WHERE a BETWEEN 1 AND 300 ORDER BY a;
193-
QUERY PLAN
194-
-----------------------------------------------------------------
193+
QUERY PLAN
194+
---------------------------------------------------------------------
195195
Sort
196196
Sort Key: a
197197
-> Index Only Scan using numericidx on numerictmp
198-
Index Cond: ((a >= 1::numeric) AND (a <= 300::numeric))
198+
Index Cond: ((a >= '1'::numeric) AND (a <= '300'::numeric))
199199
(4 rows)
200200

201201
SELECT * FROM numerictmp WHERE a BETWEEN 1 AND 300 ORDER BY a;

contrib/postgres_fdw/expected/postgres_fdw.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,7 @@ SELECT * FROM ft1 t1 WHERE t1.tableoid = 'pg_class'::regclass LIMIT 1;
874874
Output: c1, c2, c3, c4, c5, c6, c7, c8
875875
-> Foreign Scan on public.ft1 t1
876876
Output: c1, c2, c3, c4, c5, c6, c7, c8
877-
Filter: (t1.tableoid = 1259::oid)
877+
Filter: (t1.tableoid = '1259'::oid)
878878
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
879879
(6 rows)
880880

src/backend/utils/adt/ruleutils.c

+52-39
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
#include "postgres.h"
1717

18+
#include <ctype.h>
1819
#include <unistd.h>
1920
#include <fcntl.h>
2021

@@ -7977,6 +7978,13 @@ get_coercion_expr(Node *arg, deparse_context *context,
79777978
* right above it. Avoid generating redundant output. However, beware of
79787979
* suppressing casts when the user actually wrote something like
79797980
* 'foo'::text::char(3).
7981+
*
7982+
* Note: it might seem that we are missing the possibility of needing to
7983+
* print a COLLATE clause for such a Const. However, a Const could only
7984+
* have nondefault collation in a post-constant-folding tree, in which the
7985+
* length coercion would have been folded too. See also the special
7986+
* handling of CollateExpr in coerce_to_target_type(): any collation
7987+
* marking will be above the coercion node, not below it.
79807988
*/
79817989
if (arg && IsA(arg, Const) &&
79827990
((Const *) arg)->consttype == resulttype &&
@@ -8007,8 +8015,9 @@ get_coercion_expr(Node *arg, deparse_context *context,
80078015
* the right type by default.
80088016
*
80098017
* If the Const's collation isn't default for its type, show that too.
8010-
* This can only happen in trees that have been through constant-folding.
8011-
* We assume we don't need to do this when showtype is -1.
8018+
* We mustn't do this when showtype is -1 (since that means the caller will
8019+
* print "::typename", and we can't put a COLLATE clause in between). It's
8020+
* caller's responsibility that collation isn't missed in such cases.
80128021
* ----------
80138022
*/
80148023
static void
@@ -8018,8 +8027,7 @@ get_const_expr(Const *constval, deparse_context *context, int showtype)
80188027
Oid typoutput;
80198028
bool typIsVarlena;
80208029
char *extval;
8021-
bool isfloat = false;
8022-
bool needlabel;
8030+
bool needlabel = false;
80238031

80248032
if (constval->constisnull)
80258033
{
@@ -8045,40 +8053,42 @@ get_const_expr(Const *constval, deparse_context *context, int showtype)
80458053

80468054
switch (constval->consttype)
80478055
{
8048-
case INT2OID:
80498056
case INT4OID:
8050-
case INT8OID:
8051-
case OIDOID:
8052-
case FLOAT4OID:
8053-
case FLOAT8OID:
8057+
8058+
/*
8059+
* INT4 can be printed without any decoration, unless it is
8060+
* negative; in that case print it as '-nnn'::integer to ensure
8061+
* that the output will re-parse as a constant, not as a constant
8062+
* plus operator. In most cases we could get away with printing
8063+
* (-nnn) instead, because of the way that gram.y handles negative
8064+
* literals; but that doesn't work for INT_MIN, and it doesn't
8065+
* seem that much prettier anyway.
8066+
*/
8067+
if (extval[0] != '-')
8068+
appendStringInfoString(buf, extval);
8069+
else
8070+
{
8071+
appendStringInfo(buf, "'%s'", extval);
8072+
needlabel = true; /* we must attach a cast */
8073+
}
8074+
break;
8075+
80548076
case NUMERICOID:
8077+
8078+
/*
8079+
* NUMERIC can be printed without quotes if it looks like a float
8080+
* constant (not an integer, and not Infinity or NaN) and doesn't
8081+
* have a leading sign (for the same reason as for INT4).
8082+
*/
8083+
if (isdigit((unsigned char) extval[0]) &&
8084+
strcspn(extval, "eE.") != strlen(extval))
80558085
{
8056-
/*
8057-
* These types are printed without quotes unless they contain
8058-
* values that aren't accepted by the scanner unquoted (e.g.,
8059-
* 'NaN'). Note that strtod() and friends might accept NaN,
8060-
* so we can't use that to test.
8061-
*
8062-
* In reality we only need to defend against infinity and NaN,
8063-
* so we need not get too crazy about pattern matching here.
8064-
*
8065-
* There is a special-case gotcha: if the constant is signed,
8066-
* we need to parenthesize it, else the parser might see a
8067-
* leading plus/minus as binding less tightly than adjacent
8068-
* operators --- particularly, the cast that we might attach
8069-
* below.
8070-
*/
8071-
if (strspn(extval, "0123456789+-eE.") == strlen(extval))
8072-
{
8073-
if (extval[0] == '+' || extval[0] == '-')
8074-
appendStringInfo(buf, "(%s)", extval);
8075-
else
8076-
appendStringInfoString(buf, extval);
8077-
if (strcspn(extval, "eE.") != strlen(extval))
8078-
isfloat = true; /* it looks like a float */
8079-
}
8080-
else
8081-
appendStringInfo(buf, "'%s'", extval);
8086+
appendStringInfoString(buf, extval);
8087+
}
8088+
else
8089+
{
8090+
appendStringInfo(buf, "'%s'", extval);
8091+
needlabel = true; /* we must attach a cast */
80828092
}
80838093
break;
80848094

@@ -8114,18 +8124,21 @@ get_const_expr(Const *constval, deparse_context *context, int showtype)
81148124
switch (constval->consttype)
81158125
{
81168126
case BOOLOID:
8117-
case INT4OID:
81188127
case UNKNOWNOID:
81198128
/* These types can be left unlabeled */
81208129
needlabel = false;
81218130
break;
8131+
case INT4OID:
8132+
/* We determined above whether a label is needed */
8133+
break;
81228134
case NUMERICOID:
81238135

81248136
/*
8125-
* Float-looking constants will be typed as numeric, but if
8126-
* there's a specific typmod we need to show it.
8137+
* Float-looking constants will be typed as numeric, which we
8138+
* checked above; but if there's a nondefault typmod we need to
8139+
* show it.
81278140
*/
8128-
needlabel = !isfloat || (constval->consttypmod >= 0);
8141+
needlabel |= (constval->consttypmod >= 0);
81298142
break;
81308143
default:
81318144
needlabel = true;

src/test/regress/expected/equivclass.out

+22-22
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ set enable_mergejoin = off;
104104
--
105105
explain (costs off)
106106
select * from ec0 where ff = f1 and f1 = '42'::int8;
107-
QUERY PLAN
108-
----------------------------------
107+
QUERY PLAN
108+
-----------------------------------
109109
Index Scan using ec0_pkey on ec0
110-
Index Cond: (ff = 42::bigint)
111-
Filter: (f1 = 42::bigint)
110+
Index Cond: (ff = '42'::bigint)
111+
Filter: (f1 = '42'::bigint)
112112
(3 rows)
113113

114114
explain (costs off)
@@ -139,12 +139,12 @@ explain (costs off)
139139

140140
explain (costs off)
141141
select * from ec1, ec2 where ff = x1 and ff = '42'::int8;
142-
QUERY PLAN
143-
---------------------------------------------------------------
142+
QUERY PLAN
143+
-------------------------------------------------------------------
144144
Nested Loop
145145
Join Filter: (ec1.ff = ec2.x1)
146146
-> Index Scan using ec1_pkey on ec1
147-
Index Cond: ((ff = 42::bigint) AND (ff = 42::bigint))
147+
Index Cond: ((ff = '42'::bigint) AND (ff = '42'::bigint))
148148
-> Seq Scan on ec2
149149
(5 rows)
150150

@@ -161,14 +161,14 @@ explain (costs off)
161161

162162
explain (costs off)
163163
select * from ec1, ec2 where ff = x1 and '42'::int8 = x1;
164-
QUERY PLAN
165-
----------------------------------------
164+
QUERY PLAN
165+
-----------------------------------------
166166
Nested Loop
167167
Join Filter: (ec1.ff = ec2.x1)
168168
-> Index Scan using ec1_pkey on ec1
169-
Index Cond: (ff = 42::bigint)
169+
Index Cond: (ff = '42'::bigint)
170170
-> Seq Scan on ec2
171-
Filter: (42::bigint = x1)
171+
Filter: ('42'::bigint = x1)
172172
(6 rows)
173173

174174
explain (costs off)
@@ -210,7 +210,7 @@ explain (costs off)
210210
-----------------------------------------------------
211211
Nested Loop
212212
-> Index Scan using ec1_pkey on ec1
213-
Index Cond: (ff = 42::bigint)
213+
Index Cond: (ff = '42'::bigint)
214214
-> Append
215215
-> Index Scan using ec1_expr2 on ec1 ec1_1
216216
Index Cond: (((ff + 2) + 1) = ec1.f1)
@@ -229,20 +229,20 @@ explain (costs off)
229229
union all
230230
select ff + 4 as x from ec1) as ss1
231231
where ss1.x = ec1.f1 and ec1.ff = 42::int8 and ec1.ff = ec1.f1;
232-
QUERY PLAN
233-
---------------------------------------------------------------
232+
QUERY PLAN
233+
-------------------------------------------------------------------
234234
Nested Loop
235235
Join Filter: ((((ec1_1.ff + 2) + 1)) = ec1.f1)
236236
-> Index Scan using ec1_pkey on ec1
237-
Index Cond: ((ff = 42::bigint) AND (ff = 42::bigint))
237+
Index Cond: ((ff = '42'::bigint) AND (ff = '42'::bigint))
238238
Filter: (ff = f1)
239239
-> Append
240240
-> Index Scan using ec1_expr2 on ec1 ec1_1
241-
Index Cond: (((ff + 2) + 1) = 42::bigint)
241+
Index Cond: (((ff + 2) + 1) = '42'::bigint)
242242
-> Index Scan using ec1_expr3 on ec1 ec1_2
243-
Index Cond: (((ff + 3) + 1) = 42::bigint)
243+
Index Cond: (((ff + 3) + 1) = '42'::bigint)
244244
-> Index Scan using ec1_expr4 on ec1 ec1_3
245-
Index Cond: ((ff + 4) = 42::bigint)
245+
Index Cond: ((ff + 4) = '42'::bigint)
246246
(12 rows)
247247

248248
explain (costs off)
@@ -265,7 +265,7 @@ explain (costs off)
265265
Nested Loop
266266
-> Nested Loop
267267
-> Index Scan using ec1_pkey on ec1
268-
Index Cond: (ff = 42::bigint)
268+
Index Cond: (ff = '42'::bigint)
269269
-> Append
270270
-> Index Scan using ec1_expr2 on ec1 ec1_1
271271
Index Cond: (((ff + 2) + 1) = ec1.f1)
@@ -321,7 +321,7 @@ explain (costs off)
321321
-> Sort
322322
Sort Key: ec1.f1 USING <
323323
-> Index Scan using ec1_pkey on ec1
324-
Index Cond: (ff = 42::bigint)
324+
Index Cond: (ff = '42'::bigint)
325325
(20 rows)
326326

327327
-- check partially indexed scan
@@ -341,7 +341,7 @@ explain (costs off)
341341
-----------------------------------------------------
342342
Nested Loop
343343
-> Index Scan using ec1_pkey on ec1
344-
Index Cond: (ff = 42::bigint)
344+
Index Cond: (ff = '42'::bigint)
345345
-> Append
346346
-> Index Scan using ec1_expr2 on ec1 ec1_1
347347
Index Cond: (((ff + 2) + 1) = ec1.f1)
@@ -378,6 +378,6 @@ explain (costs off)
378378
-> Sort
379379
Sort Key: ec1.f1 USING <
380380
-> Index Scan using ec1_pkey on ec1
381-
Index Cond: (ff = 42::bigint)
381+
Index Cond: (ff = '42'::bigint)
382382
(14 rows)
383383

0 commit comments

Comments
 (0)