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

Commit 3bea3f8

Browse files
committed
postgres_fdw: When sending ORDER BY, always include NULLS FIRST/LAST.
Previously, we included NULLS FIRST when appropriate but relied on the default behavior to be NULLS LAST. This is, however, not true for a sort in descending order and seems like a fragile assumption anyway. Report by Rajkumar Raghuwanshi. Patch by Ashutosh Bapat. Review comments from Michael Paquier and Tom Lane.
1 parent 52fe6f4 commit 3bea3f8

File tree

3 files changed

+125
-31
lines changed

3 files changed

+125
-31
lines changed

contrib/postgres_fdw/deparse.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,6 +2308,8 @@ appendOrderByClause(List *pathkeys, deparse_expr_cxt *context)
23082308

23092309
if (pathkey->pk_nulls_first)
23102310
appendStringInfoString(buf, " NULLS FIRST");
2311+
else
2312+
appendStringInfoString(buf, " NULLS LAST");
23112313

23122314
delim = ", ";
23132315
}

contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 111 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,13 @@ SELECT * FROM ft1 t1 ORDER BY t1.c3, t1.c1, t1.tableoid OFFSET 100 LIMIT 10;
245245

246246
-- whole-row reference
247247
EXPLAIN (VERBOSE, COSTS false) SELECT t1 FROM ft1 t1 ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
248-
QUERY PLAN
249-
----------------------------------------------------------------------------------------------------------
248+
QUERY PLAN
249+
--------------------------------------------------------------------------------------------------------------------------------
250250
Limit
251251
Output: t1.*, c3, c1
252252
-> Foreign Scan on public.ft1 t1
253253
Output: t1.*, c3, c1
254-
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY c3 ASC, "C 1" ASC
254+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY c3 ASC NULLS LAST, "C 1" ASC NULLS LAST
255255
(5 rows)
256256

257257
SELECT t1 FROM ft1 t1 ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
@@ -382,16 +382,16 @@ SET enable_nestloop TO false;
382382
-- inner join; expressions in the clauses appear in the equivalence class list
383383
EXPLAIN (VERBOSE, COSTS false)
384384
SELECT t1.c1, t2."C 1" FROM ft2 t1 JOIN "S 1"."T 1" t2 ON (t1.c1 = t2."C 1") OFFSET 100 LIMIT 10;
385-
QUERY PLAN
386-
----------------------------------------------------------------------------
385+
QUERY PLAN
386+
---------------------------------------------------------------------------------------
387387
Limit
388388
Output: t1.c1, t2."C 1"
389389
-> Merge Join
390390
Output: t1.c1, t2."C 1"
391391
Merge Cond: (t1.c1 = t2."C 1")
392392
-> Foreign Scan on public.ft2 t1
393393
Output: t1.c1
394-
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC
394+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
395395
-> Index Only Scan using t1_pkey on "S 1"."T 1" t2
396396
Output: t2."C 1"
397397
(10 rows)
@@ -415,16 +415,16 @@ SELECT t1.c1, t2."C 1" FROM ft2 t1 JOIN "S 1"."T 1" t2 ON (t1.c1 = t2."C 1") OFF
415415
-- list but no output change as compared to the previous query
416416
EXPLAIN (VERBOSE, COSTS false)
417417
SELECT t1.c1, t2."C 1" FROM ft2 t1 LEFT JOIN "S 1"."T 1" t2 ON (t1.c1 = t2."C 1") OFFSET 100 LIMIT 10;
418-
QUERY PLAN
419-
----------------------------------------------------------------------------
418+
QUERY PLAN
419+
---------------------------------------------------------------------------------------
420420
Limit
421421
Output: t1.c1, t2."C 1"
422422
-> Merge Left Join
423423
Output: t1.c1, t2."C 1"
424424
Merge Cond: (t1.c1 = t2."C 1")
425425
-> Foreign Scan on public.ft2 t1
426426
Output: t1.c1
427-
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC
427+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
428428
-> Index Only Scan using t1_pkey on "S 1"."T 1" t2
429429
Output: t2."C 1"
430430
(10 rows)
@@ -1341,21 +1341,21 @@ SELECT t1.ctid, t1, t2, t1.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER B
13411341
-- SEMI JOIN, not pushed down
13421342
EXPLAIN (COSTS false, VERBOSE)
13431343
SELECT t1.c1 FROM ft1 t1 WHERE EXISTS (SELECT 1 FROM ft2 t2 WHERE t1.c1 = t2.c1) ORDER BY t1.c1 OFFSET 100 LIMIT 10;
1344-
QUERY PLAN
1345-
----------------------------------------------------------------------------------
1344+
QUERY PLAN
1345+
---------------------------------------------------------------------------------------------
13461346
Limit
13471347
Output: t1.c1
13481348
-> Merge Semi Join
13491349
Output: t1.c1
13501350
Merge Cond: (t1.c1 = t2.c1)
13511351
-> Foreign Scan on public.ft1 t1
13521352
Output: t1.c1
1353-
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC
1353+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
13541354
-> Materialize
13551355
Output: t2.c1
13561356
-> Foreign Scan on public.ft2 t2
13571357
Output: t2.c1
1358-
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC
1358+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
13591359
(13 rows)
13601360

13611361
SELECT t1.c1 FROM ft1 t1 WHERE EXISTS (SELECT 1 FROM ft2 t2 WHERE t1.c1 = t2.c1) ORDER BY t1.c1 OFFSET 100 LIMIT 10;
@@ -1376,21 +1376,21 @@ SELECT t1.c1 FROM ft1 t1 WHERE EXISTS (SELECT 1 FROM ft2 t2 WHERE t1.c1 = t2.c1)
13761376
-- ANTI JOIN, not pushed down
13771377
EXPLAIN (COSTS false, VERBOSE)
13781378
SELECT t1.c1 FROM ft1 t1 WHERE NOT EXISTS (SELECT 1 FROM ft2 t2 WHERE t1.c1 = t2.c2) ORDER BY t1.c1 OFFSET 100 LIMIT 10;
1379-
QUERY PLAN
1380-
----------------------------------------------------------------------------
1379+
QUERY PLAN
1380+
---------------------------------------------------------------------------------------
13811381
Limit
13821382
Output: t1.c1
13831383
-> Merge Anti Join
13841384
Output: t1.c1
13851385
Merge Cond: (t1.c1 = t2.c2)
13861386
-> Foreign Scan on public.ft1 t1
13871387
Output: t1.c1
1388-
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC
1388+
Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
13891389
-> Materialize
13901390
Output: t2.c2
13911391
-> Foreign Scan on public.ft2 t2
13921392
Output: t2.c2
1393-
Remote SQL: SELECT c2 FROM "S 1"."T 1" ORDER BY c2 ASC
1393+
Remote SQL: SELECT c2 FROM "S 1"."T 1" ORDER BY c2 ASC NULLS LAST
13941394
(13 rows)
13951395

13961396
SELECT t1.c1 FROM ft1 t1 WHERE NOT EXISTS (SELECT 1 FROM ft2 t2 WHERE t1.c1 = t2.c2) ORDER BY t1.c1 OFFSET 100 LIMIT 10;
@@ -1448,21 +1448,21 @@ SELECT t1.c1, t2.c1 FROM ft1 t1 CROSS JOIN ft2 t2 ORDER BY t1.c1, t2.c1 OFFSET 1
14481448
-- different server, not pushed down. No result expected.
14491449
EXPLAIN (COSTS false, VERBOSE)
14501450
SELECT t1.c1, t2.c1 FROM ft5 t1 JOIN ft6 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
1451-
QUERY PLAN
1452-
----------------------------------------------------------------------------
1451+
QUERY PLAN
1452+
---------------------------------------------------------------------------------------
14531453
Limit
14541454
Output: t1.c1, t2.c1
14551455
-> Merge Join
14561456
Output: t1.c1, t2.c1
14571457
Merge Cond: (t2.c1 = t1.c1)
14581458
-> Foreign Scan on public.ft6 t2
14591459
Output: t2.c1, t2.c2, t2.c3
1460-
Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC
1460+
Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC NULLS LAST
14611461
-> Materialize
14621462
Output: t1.c1, t1.c2, t1.c3
14631463
-> Foreign Scan on public.ft5 t1
14641464
Output: t1.c1, t1.c2, t1.c3
1465-
Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC
1465+
Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC NULLS LAST
14661466
(13 rows)
14671467

14681468
SELECT t1.c1, t2.c1 FROM ft5 t1 JOIN ft6 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
@@ -1746,21 +1746,21 @@ EXECUTE join_stmt;
17461746
-- different user mappings
17471747
CREATE USER MAPPING FOR view_owner SERVER loopback;
17481748
EXPLAIN (COSTS false, VERBOSE) EXECUTE join_stmt;
1749-
QUERY PLAN
1750-
----------------------------------------------------------------------------
1749+
QUERY PLAN
1750+
---------------------------------------------------------------------------------------
17511751
Limit
17521752
Output: t1.c1, ft5.c1
17531753
-> Merge Join
17541754
Output: t1.c1, ft5.c1
17551755
Merge Cond: (t1.c1 = ft5.c1)
17561756
-> Foreign Scan on public.ft5 t1
17571757
Output: t1.c1, t1.c2, t1.c3
1758-
Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC
1758+
Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC NULLS LAST
17591759
-> Materialize
17601760
Output: ft5.c1, ft5.c2, ft5.c3
17611761
-> Foreign Scan on public.ft5
17621762
Output: ft5.c1, ft5.c2, ft5.c3
1763-
Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC
1763+
Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC NULLS LAST
17641764
(13 rows)
17651765

17661766
EXECUTE join_stmt;
@@ -3813,6 +3813,86 @@ select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
38133813
407 | 100
38143814
(13 rows)
38153815

3816+
-- Above DMLs add data with c6 as NULL in ft1, so test ORDER BY NULLS LAST and NULLs
3817+
-- FIRST behavior here.
3818+
-- ORDER BY DESC NULLS LAST options
3819+
EXPLAIN (VERBOSE, COSTS false) SELECT * FROM ft1 ORDER BY c6 DESC NULLS LAST, c1 OFFSET 795 LIMIT 10;
3820+
QUERY PLAN
3821+
---------------------------------------------------------------------------------------------------------------------------------
3822+
Limit
3823+
Output: c1, c2, c3, c4, c5, c6, c7, c8
3824+
-> Foreign Scan on public.ft1
3825+
Output: c1, c2, c3, c4, c5, c6, c7, c8
3826+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY c6 DESC NULLS LAST, "C 1" ASC NULLS LAST
3827+
(5 rows)
3828+
3829+
SELECT * FROM ft1 ORDER BY c6 DESC NULLS LAST, c1 OFFSET 795 LIMIT 10;
3830+
c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
3831+
------+-----+--------------------+------------------------------+--------------------------+------+------------+-----
3832+
960 | 42 | 00960_trig_update | Mon Mar 02 00:00:00 1970 PST | Mon Mar 02 00:00:00 1970 | 0 | 0 | foo
3833+
970 | 42 | 00970_trig_update | Thu Mar 12 00:00:00 1970 PST | Thu Mar 12 00:00:00 1970 | 0 | 0 | foo
3834+
980 | 42 | 00980_trig_update | Sun Mar 22 00:00:00 1970 PST | Sun Mar 22 00:00:00 1970 | 0 | 0 | foo
3835+
990 | 42 | 00990_trig_update | Wed Apr 01 00:00:00 1970 PST | Wed Apr 01 00:00:00 1970 | 0 | 0 | foo
3836+
1000 | 42 | 01000_trig_update | Thu Jan 01 00:00:00 1970 PST | Thu Jan 01 00:00:00 1970 | 0 | 0 | foo
3837+
1218 | 818 | ggg_trig_update | | | (--; | ft2 |
3838+
1001 | 101 | 0000100001 | | | | ft2 |
3839+
1003 | 403 | 0000300003_update3 | | | | ft2 |
3840+
1004 | 104 | 0000400004 | | | | ft2 |
3841+
1006 | 106 | 0000600006 | | | | ft2 |
3842+
(10 rows)
3843+
3844+
-- ORDER BY DESC NULLS FIRST options
3845+
EXPLAIN (VERBOSE, COSTS false) SELECT * FROM ft1 ORDER BY c6 DESC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
3846+
QUERY PLAN
3847+
----------------------------------------------------------------------------------------------------------------------------------
3848+
Limit
3849+
Output: c1, c2, c3, c4, c5, c6, c7, c8
3850+
-> Foreign Scan on public.ft1
3851+
Output: c1, c2, c3, c4, c5, c6, c7, c8
3852+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY c6 DESC NULLS FIRST, "C 1" ASC NULLS LAST
3853+
(5 rows)
3854+
3855+
SELECT * FROM ft1 ORDER BY c6 DESC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
3856+
c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
3857+
------+-----+-----------------+------------------------------+--------------------------+----+------------+-----
3858+
1020 | 100 | 0002000020 | | | | ft2 |
3859+
1101 | 201 | aaa | | | | ft2 |
3860+
1103 | 503 | ccc_update3 | | | | ft2 |
3861+
1104 | 204 | ddd | | | | ft2 |
3862+
1208 | 818 | fff_trig_update | | | | ft2 |
3863+
9 | 509 | 00009_update9 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9 | ft2 | foo
3864+
19 | 509 | 00019_update9 | Tue Jan 20 00:00:00 1970 PST | Tue Jan 20 00:00:00 1970 | 9 | ft2 | foo
3865+
29 | 509 | 00029_update9 | Fri Jan 30 00:00:00 1970 PST | Fri Jan 30 00:00:00 1970 | 9 | ft2 | foo
3866+
39 | 509 | 00039_update9 | Mon Feb 09 00:00:00 1970 PST | Mon Feb 09 00:00:00 1970 | 9 | ft2 | foo
3867+
49 | 509 | 00049_update9 | Thu Feb 19 00:00:00 1970 PST | Thu Feb 19 00:00:00 1970 | 9 | ft2 | foo
3868+
(10 rows)
3869+
3870+
-- ORDER BY ASC NULLS FIRST options
3871+
EXPLAIN (VERBOSE, COSTS false) SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
3872+
QUERY PLAN
3873+
---------------------------------------------------------------------------------------------------------------------------------
3874+
Limit
3875+
Output: c1, c2, c3, c4, c5, c6, c7, c8
3876+
-> Foreign Scan on public.ft1
3877+
Output: c1, c2, c3, c4, c5, c6, c7, c8
3878+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY c6 ASC NULLS FIRST, "C 1" ASC NULLS LAST
3879+
(5 rows)
3880+
3881+
SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
3882+
c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
3883+
------+-----+-------------------+------------------------------+--------------------------+------+------------+-----
3884+
1020 | 100 | 0002000020 | | | | ft2 |
3885+
1101 | 201 | aaa | | | | ft2 |
3886+
1103 | 503 | ccc_update3 | | | | ft2 |
3887+
1104 | 204 | ddd | | | | ft2 |
3888+
1208 | 818 | fff_trig_update | | | | ft2 |
3889+
1218 | 818 | ggg_trig_update | | | (--; | ft2 |
3890+
10 | 42 | 00010_trig_update | Sun Jan 11 00:00:00 1970 PST | Sun Jan 11 00:00:00 1970 | 0 | 0 | foo
3891+
20 | 42 | 00020_trig_update | Wed Jan 21 00:00:00 1970 PST | Wed Jan 21 00:00:00 1970 | 0 | 0 | foo
3892+
30 | 42 | 00030_trig_update | Sat Jan 31 00:00:00 1970 PST | Sat Jan 31 00:00:00 1970 | 0 | 0 | foo
3893+
40 | 42 | 00040_trig_update | Tue Feb 10 00:00:00 1970 PST | Tue Feb 10 00:00:00 1970 | 0 | 0 | foo
3894+
(10 rows)
3895+
38163896
-- ===================================================================
38173897
-- test check constraints
38183898
-- ===================================================================
@@ -4630,8 +4710,8 @@ analyze loct1;
46304710
-- inner join; expressions in the clauses appear in the equivalence class list
46314711
explain (verbose, costs off)
46324712
select foo.f1, loct1.f1 from foo join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
4633-
QUERY PLAN
4634-
---------------------------------------------------------------------------------------
4713+
QUERY PLAN
4714+
--------------------------------------------------------------------------------------------------
46354715
Limit
46364716
Output: foo.f1, loct1.f1, foo.f2
46374717
-> Sort
@@ -4646,7 +4726,7 @@ explain (verbose, costs off)
46464726
Output: foo.f1, foo.f2
46474727
-> Foreign Scan on public.foo2
46484728
Output: foo2.f1, foo2.f2
4649-
Remote SQL: SELECT f1, f2 FROM public.loct1 ORDER BY f1 ASC
4729+
Remote SQL: SELECT f1, f2 FROM public.loct1 ORDER BY f1 ASC NULLS LAST
46504730
-> Index Only Scan using i_loct1_f1 on public.loct1
46514731
Output: loct1.f1
46524732
(17 rows)
@@ -4670,8 +4750,8 @@ select foo.f1, loct1.f1 from foo join loct1 on (foo.f1 = loct1.f1) order by foo.
46704750
-- list but no output change as compared to the previous query
46714751
explain (verbose, costs off)
46724752
select foo.f1, loct1.f1 from foo left join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
4673-
QUERY PLAN
4674-
---------------------------------------------------------------------------------------
4753+
QUERY PLAN
4754+
--------------------------------------------------------------------------------------------------
46754755
Limit
46764756
Output: foo.f1, loct1.f1, foo.f2
46774757
-> Sort
@@ -4686,7 +4766,7 @@ explain (verbose, costs off)
46864766
Output: foo.f1, foo.f2
46874767
-> Foreign Scan on public.foo2
46884768
Output: foo2.f1, foo2.f2
4689-
Remote SQL: SELECT f1, f2 FROM public.loct1 ORDER BY f1 ASC
4769+
Remote SQL: SELECT f1, f2 FROM public.loct1 ORDER BY f1 ASC NULLS LAST
46904770
-> Index Only Scan using i_loct1_f1 on public.loct1
46914771
Output: loct1.f1
46924772
(17 rows)

contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,18 @@ commit;
677677
select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
678678
select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
679679

680+
-- Above DMLs add data with c6 as NULL in ft1, so test ORDER BY NULLS LAST and NULLs
681+
-- FIRST behavior here.
682+
-- ORDER BY DESC NULLS LAST options
683+
EXPLAIN (VERBOSE, COSTS false) SELECT * FROM ft1 ORDER BY c6 DESC NULLS LAST, c1 OFFSET 795 LIMIT 10;
684+
SELECT * FROM ft1 ORDER BY c6 DESC NULLS LAST, c1 OFFSET 795 LIMIT 10;
685+
-- ORDER BY DESC NULLS FIRST options
686+
EXPLAIN (VERBOSE, COSTS false) SELECT * FROM ft1 ORDER BY c6 DESC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
687+
SELECT * FROM ft1 ORDER BY c6 DESC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
688+
-- ORDER BY ASC NULLS FIRST options
689+
EXPLAIN (VERBOSE, COSTS false) SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
690+
SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
691+
680692
-- ===================================================================
681693
-- test check constraints
682694
-- ===================================================================

0 commit comments

Comments
 (0)