Skip to content

Commit dee9a9a

Browse files
committed
2 parents c3fba52 + 6a0b55b commit dee9a9a

File tree

167 files changed

+6729
-4449
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

167 files changed

+6729
-4449
lines changed

contrib/postgres_fdw/deparse.c

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
* We do not consider that it is ever safe to send COLLATE expressions to
1818
* the remote server: it might not have the same collation names we do.
1919
* (Later we might consider it safe to send COLLATE "C", but even that would
20-
* fail on old remote servers.) An expression is considered safe to send only
21-
* if all collations used in it are traceable to Var(s) of the foreign table.
22-
* That implies that if the remote server gets a different answer than we do,
23-
* the foreign table's columns are not marked with collations that match the
24-
* remote table's columns, which we can consider to be user error.
20+
* fail on old remote servers.) An expression is considered safe to send
21+
* only if all operator/function input collations used in it are traceable to
22+
* Var(s) of the foreign table. That implies that if the remote server gets
23+
* a different answer than we do, the foreign table's columns are not marked
24+
* with collations that match the remote table's columns, which we can
25+
* consider to be user error.
2526
*
2627
* Portions Copyright (c) 2012-2015, PostgreSQL Global Development Group
2728
*
@@ -69,9 +70,12 @@ typedef struct foreign_glob_cxt
6970
*/
7071
typedef enum
7172
{
72-
FDW_COLLATE_NONE, /* expression is of a noncollatable type */
73+
FDW_COLLATE_NONE, /* expression is of a noncollatable type, or
74+
* it has default collation that is not
75+
* traceable to a foreign Var */
7376
FDW_COLLATE_SAFE, /* collation derives from a foreign Var */
74-
FDW_COLLATE_UNSAFE /* collation derives from something else */
77+
FDW_COLLATE_UNSAFE /* collation is non-default and derives from
78+
* something other than a foreign Var */
7579
} FDWCollateState;
7680

7781
typedef struct foreign_loc_cxt
@@ -272,13 +276,24 @@ foreign_expr_walker(Node *node,
272276
else
273277
{
274278
/* Var belongs to some other table */
275-
if (var->varcollid != InvalidOid &&
276-
var->varcollid != DEFAULT_COLLATION_OID)
277-
return false;
278-
279-
/* We can consider that it doesn't set collation */
280-
collation = InvalidOid;
281-
state = FDW_COLLATE_NONE;
279+
collation = var->varcollid;
280+
if (collation == InvalidOid ||
281+
collation == DEFAULT_COLLATION_OID)
282+
{
283+
/*
284+
* It's noncollatable, or it's safe to combine with a
285+
* collatable foreign Var, so set state to NONE.
286+
*/
287+
state = FDW_COLLATE_NONE;
288+
}
289+
else
290+
{
291+
/*
292+
* Do not fail right away, since the Var might appear
293+
* in a collation-insensitive context.
294+
*/
295+
state = FDW_COLLATE_UNSAFE;
296+
}
282297
}
283298
}
284299
break;
@@ -288,31 +303,31 @@ foreign_expr_walker(Node *node,
288303

289304
/*
290305
* If the constant has nondefault collation, either it's of a
291-
* non-builtin type, or it reflects folding of a CollateExpr;
292-
* either way, it's unsafe to send to the remote.
306+
* non-builtin type, or it reflects folding of a CollateExpr.
307+
* It's unsafe to send to the remote unless it's used in a
308+
* non-collation-sensitive context.
293309
*/
294-
if (c->constcollid != InvalidOid &&
295-
c->constcollid != DEFAULT_COLLATION_OID)
296-
return false;
297-
298-
/* Otherwise, we can consider that it doesn't set collation */
299-
collation = InvalidOid;
300-
state = FDW_COLLATE_NONE;
310+
collation = c->constcollid;
311+
if (collation == InvalidOid ||
312+
collation == DEFAULT_COLLATION_OID)
313+
state = FDW_COLLATE_NONE;
314+
else
315+
state = FDW_COLLATE_UNSAFE;
301316
}
302317
break;
303318
case T_Param:
304319
{
305320
Param *p = (Param *) node;
306321

307322
/*
308-
* Collation handling is same as for Consts.
323+
* Collation rule is same as for Consts and non-foreign Vars.
309324
*/
310-
if (p->paramcollid != InvalidOid &&
311-
p->paramcollid != DEFAULT_COLLATION_OID)
312-
return false;
313-
314-
collation = InvalidOid;
315-
state = FDW_COLLATE_NONE;
325+
collation = p->paramcollid;
326+
if (collation == InvalidOid ||
327+
collation == DEFAULT_COLLATION_OID)
328+
state = FDW_COLLATE_NONE;
329+
else
330+
state = FDW_COLLATE_UNSAFE;
316331
}
317332
break;
318333
case T_ArrayRef:
@@ -348,6 +363,8 @@ foreign_expr_walker(Node *node,
348363
else if (inner_cxt.state == FDW_COLLATE_SAFE &&
349364
collation == inner_cxt.collation)
350365
state = FDW_COLLATE_SAFE;
366+
else if (collation == DEFAULT_COLLATION_OID)
367+
state = FDW_COLLATE_NONE;
351368
else
352369
state = FDW_COLLATE_UNSAFE;
353370
}
@@ -393,6 +410,8 @@ foreign_expr_walker(Node *node,
393410
else if (inner_cxt.state == FDW_COLLATE_SAFE &&
394411
collation == inner_cxt.collation)
395412
state = FDW_COLLATE_SAFE;
413+
else if (collation == DEFAULT_COLLATION_OID)
414+
state = FDW_COLLATE_NONE;
396415
else
397416
state = FDW_COLLATE_UNSAFE;
398417
}
@@ -434,6 +453,8 @@ foreign_expr_walker(Node *node,
434453
else if (inner_cxt.state == FDW_COLLATE_SAFE &&
435454
collation == inner_cxt.collation)
436455
state = FDW_COLLATE_SAFE;
456+
else if (collation == DEFAULT_COLLATION_OID)
457+
state = FDW_COLLATE_NONE;
437458
else
438459
state = FDW_COLLATE_UNSAFE;
439460
}
@@ -483,14 +504,16 @@ foreign_expr_walker(Node *node,
483504

484505
/*
485506
* RelabelType must not introduce a collation not derived from
486-
* an input foreign Var.
507+
* an input foreign Var (same logic as for a real function).
487508
*/
488509
collation = r->resultcollid;
489510
if (collation == InvalidOid)
490511
state = FDW_COLLATE_NONE;
491512
else if (inner_cxt.state == FDW_COLLATE_SAFE &&
492513
collation == inner_cxt.collation)
493514
state = FDW_COLLATE_SAFE;
515+
else if (collation == DEFAULT_COLLATION_OID)
516+
state = FDW_COLLATE_NONE;
494517
else
495518
state = FDW_COLLATE_UNSAFE;
496519
}
@@ -540,14 +563,16 @@ foreign_expr_walker(Node *node,
540563

541564
/*
542565
* ArrayExpr must not introduce a collation not derived from
543-
* an input foreign Var.
566+
* an input foreign Var (same logic as for a function).
544567
*/
545568
collation = a->array_collid;
546569
if (collation == InvalidOid)
547570
state = FDW_COLLATE_NONE;
548571
else if (inner_cxt.state == FDW_COLLATE_SAFE &&
549572
collation == inner_cxt.collation)
550573
state = FDW_COLLATE_SAFE;
574+
else if (collation == DEFAULT_COLLATION_OID)
575+
state = FDW_COLLATE_NONE;
551576
else
552577
state = FDW_COLLATE_UNSAFE;
553578
}

contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,71 +1005,110 @@ COMMIT;
10051005
-- ===================================================================
10061006
-- test handling of collations
10071007
-- ===================================================================
1008-
create table loct3 (f1 text collate "C", f2 text);
1009-
create foreign table ft3 (f1 text collate "C", f2 text)
1010-
server loopback options (table_name 'loct3');
1008+
create table loct3 (f1 text collate "C" unique, f2 text, f3 varchar(10) unique);
1009+
create foreign table ft3 (f1 text collate "C", f2 text, f3 varchar(10))
1010+
server loopback options (table_name 'loct3', use_remote_estimate 'true');
10111011
-- can be sent to remote
10121012
explain (verbose, costs off) select * from ft3 where f1 = 'foo';
1013-
QUERY PLAN
1014-
--------------------------------------------------------------------------
1013+
QUERY PLAN
1014+
------------------------------------------------------------------------------
10151015
Foreign Scan on public.ft3
1016-
Output: f1, f2
1017-
Remote SQL: SELECT f1, f2 FROM public.loct3 WHERE ((f1 = 'foo'::text))
1016+
Output: f1, f2, f3
1017+
Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f1 = 'foo'::text))
10181018
(3 rows)
10191019

10201020
explain (verbose, costs off) select * from ft3 where f1 COLLATE "C" = 'foo';
1021-
QUERY PLAN
1022-
--------------------------------------------------------------------------
1021+
QUERY PLAN
1022+
------------------------------------------------------------------------------
10231023
Foreign Scan on public.ft3
1024-
Output: f1, f2
1025-
Remote SQL: SELECT f1, f2 FROM public.loct3 WHERE ((f1 = 'foo'::text))
1024+
Output: f1, f2, f3
1025+
Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f1 = 'foo'::text))
10261026
(3 rows)
10271027

10281028
explain (verbose, costs off) select * from ft3 where f2 = 'foo';
1029-
QUERY PLAN
1030-
--------------------------------------------------------------------------
1029+
QUERY PLAN
1030+
------------------------------------------------------------------------------
10311031
Foreign Scan on public.ft3
1032-
Output: f1, f2
1033-
Remote SQL: SELECT f1, f2 FROM public.loct3 WHERE ((f2 = 'foo'::text))
1032+
Output: f1, f2, f3
1033+
Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f2 = 'foo'::text))
10341034
(3 rows)
10351035

1036+
explain (verbose, costs off) select * from ft3 where f3 = 'foo';
1037+
QUERY PLAN
1038+
------------------------------------------------------------------------------
1039+
Foreign Scan on public.ft3
1040+
Output: f1, f2, f3
1041+
Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f3 = 'foo'::text))
1042+
(3 rows)
1043+
1044+
explain (verbose, costs off) select * from ft3 f, loct3 l
1045+
where f.f3 = l.f3 and l.f1 = 'foo';
1046+
QUERY PLAN
1047+
--------------------------------------------------------------------------------------------------
1048+
Nested Loop
1049+
Output: f.f1, f.f2, f.f3, l.f1, l.f2, l.f3
1050+
-> Index Scan using loct3_f1_key on public.loct3 l
1051+
Output: l.f1, l.f2, l.f3
1052+
Index Cond: (l.f1 = 'foo'::text)
1053+
-> Foreign Scan on public.ft3 f
1054+
Output: f.f1, f.f2, f.f3
1055+
Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE (($1::character varying(10) = f3))
1056+
(8 rows)
1057+
10361058
-- can't be sent to remote
10371059
explain (verbose, costs off) select * from ft3 where f1 COLLATE "POSIX" = 'foo';
1038-
QUERY PLAN
1039-
-----------------------------------------------
1060+
QUERY PLAN
1061+
---------------------------------------------------
10401062
Foreign Scan on public.ft3
1041-
Output: f1, f2
1063+
Output: f1, f2, f3
10421064
Filter: ((ft3.f1)::text = 'foo'::text)
1043-
Remote SQL: SELECT f1, f2 FROM public.loct3
1065+
Remote SQL: SELECT f1, f2, f3 FROM public.loct3
10441066
(4 rows)
10451067

10461068
explain (verbose, costs off) select * from ft3 where f1 = 'foo' COLLATE "C";
1047-
QUERY PLAN
1048-
-----------------------------------------------
1069+
QUERY PLAN
1070+
---------------------------------------------------
10491071
Foreign Scan on public.ft3
1050-
Output: f1, f2
1072+
Output: f1, f2, f3
10511073
Filter: (ft3.f1 = 'foo'::text COLLATE "C")
1052-
Remote SQL: SELECT f1, f2 FROM public.loct3
1074+
Remote SQL: SELECT f1, f2, f3 FROM public.loct3
10531075
(4 rows)
10541076

10551077
explain (verbose, costs off) select * from ft3 where f2 COLLATE "C" = 'foo';
1056-
QUERY PLAN
1057-
-----------------------------------------------
1078+
QUERY PLAN
1079+
---------------------------------------------------
10581080
Foreign Scan on public.ft3
1059-
Output: f1, f2
1081+
Output: f1, f2, f3
10601082
Filter: ((ft3.f2)::text = 'foo'::text)
1061-
Remote SQL: SELECT f1, f2 FROM public.loct3
1083+
Remote SQL: SELECT f1, f2, f3 FROM public.loct3
10621084
(4 rows)
10631085

10641086
explain (verbose, costs off) select * from ft3 where f2 = 'foo' COLLATE "C";
1065-
QUERY PLAN
1066-
-----------------------------------------------
1087+
QUERY PLAN
1088+
---------------------------------------------------
10671089
Foreign Scan on public.ft3
1068-
Output: f1, f2
1090+
Output: f1, f2, f3
10691091
Filter: (ft3.f2 = 'foo'::text COLLATE "C")
1070-
Remote SQL: SELECT f1, f2 FROM public.loct3
1092+
Remote SQL: SELECT f1, f2, f3 FROM public.loct3
10711093
(4 rows)
10721094

1095+
explain (verbose, costs off) select * from ft3 f, loct3 l
1096+
where f.f3 = l.f3 COLLATE "POSIX" and l.f1 = 'foo';
1097+
QUERY PLAN
1098+
-------------------------------------------------------------
1099+
Hash Join
1100+
Output: f.f1, f.f2, f.f3, l.f1, l.f2, l.f3
1101+
Hash Cond: ((f.f3)::text = (l.f3)::text)
1102+
-> Foreign Scan on public.ft3 f
1103+
Output: f.f1, f.f2, f.f3
1104+
Remote SQL: SELECT f1, f2, f3 FROM public.loct3
1105+
-> Hash
1106+
Output: l.f1, l.f2, l.f3
1107+
-> Index Scan using loct3_f1_key on public.loct3 l
1108+
Output: l.f1, l.f2, l.f3
1109+
Index Cond: (l.f1 = 'foo'::text)
1110+
(11 rows)
1111+
10731112
-- ===================================================================
10741113
-- test writable foreign table stuff
10751114
-- ===================================================================

contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,19 +316,24 @@ COMMIT;
316316
-- ===================================================================
317317
-- test handling of collations
318318
-- ===================================================================
319-
create table loct3 (f1 text collate "C", f2 text);
320-
create foreign table ft3 (f1 text collate "C", f2 text)
321-
server loopback options (table_name 'loct3');
319+
create table loct3 (f1 text collate "C" unique, f2 text, f3 varchar(10) unique);
320+
create foreign table ft3 (f1 text collate "C", f2 text, f3 varchar(10))
321+
server loopback options (table_name 'loct3', use_remote_estimate 'true');
322322

323323
-- can be sent to remote
324324
explain (verbose, costs off) select * from ft3 where f1 = 'foo';
325325
explain (verbose, costs off) select * from ft3 where f1 COLLATE "C" = 'foo';
326326
explain (verbose, costs off) select * from ft3 where f2 = 'foo';
327+
explain (verbose, costs off) select * from ft3 where f3 = 'foo';
328+
explain (verbose, costs off) select * from ft3 f, loct3 l
329+
where f.f3 = l.f3 and l.f1 = 'foo';
327330
-- can't be sent to remote
328331
explain (verbose, costs off) select * from ft3 where f1 COLLATE "POSIX" = 'foo';
329332
explain (verbose, costs off) select * from ft3 where f1 = 'foo' COLLATE "C";
330333
explain (verbose, costs off) select * from ft3 where f2 COLLATE "C" = 'foo';
331334
explain (verbose, costs off) select * from ft3 where f2 = 'foo' COLLATE "C";
335+
explain (verbose, costs off) select * from ft3 f, loct3 l
336+
where f.f3 = l.f3 COLLATE "POSIX" and l.f1 = 'foo';
332337

333338
-- ===================================================================
334339
-- test writable foreign table stuff

contrib/test_decoding/expected/binary.out

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,22 @@ SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_d
77
(1 row)
88

99
-- succeeds, textual plugin, textual consumer
10-
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '0');
10+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '0', 'skip-empty-xacts', '1');
1111
data
1212
------
1313
(0 rows)
1414

1515
-- fails, binary plugin, textual consumer
16-
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '1');
16+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '1', 'skip-empty-xacts', '1');
1717
ERROR: logical decoding output plugin "test_decoding" produces binary output, but "pg_logical_slot_get_changes(name,pg_lsn,integer,text[])" expects textual data
1818
-- succeeds, textual plugin, binary consumer
19-
SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '0');
19+
SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '0', 'skip-empty-xacts', '1');
2020
data
2121
------
2222
(0 rows)
2323

2424
-- succeeds, binary plugin, binary consumer
25-
SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '1');
25+
SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '1', 'skip-empty-xacts', '1');
2626
data
2727
------
2828
(0 rows)

contrib/test_decoding/sql/binary.sql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ SET synchronous_commit = on;
33

44
SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
55
-- succeeds, textual plugin, textual consumer
6-
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '0');
6+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '0', 'skip-empty-xacts', '1');
77
-- fails, binary plugin, textual consumer
8-
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '1');
8+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '1', 'skip-empty-xacts', '1');
99
-- succeeds, textual plugin, binary consumer
10-
SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '0');
10+
SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '0', 'skip-empty-xacts', '1');
1111
-- succeeds, binary plugin, binary consumer
12-
SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '1');
12+
SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '1', 'skip-empty-xacts', '1');
1313

1414
SELECT 'init' FROM pg_drop_replication_slot('regression_slot');

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy