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

Commit 9301e0f

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 c42e5fd commit 9301e0f

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
@@ -3251,13 +3251,12 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
32513251
{
32523252
ListCell *lcell;
32533253
int nestlevel;
3254-
const char *delim = " ";
32553254
StringInfo buf = context->buf;
3255+
bool gotone = false;
32563256

32573257
/* Make sure any constants in the exprs are printed portably */
32583258
nestlevel = set_transmission_modes();
32593259

3260-
appendStringInfoString(buf, " ORDER BY");
32613260
foreach(lcell, pathkeys)
32623261
{
32633262
PathKey *pathkey = lfirst(lcell);
@@ -3290,6 +3289,26 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
32903289

32913290
em_expr = em->em_expr;
32923291

3292+
/*
3293+
* If the member is a Const expression then we needn't add it to the
3294+
* ORDER BY clause. This can happen in UNION ALL queries where the
3295+
* union child targetlist has a Const. Adding these would be
3296+
* wasteful, but also, for INT columns, an integer literal would be
3297+
* seen as an ordinal column position rather than a value to sort by.
3298+
* deparseConst() does have code to handle this, but it seems less
3299+
* effort on all accounts just to skip these for ORDER BY clauses.
3300+
*/
3301+
if (IsA(em_expr, Const))
3302+
continue;
3303+
3304+
if (!gotone)
3305+
{
3306+
appendStringInfoString(buf, " ORDER BY ");
3307+
gotone = true;
3308+
}
3309+
else
3310+
appendStringInfoString(buf, ", ");
3311+
32933312
/*
32943313
* Lookup the operator corresponding to the strategy in the opclass.
32953314
* The datatype used by the opfamily is not necessarily the same as
@@ -3304,7 +3323,6 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
33043323
pathkey->pk_strategy, em->em_datatype, em->em_datatype,
33053324
pathkey->pk_opfamily);
33063325

3307-
appendStringInfoString(buf, delim);
33083326
deparseExpr(em_expr, context);
33093327

33103328
/*
@@ -3314,7 +3332,6 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
33143332
appendOrderBySuffix(oprid, exprType((Node *) em_expr),
33153333
pathkey->pk_nulls_first, context);
33163334

3317-
delim = ", ";
33183335
}
33193336
reset_transmission_modes(nestlevel);
33203337
}

contrib/postgres_fdw/expected/postgres_fdw.out

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

875-
-- we should not push order by clause with volatile expressions or unsafe
876-
-- collations
877-
EXPLAIN (VERBOSE, COSTS OFF)
878-
SELECT * FROM ft2 ORDER BY ft2.c1, random();
879-
QUERY PLAN
880-
-------------------------------------------------------------------------------
881-
Sort
882-
Output: c1, c2, c3, c4, c5, c6, c7, c8, (random())
883-
Sort Key: ft2.c1, (random())
884-
-> Foreign Scan on public.ft2
885-
Output: c1, c2, c3, c4, c5, c6, c7, c8, random()
886-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
887-
(6 rows)
888-
889-
EXPLAIN (VERBOSE, COSTS OFF)
890-
SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
891-
QUERY PLAN
892-
-------------------------------------------------------------------------------
893-
Sort
894-
Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text)
895-
Sort Key: ft2.c1, ft2.c3 COLLATE "C"
896-
-> Foreign Scan on public.ft2
897-
Output: c1, c2, c3, c4, c5, c6, c7, c8, c3
898-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
899-
(6 rows)
900-
901875
-- user-defined operator/function
902876
CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$
903877
BEGIN
@@ -1072,6 +1046,73 @@ WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
10721046
642 | '00642':1
10731047
(1 row)
10741048

1049+
-- ===================================================================
1050+
-- ORDER BY queries
1051+
-- ===================================================================
1052+
-- we should not push order by clause with volatile expressions or unsafe
1053+
-- collations
1054+
EXPLAIN (VERBOSE, COSTS OFF)
1055+
SELECT * FROM ft2 ORDER BY ft2.c1, random();
1056+
QUERY PLAN
1057+
-------------------------------------------------------------------------------
1058+
Sort
1059+
Output: c1, c2, c3, c4, c5, c6, c7, c8, (random())
1060+
Sort Key: ft2.c1, (random())
1061+
-> Foreign Scan on public.ft2
1062+
Output: c1, c2, c3, c4, c5, c6, c7, c8, random()
1063+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1064+
(6 rows)
1065+
1066+
EXPLAIN (VERBOSE, COSTS OFF)
1067+
SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
1068+
QUERY PLAN
1069+
-------------------------------------------------------------------------------
1070+
Sort
1071+
Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text)
1072+
Sort Key: ft2.c1, ft2.c3 COLLATE "C"
1073+
-> Foreign Scan on public.ft2
1074+
Output: c1, c2, c3, c4, c5, c6, c7, c8, c3
1075+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1076+
(6 rows)
1077+
1078+
-- Ensure we don't push ORDER BY expressions which are Consts at the UNION
1079+
-- child level to the foreign server.
1080+
EXPLAIN (VERBOSE, COSTS OFF)
1081+
SELECT * FROM (
1082+
SELECT 1 AS type,c1 FROM ft1
1083+
UNION ALL
1084+
SELECT 2 AS type,c1 FROM ft2
1085+
) a ORDER BY type,c1;
1086+
QUERY PLAN
1087+
---------------------------------------------------------------------------------
1088+
Merge Append
1089+
Sort Key: (1), ft1.c1
1090+
-> Foreign Scan on public.ft1
1091+
Output: 1, ft1.c1
1092+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
1093+
-> Foreign Scan on public.ft2
1094+
Output: 2, ft2.c1
1095+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
1096+
(8 rows)
1097+
1098+
EXPLAIN (VERBOSE, COSTS OFF)
1099+
SELECT * FROM (
1100+
SELECT 1 AS type,c1 FROM ft1
1101+
UNION ALL
1102+
SELECT 2 AS type,c1 FROM ft2
1103+
) a ORDER BY type;
1104+
QUERY PLAN
1105+
---------------------------------------------------
1106+
Merge Append
1107+
Sort Key: (1)
1108+
-> Foreign Scan on public.ft1
1109+
Output: 1, ft1.c1
1110+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
1111+
-> Foreign Scan on public.ft2
1112+
Output: 2, ft2.c1
1113+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
1114+
(8 rows)
1115+
10751116
-- ===================================================================
10761117
-- JOIN queries
10771118
-- ===================================================================

contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,6 @@ WHERE a.c2 = 6 AND b.c1 = a.c1 AND a.c8 = 'foo' AND b.c7 = upper(a.c7);
326326
-- bug before 9.3.5 due to sloppy handling of remote-estimate parameters
327327
SELECT * FROM ft1 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft2 WHERE c1 < 5));
328328
SELECT * FROM ft2 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft1 WHERE c1 < 5));
329-
-- we should not push order by clause with volatile expressions or unsafe
330-
-- collations
331-
EXPLAIN (VERBOSE, COSTS OFF)
332-
SELECT * FROM ft2 ORDER BY ft2.c1, random();
333-
EXPLAIN (VERBOSE, COSTS OFF)
334-
SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
335329

336330
-- user-defined operator/function
337331
CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$
@@ -394,6 +388,32 @@ WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
394388
SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1
395389
WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
396390

391+
-- ===================================================================
392+
-- ORDER BY queries
393+
-- ===================================================================
394+
-- we should not push order by clause with volatile expressions or unsafe
395+
-- collations
396+
EXPLAIN (VERBOSE, COSTS OFF)
397+
SELECT * FROM ft2 ORDER BY ft2.c1, random();
398+
EXPLAIN (VERBOSE, COSTS OFF)
399+
SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
400+
401+
-- Ensure we don't push ORDER BY expressions which are Consts at the UNION
402+
-- child level to the foreign server.
403+
EXPLAIN (VERBOSE, COSTS OFF)
404+
SELECT * FROM (
405+
SELECT 1 AS type,c1 FROM ft1
406+
UNION ALL
407+
SELECT 2 AS type,c1 FROM ft2
408+
) a ORDER BY type,c1;
409+
410+
EXPLAIN (VERBOSE, COSTS OFF)
411+
SELECT * FROM (
412+
SELECT 1 AS type,c1 FROM ft1
413+
UNION ALL
414+
SELECT 2 AS type,c1 FROM ft2
415+
) a ORDER BY type;
416+
397417
-- ===================================================================
398418
-- JOIN queries
399419
-- ===================================================================

0 commit comments

Comments
 (0)