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

Commit 6a9e2cb

Browse files
committed
Fix deparsing of Consts in postgres_fdw ORDER BY
For UNION ALL queries where a union child query contained a foreign table, if the targetlist of that query contained a constant, and the top-level query performed an ORDER BY which contained the column for the constant value, then postgres_fdw would find the EquivalenceMember with the Const and then try to produce an ORDER BY containing that Const. This caused problems with INT typed Consts as these could appear to be requests to order by an ordinal column position rather than the constant value. This could lead to either an error such as: ERROR: ORDER BY position <int const> is not in select list or worse, if the constant value is a valid column, then we could just sort by the wrong column altogether. Here we fix this issue by just not including these Consts in the ORDER BY clause. In passing, add a new section for testing ORDER BY in the postgres_fdw tests and move two existing tests which were misplaced in the WHERE clause testing section into it. Reported-by: Michał Kłeczek Reviewed-by: Ashutosh Bapat, Richard Guo Bug: #18381 Discussion: https://postgr.es/m/0714C8B8-8D82-4ABB-9F8D-A0C3657E7B6E%40kleczek.org Discussion: https://postgr.es/m/18381-137456acd168bf93%40postgresql.org Backpatch-through: 12, oldest supported version
1 parent 6a2c80e commit 6a9e2cb

File tree

3 files changed

+114
-36
lines changed

3 files changed

+114
-36
lines changed

contrib/postgres_fdw/deparse.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3770,13 +3770,12 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
37703770
{
37713771
ListCell *lcell;
37723772
int nestlevel;
3773-
const char *delim = " ";
37743773
StringInfo buf = context->buf;
3774+
bool gotone = false;
37753775

37763776
/* Make sure any constants in the exprs are printed portably */
37773777
nestlevel = set_transmission_modes();
37783778

3779-
appendStringInfoString(buf, " ORDER BY");
37803779
foreach(lcell, pathkeys)
37813780
{
37823781
PathKey *pathkey = lfirst(lcell);
@@ -3809,6 +3808,26 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
38093808

38103809
em_expr = em->em_expr;
38113810

3811+
/*
3812+
* If the member is a Const expression then we needn't add it to the
3813+
* ORDER BY clause. This can happen in UNION ALL queries where the
3814+
* union child targetlist has a Const. Adding these would be
3815+
* wasteful, but also, for INT columns, an integer literal would be
3816+
* seen as an ordinal column position rather than a value to sort by.
3817+
* deparseConst() does have code to handle this, but it seems less
3818+
* effort on all accounts just to skip these for ORDER BY clauses.
3819+
*/
3820+
if (IsA(em_expr, Const))
3821+
continue;
3822+
3823+
if (!gotone)
3824+
{
3825+
appendStringInfoString(buf, " ORDER BY ");
3826+
gotone = true;
3827+
}
3828+
else
3829+
appendStringInfoString(buf, ", ");
3830+
38123831
/*
38133832
* Lookup the operator corresponding to the strategy in the opclass.
38143833
* The datatype used by the opfamily is not necessarily the same as
@@ -3823,7 +3842,6 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
38233842
pathkey->pk_strategy, em->em_datatype, em->em_datatype,
38243843
pathkey->pk_opfamily);
38253844

3826-
appendStringInfoString(buf, delim);
38273845
deparseExpr(em_expr, context);
38283846

38293847
/*
@@ -3833,7 +3851,6 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
38333851
appendOrderBySuffix(oprid, exprType((Node *) em_expr),
38343852
pathkey->pk_nulls_first, context);
38353853

3836-
delim = ", ";
38373854
}
38383855
reset_transmission_modes(nestlevel);
38393856
}

contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 67 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -893,32 +893,6 @@ SELECT * FROM ft2 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft1 WHERE c1 < 5));
893893
4 | 4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4 | 4 | foo
894894
(4 rows)
895895

896-
-- we should not push order by clause with volatile expressions or unsafe
897-
-- collations
898-
EXPLAIN (VERBOSE, COSTS OFF)
899-
SELECT * FROM ft2 ORDER BY ft2.c1, random();
900-
QUERY PLAN
901-
-------------------------------------------------------------------------------
902-
Sort
903-
Output: c1, c2, c3, c4, c5, c6, c7, c8, (random())
904-
Sort Key: ft2.c1, (random())
905-
-> Foreign Scan on public.ft2
906-
Output: c1, c2, c3, c4, c5, c6, c7, c8, random()
907-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
908-
(6 rows)
909-
910-
EXPLAIN (VERBOSE, COSTS OFF)
911-
SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
912-
QUERY PLAN
913-
-------------------------------------------------------------------------------
914-
Sort
915-
Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text)
916-
Sort Key: ft2.c1, ft2.c3 COLLATE "C"
917-
-> Foreign Scan on public.ft2
918-
Output: c1, c2, c3, c4, c5, c6, c7, c8, c3
919-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
920-
(6 rows)
921-
922896
-- user-defined operator/function
923897
CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$
924898
BEGIN
@@ -1206,6 +1180,73 @@ WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
12061180
642 | '00642':1
12071181
(1 row)
12081182

1183+
-- ===================================================================
1184+
-- ORDER BY queries
1185+
-- ===================================================================
1186+
-- we should not push order by clause with volatile expressions or unsafe
1187+
-- collations
1188+
EXPLAIN (VERBOSE, COSTS OFF)
1189+
SELECT * FROM ft2 ORDER BY ft2.c1, random();
1190+
QUERY PLAN
1191+
-------------------------------------------------------------------------------
1192+
Sort
1193+
Output: c1, c2, c3, c4, c5, c6, c7, c8, (random())
1194+
Sort Key: ft2.c1, (random())
1195+
-> Foreign Scan on public.ft2
1196+
Output: c1, c2, c3, c4, c5, c6, c7, c8, random()
1197+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1198+
(6 rows)
1199+
1200+
EXPLAIN (VERBOSE, COSTS OFF)
1201+
SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
1202+
QUERY PLAN
1203+
-------------------------------------------------------------------------------
1204+
Sort
1205+
Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text)
1206+
Sort Key: ft2.c1, ft2.c3 COLLATE "C"
1207+
-> Foreign Scan on public.ft2
1208+
Output: c1, c2, c3, c4, c5, c6, c7, c8, c3
1209+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1210+
(6 rows)
1211+
1212+
-- Ensure we don't push ORDER BY expressions which are Consts at the UNION
1213+
-- child level to the foreign server.
1214+
EXPLAIN (VERBOSE, COSTS OFF)
1215+
SELECT * FROM (
1216+
SELECT 1 AS type,c1 FROM ft1
1217+
UNION ALL
1218+
SELECT 2 AS type,c1 FROM ft2
1219+
) a ORDER BY type,c1;
1220+
QUERY PLAN
1221+
---------------------------------------------------------------------------------
1222+
Merge Append
1223+
Sort Key: (1), ft1.c1
1224+
-> Foreign Scan on public.ft1
1225+
Output: 1, ft1.c1
1226+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
1227+
-> Foreign Scan on public.ft2
1228+
Output: 2, ft2.c1
1229+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
1230+
(8 rows)
1231+
1232+
EXPLAIN (VERBOSE, COSTS OFF)
1233+
SELECT * FROM (
1234+
SELECT 1 AS type,c1 FROM ft1
1235+
UNION ALL
1236+
SELECT 2 AS type,c1 FROM ft2
1237+
) a ORDER BY type;
1238+
QUERY PLAN
1239+
---------------------------------------------------
1240+
Merge Append
1241+
Sort Key: (1)
1242+
-> Foreign Scan on public.ft1
1243+
Output: 1, ft1.c1
1244+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
1245+
-> Foreign Scan on public.ft2
1246+
Output: 2, ft2.c1
1247+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
1248+
(8 rows)
1249+
12091250
-- ===================================================================
12101251
-- JOIN queries
12111252
-- ===================================================================

contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,6 @@ WHERE a.c2 = 6 AND b.c1 = a.c1 AND a.c8 = 'foo' AND b.c7 = upper(a.c7);
355355
-- bug before 9.3.5 due to sloppy handling of remote-estimate parameters
356356
SELECT * FROM ft1 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft2 WHERE c1 < 5));
357357
SELECT * FROM ft2 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft1 WHERE c1 < 5));
358-
-- we should not push order by clause with volatile expressions or unsafe
359-
-- collations
360-
EXPLAIN (VERBOSE, COSTS OFF)
361-
SELECT * FROM ft2 ORDER BY ft2.c1, random();
362-
EXPLAIN (VERBOSE, COSTS OFF)
363-
SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
364358

365359
-- user-defined operator/function
366360
CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$
@@ -462,6 +456,32 @@ WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
462456
SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1
463457
WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
464458

459+
-- ===================================================================
460+
-- ORDER BY queries
461+
-- ===================================================================
462+
-- we should not push order by clause with volatile expressions or unsafe
463+
-- collations
464+
EXPLAIN (VERBOSE, COSTS OFF)
465+
SELECT * FROM ft2 ORDER BY ft2.c1, random();
466+
EXPLAIN (VERBOSE, COSTS OFF)
467+
SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
468+
469+
-- Ensure we don't push ORDER BY expressions which are Consts at the UNION
470+
-- child level to the foreign server.
471+
EXPLAIN (VERBOSE, COSTS OFF)
472+
SELECT * FROM (
473+
SELECT 1 AS type,c1 FROM ft1
474+
UNION ALL
475+
SELECT 2 AS type,c1 FROM ft2
476+
) a ORDER BY type,c1;
477+
478+
EXPLAIN (VERBOSE, COSTS OFF)
479+
SELECT * FROM (
480+
SELECT 1 AS type,c1 FROM ft1
481+
UNION ALL
482+
SELECT 2 AS type,c1 FROM ft2
483+
) a ORDER BY type;
484+
465485
-- ===================================================================
466486
-- JOIN queries
467487
-- ===================================================================

0 commit comments

Comments
 (0)