products/Sources/formale Sprachen/C/Postgres/src/backend/access/gin/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 24 kB image not shown  

Impressum join.out   Sprache: unbekannt

 
Spracherkennung für: .out vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

--
-- JOIN
-- Test JOIN clauses
--
CREATE TABLE J1_TBL (
  i integer,
  j integer,
  t text
);
CREATE TABLE J2_TBL (
  i integer,
  k integer
);
INSERT INTO J1_TBL VALUES (14, 'one');
INSERT INTO J1_TBL VALUES (23, 'two');
INSERT INTO J1_TBL VALUES (32, 'three');
INSERT INTO J1_TBL VALUES (41, 'four');
INSERT INTO J1_TBL VALUES (50, 'five');
INSERT INTO J1_TBL VALUES (66, 'six');
INSERT INTO J1_TBL VALUES (77, 'seven');
INSERT INTO J1_TBL VALUES (88, 'eight');
INSERT INTO J1_TBL VALUES (0, NULL, 'zero');
INSERT INTO J1_TBL VALUES (NULL, NULL, 'null');
INSERT INTO J1_TBL VALUES (NULL, 0, 'zero');
INSERT INTO J2_TBL VALUES (1, -1);
INSERT INTO J2_TBL VALUES (22);
INSERT INTO J2_TBL VALUES (3, -3);
INSERT INTO J2_TBL VALUES (24);
INSERT INTO J2_TBL VALUES (5, -5);
INSERT INTO J2_TBL VALUES (5, -5);
INSERT INTO J2_TBL VALUES (0, NULL);
INSERT INTO J2_TBL VALUES (NULL, NULL);
INSERT INTO J2_TBL VALUES (NULL, 0);
-- useful in some tests below
create temp table onerow();
insert into onerow default values;
analyze onerow;
--
-- CORRELATION NAMES
-- Make sure that table/column aliases are supported
-- before diving into more complex join syntax.
--
SELECT *
  FROM J1_TBL AS tx;
 i | j |   t   
---+---+-------
 1 | 4 | one
 2 | 3 | two
 3 | 2 | three
 4 | 1 | four
 5 | 0 | five
 6 | 6 | six
 7 | 7 | seven
 8 | 8 | eight
 0 |   | zero
   |   | null
   | 0 | zero
(11 rows)

SELECT *
  FROM J1_TBL tx;
 i | j |   t   
---+---+-------
 1 | 4 | one
 2 | 3 | two
 3 | 2 | three
 4 | 1 | four
 5 | 0 | five
 6 | 6 | six
 7 | 7 | seven
 8 | 8 | eight
 0 |   | zero
   |   | null
   | 0 | zero
(11 rows)

SELECT *
  FROM J1_TBL AS t1 (a, b, c);
 a | b |   c   
---+---+-------
 1 | 4 | one
 2 | 3 | two
 3 | 2 | three
 4 | 1 | four
 5 | 0 | five
 6 | 6 | six
 7 | 7 | seven
 8 | 8 | eight
 0 |   | zero
   |   | null
   | 0 | zero
(11 rows)

SELECT *
  FROM J1_TBL t1 (a, b, c);
 a | b |   c   
---+---+-------
 1 | 4 | one
 2 | 3 | two
 3 | 2 | three
 4 | 1 | four
 5 | 0 | five
 6 | 6 | six
 7 | 7 | seven
 8 | 8 | eight
 0 |   | zero
   |   | null
   | 0 | zero
(11 rows)

SELECT *
  FROM J1_TBL t1 (a, b, c), J2_TBL t2 (d, e);
 a | b |   c   | d | e  
---+---+-------+---+----
 1 | 4 | one   | 1 | -1
 2 | 3 | two   | 1 | -1
 3 | 2 | three | 1 | -1
 4 | 1 | four  | 1 | -1
 5 | 0 | five  | 1 | -1
 6 | 6 | six   | 1 | -1
 7 | 7 | seven | 1 | -1
 8 | 8 | eight | 1 | -1
 0 |   | zero  | 1 | -1
   |   | null  | 1 | -1
   | 0 | zero  | 1 | -1
 1 | 4 | one   | 2 |  2
 2 | 3 | two   | 2 |  2
 3 | 2 | three | 2 |  2
 4 | 1 | four  | 2 |  2
 5 | 0 | five  | 2 |  2
 6 | 6 | six   | 2 |  2
 7 | 7 | seven | 2 |  2
 8 | 8 | eight | 2 |  2
 0 |   | zero  | 2 |  2
   |   | null  | 2 |  2
   | 0 | zero  | 2 |  2
 1 | 4 | one   | 3 | -3
 2 | 3 | two   | 3 | -3
 3 | 2 | three | 3 | -3
 4 | 1 | four  | 3 | -3
 5 | 0 | five  | 3 | -3
 6 | 6 | six   | 3 | -3
 7 | 7 | seven | 3 | -3
 8 | 8 | eight | 3 | -3
 0 |   | zero  | 3 | -3
   |   | null  | 3 | -3
   | 0 | zero  | 3 | -3
 1 | 4 | one   | 2 |  4
 2 | 3 | two   | 2 |  4
 3 | 2 | three | 2 |  4
 4 | 1 | four  | 2 |  4
 5 | 0 | five  | 2 |  4
 6 | 6 | six   | 2 |  4
 7 | 7 | seven | 2 |  4
 8 | 8 | eight | 2 |  4
 0 |   | zero  | 2 |  4
   |   | null  | 2 |  4
   | 0 | zero  | 2 |  4
 1 | 4 | one   | 5 | -5
 2 | 3 | two   | 5 | -5
 3 | 2 | three | 5 | -5
 4 | 1 | four  | 5 | -5
 5 | 0 | five  | 5 | -5
 6 | 6 | six   | 5 | -5
 7 | 7 | seven | 5 | -5
 8 | 8 | eight | 5 | -5
 0 |   | zero  | 5 | -5
   |   | null  | 5 | -5
   | 0 | zero  | 5 | -5
 1 | 4 | one   | 5 | -5
 2 | 3 | two   | 5 | -5
 3 | 2 | three | 5 | -5
 4 | 1 | four  | 5 | -5
 5 | 0 | five  | 5 | -5
 6 | 6 | six   | 5 | -5
 7 | 7 | seven | 5 | -5
 8 | 8 | eight | 5 | -5
 0 |   | zero  | 5 | -5
   |   | null  | 5 | -5
   | 0 | zero  | 5 | -5
 1 | 4 | one   | 0 |   
 2 | 3 | two   | 0 |   
 3 | 2 | three | 0 |   
 4 | 1 | four  | 0 |   
 5 | 0 | five  | 0 |   
 6 | 6 | six   | 0 |   
 7 | 7 | seven | 0 |   
 8 | 8 | eight | 0 |   
 0 |   | zero  | 0 |   
   |   | null  | 0 |   
   | 0 | zero  | 0 |   
 1 | 4 | one   |   |   
 2 | 3 | two   |   |   
 3 | 2 | three |   |   
 4 | 1 | four  |   |   
 5 | 0 | five  |   |   
 6 | 6 | six   |   |   
 7 | 7 | seven |   |   
 8 | 8 | eight |   |   
 0 |   | zero  |   |   
   |   | null  |   |   
   | 0 | zero  |   |   
 1 | 4 | one   |   |  0
 2 | 3 | two   |   |  0
 3 | 2 | three |   |  0
 4 | 1 | four  |   |  0
 5 | 0 | five  |   |  0
 6 | 6 | six   |   |  0
 7 | 7 | seven |   |  0
 8 | 8 | eight |   |  0
 0 |   | zero  |   |  0
   |   | null  |   |  0
   | 0 | zero  |   |  0
(99 rows)

SELECT t1.a, t2.e
  FROM J1_TBL t1 (a, b, c), J2_TBL t2 (d, e)
  WHERE t1.a = t2.d;
 a | e  
---+----
 0 |   
 1 | -1
 2 |  2
 2 |  4
 3 | -3
 5 | -5
 5 | -5
(7 rows)

--
-- CROSS JOIN
-- Qualifications are not allowed on cross joins,
-- which degenerate into a standard unqualified inner join.
--
SELECT *
  FROM J1_TBL CROSS JOIN J2_TBL;
 i | j |   t   | i | k  
---+---+-------+---+----
 1 | 4 | one   | 1 | -1
 2 | 3 | two   | 1 | -1
 3 | 2 | three | 1 | -1
 4 | 1 | four  | 1 | -1
 5 | 0 | five  | 1 | -1
 6 | 6 | six   | 1 | -1
 7 | 7 | seven | 1 | -1
 8 | 8 | eight | 1 | -1
 0 |   | zero  | 1 | -1
   |   | null  | 1 | -1
   | 0 | zero  | 1 | -1
 1 | 4 | one   | 2 |  2
 2 | 3 | two   | 2 |  2
 3 | 2 | three | 2 |  2
 4 | 1 | four  | 2 |  2
 5 | 0 | five  | 2 |  2
 6 | 6 | six   | 2 |  2
 7 | 7 | seven | 2 |  2
 8 | 8 | eight | 2 |  2
 0 |   | zero  | 2 |  2
   |   | null  | 2 |  2
   | 0 | zero  | 2 |  2
 1 | 4 | one   | 3 | -3
 2 | 3 | two   | 3 | -3
 3 | 2 | three | 3 | -3
 4 | 1 | four  | 3 | -3
 5 | 0 | five  | 3 | -3
 6 | 6 | six   | 3 | -3
 7 | 7 | seven | 3 | -3
 8 | 8 | eight | 3 | -3
 0 |   | zero  | 3 | -3
   |   | null  | 3 | -3
   | 0 | zero  | 3 | -3
 1 | 4 | one   | 2 |  4
 2 | 3 | two   | 2 |  4
 3 | 2 | three | 2 |  4
 4 | 1 | four  | 2 |  4
 5 | 0 | five  | 2 |  4
 6 | 6 | six   | 2 |  4
 7 | 7 | seven | 2 |  4
 8 | 8 | eight | 2 |  4
 0 |   | zero  | 2 |  4
   |   | null  | 2 |  4
   | 0 | zero  | 2 |  4
 1 | 4 | one   | 5 | -5
 2 | 3 | two   | 5 | -5
 3 | 2 | three | 5 | -5
 4 | 1 | four  | 5 | -5
 5 | 0 | five  | 5 | -5
 6 | 6 | six   | 5 | -5
 7 | 7 | seven | 5 | -5
 8 | 8 | eight | 5 | -5
 0 |   | zero  | 5 | -5
   |   | null  | 5 | -5
   | 0 | zero  | 5 | -5
 1 | 4 | one   | 5 | -5
 2 | 3 | two   | 5 | -5
 3 | 2 | three | 5 | -5
 4 | 1 | four  | 5 | -5
 5 | 0 | five  | 5 | -5
 6 | 6 | six   | 5 | -5
 7 | 7 | seven | 5 | -5
 8 | 8 | eight | 5 | -5
 0 |   | zero  | 5 | -5
   |   | null  | 5 | -5
   | 0 | zero  | 5 | -5
 1 | 4 | one   | 0 |   
 2 | 3 | two   | 0 |   
 3 | 2 | three | 0 |   
 4 | 1 | four  | 0 |   
 5 | 0 | five  | 0 |   
 6 | 6 | six   | 0 |   
 7 | 7 | seven | 0 |   
 8 | 8 | eight | 0 |   
 0 |   | zero  | 0 |   
   |   | null  | 0 |   
   | 0 | zero  | 0 |   
 1 | 4 | one   |   |   
 2 | 3 | two   |   |   
 3 | 2 | three |   |   
 4 | 1 | four  |   |   
 5 | 0 | five  |   |   
 6 | 6 | six   |   |   
 7 | 7 | seven |   |   
 8 | 8 | eight |   |   
 0 |   | zero  |   |   
   |   | null  |   |   
   | 0 | zero  |   |   
 1 | 4 | one   |   |  0
 2 | 3 | two   |   |  0
 3 | 2 | three |   |  0
 4 | 1 | four  |   |  0
 5 | 0 | five  |   |  0
 6 | 6 | six   |   |  0
 7 | 7 | seven |   |  0
 8 | 8 | eight |   |  0
 0 |   | zero  |   |  0
   |   | null  |   |  0
   | 0 | zero  |   |  0
(99 rows)

-- ambiguous column
SELECT i, k, t
  FROM J1_TBL CROSS JOIN J2_TBL;
ERROR:  column reference "i" is ambiguous
LINE 1: SELECT i, k, t
               ^
-- resolve previous ambiguity by specifying the table name
SELECT t1.i, k, t
  FROM J1_TBL t1 CROSS JOIN J2_TBL t2;
 i | k  |   t   
---+----+-------
 1 | -1 | one
 2 | -1 | two
 3 | -1 | three
 4 | -1 | four
 5 | -1 | five
 6 | -1 | six
 7 | -1 | seven
 8 | -1 | eight
 0 | -1 | zero
   | -1 | null
   | -1 | zero
 1 |  2 | one
 2 |  2 | two
 3 |  2 | three
 4 |  2 | four
 5 |  2 | five
 6 |  2 | six
 7 |  2 | seven
 8 |  2 | eight
 0 |  2 | zero
   |  2 | null
   |  2 | zero
 1 | -3 | one
 2 | -3 | two
 3 | -3 | three
 4 | -3 | four
 5 | -3 | five
 6 | -3 | six
 7 | -3 | seven
 8 | -3 | eight
 0 | -3 | zero
   | -3 | null
   | -3 | zero
 1 |  4 | one
 2 |  4 | two
 3 |  4 | three
 4 |  4 | four
 5 |  4 | five
 6 |  4 | six
 7 |  4 | seven
 8 |  4 | eight
 0 |  4 | zero
   |  4 | null
   |  4 | zero
 1 | -5 | one
 2 | -5 | two
 3 | -5 | three
 4 | -5 | four
 5 | -5 | five
 6 | -5 | six
 7 | -5 | seven
 8 | -5 | eight
 0 | -5 | zero
   | -5 | null
   | -5 | zero
 1 | -5 | one
 2 | -5 | two
 3 | -5 | three
 4 | -5 | four
 5 | -5 | five
 6 | -5 | six
 7 | -5 | seven
 8 | -5 | eight
 0 | -5 | zero
   | -5 | null
   | -5 | zero
 1 |    | one
 2 |    | two
 3 |    | three
 4 |    | four
 5 |    | five
 6 |    | six
 7 |    | seven
 8 |    | eight
 0 |    | zero
   |    | null
   |    | zero
 1 |    | one
 2 |    | two
 3 |    | three
 4 |    | four
 5 |    | five
 6 |    | six
 7 |    | seven
 8 |    | eight
 0 |    | zero
   |    | null
   |    | zero
 1 |  0 | one
 2 |  0 | two
 3 |  0 | three
 4 |  0 | four
 5 |  0 | five
 6 |  0 | six
 7 |  0 | seven
 8 |  0 | eight
 0 |  0 | zero
   |  0 | null
   |  0 | zero
(99 rows)

SELECT ii, tt, kk
  FROM (J1_TBL CROSS JOIN J2_TBL)
    AS tx (ii, jj, tt, ii2, kk);
 ii |  tt   | kk 
----+-------+----
  1 | one   | -1
  2 | two   | -1
  3 | three | -1
  4 | four  | -1
  5 | five  | -1
  6 | six   | -1
  7 | seven | -1
  8 | eight | -1
  0 | zero  | -1
    | null  | -1
    | zero  | -1
  1 | one   |  2
  2 | two   |  2
  3 | three |  2
  4 | four  |  2
  5 | five  |  2
  6 | six   |  2
  7 | seven |  2
  8 | eight |  2
  0 | zero  |  2
    | null  |  2
    | zero  |  2
  1 | one   | -3
  2 | two   | -3
  3 | three | -3
  4 | four  | -3
  5 | five  | -3
  6 | six   | -3
  7 | seven | -3
  8 | eight | -3
  0 | zero  | -3
    | null  | -3
    | zero  | -3
  1 | one   |  4
  2 | two   |  4
  3 | three |  4
  4 | four  |  4
  5 | five  |  4
  6 | six   |  4
  7 | seven |  4
  8 | eight |  4
  0 | zero  |  4
    | null  |  4
    | zero  |  4
  1 | one   | -5
  2 | two   | -5
  3 | three | -5
  4 | four  | -5
  5 | five  | -5
  6 | six   | -5
  7 | seven | -5
  8 | eight | -5
  0 | zero  | -5
    | null  | -5
    | zero  | -5
  1 | one   | -5
  2 | two   | -5
  3 | three | -5
  4 | four  | -5
  5 | five  | -5
  6 | six   | -5
  7 | seven | -5
  8 | eight | -5
  0 | zero  | -5
    | null  | -5
    | zero  | -5
  1 | one   |   
  2 | two   |   
  3 | three |   
  4 | four  |   
  5 | five  |   
  6 | six   |   
  7 | seven |   
  8 | eight |   
  0 | zero  |   
    | null  |   
    | zero  |   
  1 | one   |   
  2 | two   |   
  3 | three |   
  4 | four  |   
  5 | five  |   
  6 | six   |   
  7 | seven |   
  8 | eight |   
  0 | zero  |   
    | null  |   
    | zero  |   
  1 | one   |  0
  2 | two   |  0
  3 | three |  0
  4 | four  |  0
  5 | five  |  0
  6 | six   |  0
  7 | seven |  0
  8 | eight |  0
  0 | zero  |  0
    | null  |  0
    | zero  |  0
(99 rows)

SELECT tx.ii, tx.jj, tx.kk
  FROM (J1_TBL t1 (a, b, c) CROSS JOIN J2_TBL t2 (d, e))
    AS tx (ii, jj, tt, ii2, kk);
 ii | jj | kk 
----+----+----
  1 |  4 | -1
  2 |  3 | -1
  3 |  2 | -1
  4 |  1 | -1
  5 |  0 | -1
  6 |  6 | -1
  7 |  7 | -1
  8 |  8 | -1
  0 |    | -1
    |    | -1
    |  0 | -1
  1 |  4 |  2
  2 |  3 |  2
  3 |  2 |  2
  4 |  1 |  2
  5 |  0 |  2
  6 |  6 |  2
  7 |  7 |  2
  8 |  8 |  2
  0 |    |  2
    |    |  2
    |  0 |  2
  1 |  4 | -3
  2 |  3 | -3
  3 |  2 | -3
  4 |  1 | -3
  5 |  0 | -3
  6 |  6 | -3
  7 |  7 | -3
  8 |  8 | -3
  0 |    | -3
    |    | -3
    |  0 | -3
  1 |  4 |  4
  2 |  3 |  4
  3 |  2 |  4
  4 |  1 |  4
  5 |  0 |  4
  6 |  6 |  4
  7 |  7 |  4
  8 |  8 |  4
  0 |    |  4
    |    |  4
    |  0 |  4
  1 |  4 | -5
  2 |  3 | -5
  3 |  2 | -5
  4 |  1 | -5
  5 |  0 | -5
  6 |  6 | -5
  7 |  7 | -5
  8 |  8 | -5
  0 |    | -5
    |    | -5
    |  0 | -5
  1 |  4 | -5
  2 |  3 | -5
  3 |  2 | -5
  4 |  1 | -5
  5 |  0 | -5
  6 |  6 | -5
  7 |  7 | -5
  8 |  8 | -5
  0 |    | -5
    |    | -5
    |  0 | -5
  1 |  4 |   
  2 |  3 |   
  3 |  2 |   
  4 |  1 |   
  5 |  0 |   
  6 |  6 |   
  7 |  7 |   
  8 |  8 |   
  0 |    |   
    |    |   
    |  0 |   
  1 |  4 |   
  2 |  3 |   
  3 |  2 |   
  4 |  1 |   
  5 |  0 |   
  6 |  6 |   
  7 |  7 |   
  8 |  8 |   
  0 |    |   
    |    |   
    |  0 |   
  1 |  4 |  0
  2 |  3 |  0
  3 |  2 |  0
  4 |  1 |  0
  5 |  0 |  0
  6 |  6 |  0
  7 |  7 |  0
  8 |  8 |  0
  0 |    |  0
    |    |  0
    |  0 |  0
(99 rows)

SELECT *
  FROM J1_TBL CROSS JOIN J2_TBL a CROSS JOIN J2_TBL b;
 i | j |   t   | i | k  | i | k  
---+---+-------+---+----+---+----
 1 | 4 | one   | 1 | -1 | 1 | -1
 1 | 4 | one   | 1 | -1 | 2 |  2
 1 | 4 | one   | 1 | -1 | 3 | -3
 1 | 4 | one   | 1 | -1 | 2 |  4
 1 | 4 | one   | 1 | -1 | 5 | -5
 1 | 4 | one   | 1 | -1 | 5 | -5
 1 | 4 | one   | 1 | -1 | 0 |   
 1 | 4 | one   | 1 | -1 |   |   
 1 | 4 | one   | 1 | -1 |   |  0
 2 | 3 | two   | 1 | -1 | 1 | -1
 2 | 3 | two   | 1 | -1 | 2 |  2
 2 | 3 | two   | 1 | -1 | 3 | -3
 2 | 3 | two   | 1 | -1 | 2 |  4
 2 | 3 | two   | 1 | -1 | 5 | -5
 2 | 3 | two   | 1 | -1 | 5 | -5
 2 | 3 | two   | 1 | -1 | 0 |   
 2 | 3 | two   | 1 | -1 |   |   
 2 | 3 | two   | 1 | -1 |   |  0
 3 | 2 | three | 1 | -1 | 1 | -1
 3 | 2 | three | 1 | -1 | 2 |  2
 3 | 2 | three | 1 | -1 | 3 | -3
 3 | 2 | three | 1 | -1 | 2 |  4
 3 | 2 | three | 1 | -1 | 5 | -5
 3 | 2 | three | 1 | -1 | 5 | -5
 3 | 2 | three | 1 | -1 | 0 |   
 3 | 2 | three | 1 | -1 |   |   
 3 | 2 | three | 1 | -1 |   |  0
 4 | 1 | four  | 1 | -1 | 1 | -1
 4 | 1 | four  | 1 | -1 | 2 |  2
 4 | 1 | four  | 1 | -1 | 3 | -3
 4 | 1 | four  | 1 | -1 | 2 |  4
 4 | 1 | four  | 1 | -1 | 5 | -5
 4 | 1 | four  | 1 | -1 | 5 | -5
 4 | 1 | four  | 1 | -1 | 0 |   
 4 | 1 | four  | 1 | -1 |   |   
 4 | 1 | four  | 1 | -1 |   |  0
 5 | 0 | five  | 1 | -1 | 1 | -1
 5 | 0 | five  | 1 | -1 | 2 |  2
 5 | 0 | five  | 1 | -1 | 3 | -3
 5 | 0 | five  | 1 | -1 | 2 |  4
 5 | 0 | five  | 1 | -1 | 5 | -5
 5 | 0 | five  | 1 | -1 | 5 | -5
 5 | 0 | five  | 1 | -1 | 0 |   
 5 | 0 | five  | 1 | -1 |   |   
 5 | 0 | five  | 1 | -1 |   |  0
 6 | 6 | six   | 1 | -1 | 1 | -1
 6 | 6 | six   | 1 | -1 | 2 |  2
 6 | 6 | six   | 1 | -1 | 3 | -3
 6 | 6 | six   | 1 | -1 | 2 |  4
 6 | 6 | six   | 1 | -1 | 5 | -5
 6 | 6 | six   | 1 | -1 | 5 | -5
 6 | 6 | six   | 1 | -1 | 0 |   
 6 | 6 | six   | 1 | -1 |   |   
 6 | 6 | six   | 1 | -1 |   |  0
 7 | 7 | seven | 1 | -1 | 1 | -1
 7 | 7 | seven | 1 | -1 | 2 |  2
 7 | 7 | seven | 1 | -1 | 3 | -3
 7 | 7 | seven | 1 | -1 | 2 |  4
 7 | 7 | seven | 1 | -1 | 5 | -5
 7 | 7 | seven | 1 | -1 | 5 | -5
 7 | 7 | seven | 1 | -1 | 0 |   
 7 | 7 | seven | 1 | -1 |   |   
 7 | 7 | seven | 1 | -1 |   |  0
 8 | 8 | eight | 1 | -1 | 1 | -1
 8 | 8 | eight | 1 | -1 | 2 |  2
 8 | 8 | eight | 1 | -1 | 3 | -3
 8 | 8 | eight | 1 | -1 | 2 |  4
 8 | 8 | eight | 1 | -1 | 5 | -5
 8 | 8 | eight | 1 | -1 | 5 | -5
 8 | 8 | eight | 1 | -1 | 0 |   
 8 | 8 | eight | 1 | -1 |   |   
 8 | 8 | eight | 1 | -1 |   |  0
 0 |   | zero  | 1 | -1 | 1 | -1
 0 |   | zero  | 1 | -1 | 2 |  2
 0 |   | zero  | 1 | -1 | 3 | -3
 0 |   | zero  | 1 | -1 | 2 |  4
 0 |   | zero  | 1 | -1 | 5 | -5
 0 |   | zero  | 1 | -1 | 5 | -5
 0 |   | zero  | 1 | -1 | 0 |   
 0 |   | zero  | 1 | -1 |   |   
 0 |   | zero  | 1 | -1 |   |  0
   |   | null  | 1 | -1 | 1 | -1
   |   | null  | 1 | -1 | 2 |  2
   |   | null  | 1 | -1 | 3 | -3
   |   | null  | 1 | -1 | 2 |  4
   |   | null  | 1 | -1 | 5 | -5
   |   | null  | 1 | -1 | 5 | -5
   |   | null  | 1 | -1 | 0 |   
   |   | null  | 1 | -1 |   |   
   |   | null  | 1 | -1 |   |  0
   | 0 | zero  | 1 | -1 | 1 | -1
   | 0 | zero  | 1 | -1 | 2 |  2
   | 0 | zero  | 1 | -1 | 3 | -3
   | 0 | zero  | 1 | -1 | 2 |  4
   | 0 | zero  | 1 | -1 | 5 | -5
   | 0 | zero  | 1 | -1 | 5 | -5
   | 0 | zero  | 1 | -1 | 0 |   
   | 0 | zero  | 1 | -1 |   |   
   | 0 | zero  | 1 | -1 |   |  0
 1 | 4 | one   | 2 |  2 | 1 | -1
 1 | 4 | one   | 2 |  2 | 2 |  2
 1 | 4 | one   | 2 |  2 | 3 | -3
 1 | 4 | one   | 2 |  2 | 2 |  4
 1 | 4 | one   | 2 |  2 | 5 | -5
 1 | 4 | one   | 2 |  2 | 5 | -5
 1 | 4 | one   | 2 |  2 | 0 |   
 1 | 4 | one   | 2 |  2 |   |   
 1 | 4 | one   | 2 |  2 |   |  0
 2 | 3 | two   | 2 |  2 | 1 | -1
 2 | 3 | two   | 2 |  2 | 2 |  2
 2 | 3 | two   | 2 |  2 | 3 | -3
 2 | 3 | two   | 2 |  2 | 2 |  4
 2 | 3 | two   | 2 |  2 | 5 | -5
 2 | 3 | two   | 2 |  2 | 5 | -5
 2 | 3 | two   | 2 |  2 | 0 |   
 2 | 3 | two   | 2 |  2 |   |   
 2 | 3 | two   | 2 |  2 |   |  0
 3 | 2 | three | 2 |  2 | 1 | -1
 3 | 2 | three | 2 |  2 | 2 |  2
 3 | 2 | three | 2 |  2 | 3 | -3
 3 | 2 | three | 2 |  2 | 2 |  4
 3 | 2 | three | 2 |  2 | 5 | -5
 3 | 2 | three | 2 |  2 | 5 | -5
 3 | 2 | three | 2 |  2 | 0 |   
 3 | 2 | three | 2 |  2 |   |   
 3 | 2 | three | 2 |  2 |   |  0
 4 | 1 | four  | 2 |  2 | 1 | -1
 4 | 1 | four  | 2 |  2 | 2 |  2
 4 | 1 | four  | 2 |  2 | 3 | -3
 4 | 1 | four  | 2 |  2 | 2 |  4
 4 | 1 | four  | 2 |  2 | 5 | -5
 4 | 1 | four  | 2 |  2 | 5 | -5
 4 | 1 | four  | 2 |  2 | 0 |   
 4 | 1 | four  | 2 |  2 |   |   
 4 | 1 | four  | 2 |  2 |   |  0
 5 | 0 | five  | 2 |  2 | 1 | -1
 5 | 0 | five  | 2 |  2 | 2 |  2
 5 | 0 | five  | 2 |  2 | 3 | -3
 5 | 0 | five  | 2 |  2 | 2 |  4
 5 | 0 | five  | 2 |  2 | 5 | -5
 5 | 0 | five  | 2 |  2 | 5 | -5
 5 | 0 | five  | 2 |  2 | 0 |   
 5 | 0 | five  | 2 |  2 |   |   
 5 | 0 | five  | 2 |  2 |   |  0
 6 | 6 | six   | 2 |  2 | 1 | -1
 6 | 6 | six   | 2 |  2 | 2 |  2
 6 | 6 | six   | 2 |  2 | 3 | -3
 6 | 6 | six   | 2 |  2 | 2 |  4
 6 | 6 | six   | 2 |  2 | 5 | -5
 6 | 6 | six   | 2 |  2 | 5 | -5
 6 | 6 | six   | 2 |  2 | 0 |   
 6 | 6 | six   | 2 |  2 |   |   
 6 | 6 | six   | 2 |  2 |   |  0
 7 | 7 | seven | 2 |  2 | 1 | -1
 7 | 7 | seven | 2 |  2 | 2 |  2
 7 | 7 | seven | 2 |  2 | 3 | -3
 7 | 7 | seven | 2 |  2 | 2 |  4
 7 | 7 | seven | 2 |  2 | 5 | -5
 7 | 7 | seven | 2 |  2 | 5 | -5
 7 | 7 | seven | 2 |  2 | 0 |   
 7 | 7 | seven | 2 |  2 |   |   
 7 | 7 | seven | 2 |  2 |   |  0
 8 | 8 | eight | 2 |  2 | 1 | -1
 8 | 8 | eight | 2 |  2 | 2 |  2
 8 | 8 | eight | 2 |  2 | 3 | -3
 8 | 8 | eight | 2 |  2 | 2 |  4
 8 | 8 | eight | 2 |  2 | 5 | -5
 8 | 8 | eight | 2 |  2 | 5 | -5
 8 | 8 | eight | 2 |  2 | 0 |   
 8 | 8 | eight | 2 |  2 |   |   
 8 | 8 | eight | 2 |  2 |   |  0
 0 |   | zero  | 2 |  2 | 1 | -1
 0 |   | zero  | 2 |  2 | 2 |  2
 0 |   | zero  | 2 |  2 | 3 | -3
 0 |   | zero  | 2 |  2 | 2 |  4
 0 |   | zero  | 2 |  2 | 5 | -5
 0 |   | zero  | 2 |  2 | 5 | -5
 0 |   | zero  | 2 |  2 | 0 |   
 0 |   | zero  | 2 |  2 |   |   
 0 |   | zero  | 2 |  2 |   |  0
   |   | null  | 2 |  2 | 1 | -1
   |   | null  | 2 |  2 | 2 |  2
   |   | null  | 2 |  2 | 3 | -3
   |   | null  | 2 |  2 | 2 |  4
   |   | null  | 2 |  2 | 5 | -5
   |   | null  | 2 |  2 | 5 | -5
   |   | null  | 2 |  2 | 0 |   
   |   | null  | 2 |  2 |   |   
   |   | null  | 2 |  2 |   |  0
   | 0 | zero  | 2 |  2 | 1 | -1
   | 0 | zero  | 2 |  2 | 2 |  2
   | 0 | zero  | 2 |  2 | 3 | -3
   | 0 | zero  | 2 |  2 | 2 |  4
   | 0 | zero  | 2 |  2 | 5 | -5
   | 0 | zero  | 2 |  2 | 5 | -5
   | 0 | zero  | 2 |  2 | 0 |   
   | 0 | zero  | 2 |  2 |   |   
   | 0 | zero  | 2 |  2 |   |  0
 1 | 4 | one   | 3 | -3 | 1 | -1
 1 | 4 | one   | 3 | -3 | 2 |  2
 1 | 4 | one   | 3 | -3 | 3 | -3
 1 | 4 | one   | 3 | -3 | 2 |  4
 1 | 4 | one   | 3 | -3 | 5 | -5
 1 | 4 | one   | 3 | -3 | 5 | -5
 1 | 4 | one   | 3 | -3 | 0 |   
 1 | 4 | one   | 3 | -3 |   |   
 1 | 4 | one   | 3 | -3 |   |  0
 2 | 3 | two   | 3 | -3 | 1 | -1
 2 | 3 | two   | 3 | -3 | 2 |  2
 2 | 3 | two   | 3 | -3 | 3 | -3
 2 | 3 | two   | 3 | -3 | 2 |  4
 2 | 3 | two   | 3 | -3 | 5 | -5
 2 | 3 | two   | 3 | -3 | 5 | -5
 2 | 3 | two   | 3 | -3 | 0 |   
 2 | 3 | two   | 3 | -3 |   |   
 2 | 3 | two   | 3 | -3 |   |  0
 3 | 2 | three | 3 | -3 | 1 | -1
 3 | 2 | three | 3 | -3 | 2 |  2
 3 | 2 | three | 3 | -3 | 3 | -3
 3 | 2 | three | 3 | -3 | 2 |  4
 3 | 2 | three | 3 | -3 | 5 | -5
 3 | 2 | three | 3 | -3 | 5 | -5
 3 | 2 | three | 3 | -3 | 0 |   
 3 | 2 | three | 3 | -3 |   |   
 3 | 2 | three | 3 | -3 |   |  0
 4 | 1 | four  | 3 | -3 | 1 | -1
 4 | 1 | four  | 3 | -3 | 2 |  2
 4 | 1 | four  | 3 | -3 | 3 | -3
 4 | 1 | four  | 3 | -3 | 2 |  4
 4 | 1 | four  | 3 | -3 | 5 | -5
 4 | 1 | four  | 3 | -3 | 5 | -5
 4 | 1 | four  | 3 | -3 | 0 |   
 4 | 1 | four  | 3 | -3 |   |   
 4 | 1 | four  | 3 | -3 |   |  0
 5 | 0 | five  | 3 | -3 | 1 | -1
 5 | 0 | five  | 3 | -3 | 2 |  2
 5 | 0 | five  | 3 | -3 | 3 | -3
 5 | 0 | five  | 3 | -3 | 2 |  4
 5 | 0 | five  | 3 | -3 | 5 | -5
 5 | 0 | five  | 3 | -3 | 5 | -5
 5 | 0 | five  | 3 | -3 | 0 |   
 5 | 0 | five  | 3 | -3 |   |   
 5 | 0 | five  | 3 | -3 |   |  0
 6 | 6 | six   | 3 | -3 | 1 | -1
 6 | 6 | six   | 3 | -3 | 2 |  2
 6 | 6 | six   | 3 | -3 | 3 | -3
 6 | 6 | six   | 3 | -3 | 2 |  4
 6 | 6 | six   | 3 | -3 | 5 | -5
 6 | 6 | six   | 3 | -3 | 5 | -5
 6 | 6 | six   | 3 | -3 | 0 |   
 6 | 6 | six   | 3 | -3 |   |   
 6 | 6 | six   | 3 | -3 |   |  0
 7 | 7 | seven | 3 | -3 | 1 | -1
 7 | 7 | seven | 3 | -3 | 2 |  2
 7 | 7 | seven | 3 | -3 | 3 | -3
 7 | 7 | seven | 3 | -3 | 2 |  4
 7 | 7 | seven | 3 | -3 | 5 | -5
 7 | 7 | seven | 3 | -3 | 5 | -5
 7 | 7 | seven | 3 | -3 | 0 |   
 7 | 7 | seven | 3 | -3 |   |   
 7 | 7 | seven | 3 | -3 |   |  0
 8 | 8 | eight | 3 | -3 | 1 | -1
 8 | 8 | eight | 3 | -3 | 2 |  2
 8 | 8 | eight | 3 | -3 | 3 | -3
 8 | 8 | eight | 3 | -3 | 2 |  4
 8 | 8 | eight | 3 | -3 | 5 | -5
 8 | 8 | eight | 3 | -3 | 5 | -5
 8 | 8 | eight | 3 | -3 | 0 |   
 8 | 8 | eight | 3 | -3 |   |   
 8 | 8 | eight | 3 | -3 |   |  0
 0 |   | zero  | 3 | -3 | 1 | -1
 0 |   | zero  | 3 | -3 | 2 |  2
 0 |   | zero  | 3 | -3 | 3 | -3
 0 |   | zero  | 3 | -3 | 2 |  4
 0 |   | zero  | 3 | -3 | 5 | -5
 0 |   | zero  | 3 | -3 | 5 | -5
 0 |   | zero  | 3 | -3 | 0 |   
 0 |   | zero  | 3 | -3 |   |   
 0 |   | zero  | 3 | -3 |   |  0
   |   | null  | 3 | -3 | 1 | -1
   |   | null  | 3 | -3 | 2 |  2
   |   | null  | 3 | -3 | 3 | -3
   |   | null  | 3 | -3 | 2 |  4
   |   | null  | 3 | -3 | 5 | -5
   |   | null  | 3 | -3 | 5 | -5
   |   | null  | 3 | -3 | 0 |   
   |   | null  | 3 | -3 |   |   
   |   | null  | 3 | -3 |   |  0
   | 0 | zero  | 3 | -3 | 1 | -1
   | 0 | zero  | 3 | -3 | 2 |  2
   | 0 | zero  | 3 | -3 | 3 | -3
   | 0 | zero  | 3 | -3 | 2 |  4
   | 0 | zero  | 3 | -3 | 5 | -5
   | 0 | zero  | 3 | -3 | 5 | -5
   | 0 | zero  | 3 | -3 | 0 |   
   | 0 | zero  | 3 | -3 |   |   
   | 0 | zero  | 3 | -3 |   |  0
 1 | 4 | one   | 2 |  4 | 1 | -1
 1 | 4 | one   | 2 |  4 | 2 |  2
 1 | 4 | one   | 2 |  4 | 3 | -3
 1 | 4 | one   | 2 |  4 | 2 |  4
 1 | 4 | one   | 2 |  4 | 5 | -5
 1 | 4 | one   | 2 |  4 | 5 | -5
 1 | 4 | one   | 2 |  4 | 0 |   
 1 | 4 | one   | 2 |  4 |   |   
 1 | 4 | one   | 2 |  4 |   |  0
 2 | 3 | two   | 2 |  4 | 1 | -1
 2 | 3 | two   | 2 |  4 | 2 |  2
 2 | 3 | two   | 2 |  4 | 3 | -3
 2 | 3 | two   | 2 |  4 | 2 |  4
 2 | 3 | two   | 2 |  4 | 5 | -5
 2 | 3 | two   | 2 |  4 | 5 | -5
 2 | 3 | two   | 2 |  4 | 0 |   
 2 | 3 | two   | 2 |  4 |   |   
 2 | 3 | two   | 2 |  4 |   |  0
 3 | 2 | three | 2 |  4 | 1 | -1
 3 | 2 | three | 2 |  4 | 2 |  2
 3 | 2 | three | 2 |  4 | 3 | -3
 3 | 2 | three | 2 |  4 | 2 |  4
 3 | 2 | three | 2 |  4 | 5 | -5
 3 | 2 | three | 2 |  4 | 5 | -5
 3 | 2 | three | 2 |  4 | 0 |   
 3 | 2 | three | 2 |  4 |   |   
 3 | 2 | three | 2 |  4 |   |  0
 4 | 1 | four  | 2 |  4 | 1 | -1
 4 | 1 | four  | 2 |  4 | 2 |  2
 4 | 1 | four  | 2 |  4 | 3 | -3
 4 | 1 | four  | 2 |  4 | 2 |  4
 4 | 1 | four  | 2 |  4 | 5 | -5
 4 | 1 | four  | 2 |  4 | 5 | -5
 4 | 1 | four  | 2 |  4 | 0 |   
 4 | 1 | four  | 2 |  4 |   |   
 4 | 1 | four  | 2 |  4 |   |  0
 5 | 0 | five  | 2 |  4 | 1 | -1
 5 | 0 | five  | 2 |  4 | 2 |  2
 5 | 0 | five  | 2 |  4 | 3 | -3
 5 | 0 | five  | 2 |  4 | 2 |  4
 5 | 0 | five  | 2 |  4 | 5 | -5
 5 | 0 | five  | 2 |  4 | 5 | -5
 5 | 0 | five  | 2 |  4 | 0 |   
 5 | 0 | five  | 2 |  4 |   |   
 5 | 0 | five  | 2 |  4 |   |  0
 6 | 6 | six   | 2 |  4 | 1 | -1
 6 | 6 | six   | 2 |  4 | 2 |  2
 6 | 6 | six   | 2 |  4 | 3 | -3
 6 | 6 | six   | 2 |  4 | 2 |  4
 6 | 6 | six   | 2 |  4 | 5 | -5
 6 | 6 | six   | 2 |  4 | 5 | -5
 6 | 6 | six   | 2 |  4 | 0 |   
 6 | 6 | six   | 2 |  4 |   |   
 6 | 6 | six   | 2 |  4 |   |  0
 7 | 7 | seven | 2 |  4 | 1 | -1
 7 | 7 | seven | 2 |  4 | 2 |  2
 7 | 7 | seven | 2 |  4 | 3 | -3
 7 | 7 | seven | 2 |  4 | 2 |  4
 7 | 7 | seven | 2 |  4 | 5 | -5
 7 | 7 | seven | 2 |  4 | 5 | -5
 7 | 7 | seven | 2 |  4 | 0 |   
 7 | 7 | seven | 2 |  4 |   |   
 7 | 7 | seven | 2 |  4 |   |  0
 8 | 8 | eight | 2 |  4 | 1 | -1
 8 | 8 | eight | 2 |  4 | 2 |  2
 8 | 8 | eight | 2 |  4 | 3 | -3
 8 | 8 | eight | 2 |  4 | 2 |  4
 8 | 8 | eight | 2 |  4 | 5 | -5
 8 | 8 | eight | 2 |  4 | 5 | -5
 8 | 8 | eight | 2 |  4 | 0 |   
 8 | 8 | eight | 2 |  4 |   |   
 8 | 8 | eight | 2 |  4 |   |  0
 0 |   | zero  | 2 |  4 | 1 | -1
 0 |   | zero  | 2 |  4 | 2 |  2
 0 |   | zero  | 2 |  4 | 3 | -3
 0 |   | zero  | 2 |  4 | 2 |  4
 0 |   | zero  | 2 |  4 | 5 | -5
 0 |   | zero  | 2 |  4 | 5 | -5
 0 |   | zero  | 2 |  4 | 0 |   
 0 |   | zero  | 2 |  4 |   |   
 0 |   | zero  | 2 |  4 |   |  0
   |   | null  | 2 |  4 | 1 | -1
   |   | null  | 2 |  4 | 2 |  2
   |   | null  | 2 |  4 | 3 | -3
   |   | null  | 2 |  4 | 2 |  4
   |   | null  | 2 |  4 | 5 | -5
   |   | null  | 2 |  4 | 5 | -5
   |   | null  | 2 |  4 | 0 |   
   |   | null  | 2 |  4 |   |   
   |   | null  | 2 |  4 |   |  0
   | 0 | zero  | 2 |  4 | 1 | -1
   | 0 | zero  | 2 |  4 | 2 |  2
   | 0 | zero  | 2 |  4 | 3 | -3
   | 0 | zero  | 2 |  4 | 2 |  4
   | 0 | zero  | 2 |  4 | 5 | -5
   | 0 | zero  | 2 |  4 | 5 | -5
   | 0 | zero  | 2 |  4 | 0 |   
   | 0 | zero  | 2 |  4 |   |   
   | 0 | zero  | 2 |  4 |   |  0
 1 | 4 | one   | 5 | -5 | 1 | -1
 1 | 4 | one   | 5 | -5 | 2 |  2
 1 | 4 | one   | 5 | -5 | 3 | -3
 1 | 4 | one   | 5 | -5 | 2 |  4
 1 | 4 | one   | 5 | -5 | 5 | -5
 1 | 4 | one   | 5 | -5 | 5 | -5
 1 | 4 | one   | 5 | -5 | 0 |   
 1 | 4 | one   | 5 | -5 |   |   
 1 | 4 | one   | 5 | -5 |   |  0
 2 | 3 | two   | 5 | -5 | 1 | -1
 2 | 3 | two   | 5 | -5 | 2 |  2
 2 | 3 | two   | 5 | -5 | 3 | -3
 2 | 3 | two   | 5 | -5 | 2 |  4
 2 | 3 | two   | 5 | -5 | 5 | -5
 2 | 3 | two   | 5 | -5 | 5 | -5
 2 | 3 | two   | 5 | -5 | 0 |   
 2 | 3 | two   | 5 | -5 |   |   
 2 | 3 | two   | 5 | -5 |   |  0
 3 | 2 | three | 5 | -5 | 1 | -1
 3 | 2 | three | 5 | -5 | 2 |  2
 3 | 2 | three | 5 | -5 | 3 | -3
 3 | 2 | three | 5 | -5 | 2 |  4
 3 | 2 | three | 5 | -5 | 5 | -5
 3 | 2 | three | 5 | -5 | 5 | -5
 3 | 2 | three | 5 | -5 | 0 |   
 3 | 2 | three | 5 | -5 |   |   
 3 | 2 | three | 5 | -5 |   |  0
 4 | 1 | four  | 5 | -5 | 1 | -1
 4 | 1 | four  | 5 | -5 | 2 |  2
 4 | 1 | four  | 5 | -5 | 3 | -3
 4 | 1 | four  | 5 | -5 | 2 |  4
 4 | 1 | four  | 5 | -5 | 5 | -5
 4 | 1 | four  | 5 | -5 | 5 | -5
 4 | 1 | four  | 5 | -5 | 0 |   
 4 | 1 | four  | 5 | -5 |   |   
 4 | 1 | four  | 5 | -5 |   |  0
 5 | 0 | five  | 5 | -5 | 1 | -1
 5 | 0 | five  | 5 | -5 | 2 |  2
 5 | 0 | five  | 5 | -5 | 3 | -3
 5 | 0 | five  | 5 | -5 | 2 |  4
 5 | 0 | five  | 5 | -5 | 5 | -5
 5 | 0 | five  | 5 | -5 | 5 | -5
 5 | 0 | five  | 5 | -5 | 0 |   
 5 | 0 | five  | 5 | -5 |   |   
 5 | 0 | five  | 5 | -5 |   |  0
 6 | 6 | six   | 5 | -5 | 1 | -1
 6 | 6 | six   | 5 | -5 | 2 |  2
 6 | 6 | six   | 5 | -5 | 3 | -3
 6 | 6 | six   | 5 | -5 | 2 |  4
 6 | 6 | six   | 5 | -5 | 5 | -5
 6 | 6 | six   | 5 | -5 | 5 | -5
 6 | 6 | six   | 5 | -5 | 0 |   
 6 | 6 | six   | 5 | -5 |   |   
 6 | 6 | six   | 5 | -5 |   |  0
 7 | 7 | seven | 5 | -5 | 1 | -1
 7 | 7 | seven | 5 | -5 | 2 |  2
 7 | 7 | seven | 5 | -5 | 3 | -3
 7 | 7 | seven | 5 | -5 | 2 |  4
 7 | 7 | seven | 5 | -5 | 5 | -5
 7 | 7 | seven | 5 | -5 | 5 | -5
 7 | 7 | seven | 5 | -5 | 0 |   
 7 | 7 | seven | 5 | -5 |   |   
 7 | 7 | seven | 5 | -5 |   |  0
 8 | 8 | eight | 5 | -5 | 1 | -1
 8 | 8 | eight | 5 | -5 | 2 |  2
 8 | 8 | eight | 5 | -5 | 3 | -3
 8 | 8 | eight | 5 | -5 | 2 |  4
 8 | 8 | eight | 5 | -5 | 5 | -5
 8 | 8 | eight | 5 | -5 | 5 | -5
 8 | 8 | eight | 5 | -5 | 0 |   
 8 | 8 | eight | 5 | -5 |   |   
 8 | 8 | eight | 5 | -5 |   |  0
 0 |   | zero  | 5 | -5 | 1 | -1
 0 |   | zero  | 5 | -5 | 2 |  2
 0 |   | zero  | 5 | -5 | 3 | -3
 0 |   | zero  | 5 | -5 | 2 |  4
 0 |   | zero  | 5 | -5 | 5 | -5
 0 |   | zero  | 5 | -5 | 5 | -5
 0 |   | zero  | 5 | -5 | 0 |   
 0 |   | zero  | 5 | -5 |   |   
 0 |   | zero  | 5 | -5 |   |  0
   |   | null  | 5 | -5 | 1 | -1
   |   | null  | 5 | -5 | 2 |  2
   |   | null  | 5 | -5 | 3 | -3
   |   | null  | 5 | -5 | 2 |  4
   |   | null  | 5 | -5 | 5 | -5
   |   | null  | 5 | -5 | 5 | -5
   |   | null  | 5 | -5 | 0 |   
   |   | null  | 5 | -5 |   |   
   |   | null  | 5 | -5 |   |  0
   | 0 | zero  | 5 | -5 | 1 | -1
   | 0 | zero  | 5 | -5 | 2 |  2
   | 0 | zero  | 5 | -5 | 3 | -3
   | 0 | zero  | 5 | -5 | 2 |  4
   | 0 | zero  | 5 | -5 | 5 | -5
   | 0 | zero  | 5 | -5 | 5 | -5
   | 0 | zero  | 5 | -5 | 0 |   
   | 0 | zero  | 5 | -5 |   |   
   | 0 | zero  | 5 | -5 |   |  0
 1 | 4 | one   | 5 | -5 | 1 | -1
 1 | 4 | one   | 5 | -5 | 2 |  2
 1 | 4 | one   | 5 | -5 | 3 | -3
 1 | 4 | one   | 5 | -5 | 2 |  4
 1 | 4 | one   | 5 | -5 | 5 | -5
 1 | 4 | one   | 5 | -5 | 5 | -5
 1 | 4 | one   | 5 | -5 | 0 |   
 1 | 4 | one   | 5 | -5 |   |   
 1 | 4 | one   | 5 | -5 |   |  0
 2 | 3 | two   | 5 | -5 | 1 | -1
 2 | 3 | two   | 5 | -5 | 2 |  2
 2 | 3 | two   | 5 | -5 | 3 | -3
 2 | 3 | two   | 5 | -5 | 2 |  4
 2 | 3 | two   | 5 | -5 | 5 | -5
 2 | 3 | two   | 5 | -5 | 5 | -5
 2 | 3 | two   | 5 | -5 | 0 |   
 2 | 3 | two   | 5 | -5 |   |   
 2 | 3 | two   | 5 | -5 |   |  0
 3 | 2 | three | 5 | -5 | 1 | -1
 3 | 2 | three | 5 | -5 | 2 |  2
 3 | 2 | three | 5 | -5 | 3 | -3
 3 | 2 | three | 5 | -5 | 2 |  4
 3 | 2 | three | 5 | -5 | 5 | -5
 3 | 2 | three | 5 | -5 | 5 | -5
 3 | 2 | three | 5 | -5 | 0 |   
 3 | 2 | three | 5 | -5 |   |   
 3 | 2 | three | 5 | -5 |   |  0
 4 | 1 | four  | 5 | -5 | 1 | -1
 4 | 1 | four  | 5 | -5 | 2 |  2
 4 | 1 | four  | 5 | -5 | 3 | -3
 4 | 1 | four  | 5 | -5 | 2 |  4
 4 | 1 | four  | 5 | -5 | 5 | -5
 4 | 1 | four  | 5 | -5 | 5 | -5
 4 | 1 | four  | 5 | -5 | 0 |   
 4 | 1 | four  | 5 | -5 |   |   
 4 | 1 | four  | 5 | -5 |   |  0
 5 | 0 | five  | 5 | -5 | 1 | -1
 5 | 0 | five  | 5 | -5 | 2 |  2
 5 | 0 | five  | 5 | -5 | 3 | -3
 5 | 0 | five  | 5 | -5 | 2 |  4
 5 | 0 | five  | 5 | -5 | 5 | -5
 5 | 0 | five  | 5 | -5 | 5 | -5
 5 | 0 | five  | 5 | -5 | 0 |   
 5 | 0 | five  | 5 | -5 |   |   
 5 | 0 | five  | 5 | -5 |   |  0
 6 | 6 | six   | 5 | -5 | 1 | -1
 6 | 6 | six   | 5 | -5 | 2 |  2
 6 | 6 | six   | 5 | -5 | 3 | -3
 6 | 6 | six   | 5 | -5 | 2 |  4
 6 | 6 | six   | 5 | -5 | 5 | -5
 6 | 6 | six   | 5 | -5 | 5 | -5
 6 | 6 | six   | 5 | -5 | 0 |   
 6 | 6 | six   | 5 | -5 |   |   
 6 | 6 | six   | 5 | -5 |   |  0
 7 | 7 | seven | 5 | -5 | 1 | -1
 7 | 7 | seven | 5 | -5 | 2 |  2
 7 | 7 | seven | 5 | -5 | 3 | -3
 7 | 7 | seven | 5 | -5 | 2 |  4
 7 | 7 | seven | 5 | -5 | 5 | -5
 7 | 7 | seven | 5 | -5 | 5 | -5
 7 | 7 | seven | 5 | -5 | 0 |   
 7 | 7 | seven | 5 | -5 |   |   
 7 | 7 | seven | 5 | -5 |   |  0
 8 | 8 | eight | 5 | -5 | 1 | -1
 8 | 8 | eight | 5 | -5 | 2 |  2
 8 | 8 | eight | 5 | -5 | 3 | -3
 8 | 8 | eight | 5 | -5 | 2 |  4
 8 | 8 | eight | 5 | -5 | 5 | -5
 8 | 8 | eight | 5 | -5 | 5 | -5
 8 | 8 | eight | 5 | -5 | 0 |   
 8 | 8 | eight | 5 | -5 |   |   
 8 | 8 | eight | 5 | -5 |   |  0
 0 |   | zero  | 5 | -5 | 1 | -1
 0 |   | zero  | 5 | -5 | 2 |  2
 0 |   | zero  | 5 | -5 | 3 | -3
 0 |   | zero  | 5 | -5 | 2 |  4
 0 |   | zero  | 5 | -5 | 5 | -5
 0 |   | zero  | 5 | -5 | 5 | -5
 0 |   | zero  | 5 | -5 | 0 |   
 0 |   | zero  | 5 | -5 |   |   
 0 |   | zero  | 5 | -5 |   |  0
   |   | null  | 5 | -5 | 1 | -1
   |   | null  | 5 | -5 | 2 |  2
   |   | null  | 5 | -5 | 3 | -3
   |   | null  | 5 | -5 | 2 |  4
   |   | null  | 5 | -5 | 5 | -5
   |   | null  | 5 | -5 | 5 | -5
   |   | null  | 5 | -5 | 0 |   
   |   | null  | 5 | -5 |   |   
   |   | null  | 5 | -5 |   |  0
   | 0 | zero  | 5 | -5 | 1 | -1
   | 0 | zero  | 5 | -5 | 2 |  2
   | 0 | zero  | 5 | -5 | 3 | -3
   | 0 | zero  | 5 | -5 | 2 |  4
   | 0 | zero  | 5 | -5 | 5 | -5
   | 0 | zero  | 5 | -5 | 5 | -5
   | 0 | zero  | 5 | -5 | 0 |   
   | 0 | zero  | 5 | -5 |   |   
   | 0 | zero  | 5 | -5 |   |  0
 1 | 4 | one   | 0 |    | 1 | -1
 1 | 4 | one   | 0 |    | 2 |  2
 1 | 4 | one   | 0 |    | 3 | -3
 1 | 4 | one   | 0 |    | 2 |  4
 1 | 4 | one   | 0 |    | 5 | -5
 1 | 4 | one   | 0 |    | 5 | -5
 1 | 4 | one   | 0 |    | 0 |   
 1 | 4 | one   | 0 |    |   |   
 1 | 4 | one   | 0 |    |   |  0
 2 | 3 | two   | 0 |    | 1 | -1
 2 | 3 | two   | 0 |    | 2 |  2
 2 | 3 | two   | 0 |    | 3 | -3
 2 | 3 | two   | 0 |    | 2 |  4
 2 | 3 | two   | 0 |    | 5 | -5
 2 | 3 | two   | 0 |    | 5 | -5
 2 | 3 | two   | 0 |    | 0 |   
 2 | 3 | two   | 0 |    |   |   
 2 | 3 | two   | 0 |    |   |  0
 3 | 2 | three | 0 |    | 1 | -1
 3 | 2 | three | 0 |    | 2 |  2
 3 | 2 | three | 0 |    | 3 | -3
 3 | 2 | three | 0 |    | 2 |  4
 3 | 2 | three | 0 |    | 5 | -5
 3 | 2 | three | 0 |    | 5 | -5
 3 | 2 | three | 0 |    | 0 |   
 3 | 2 | three | 0 |    |   |   
 3 | 2 | three | 0 |    |   |  0
 4 | 1 | four  | 0 |    | 1 | -1
 4 | 1 | four  | 0 |    | 2 |  2
 4 | 1 | four  | 0 |    | 3 | -3
 4 | 1 | four  | 0 |    | 2 |  4
 4 | 1 | four  | 0 |    | 5 | -5
 4 | 1 | four  | 0 |    | 5 | -5
 4 | 1 | four  | 0 |    | 0 |   
 4 | 1 | four  | 0 |    |   |   
 4 | 1 | four  | 0 |    |   |  0
 5 | 0 | five  | 0 |    | 1 | -1
 5 | 0 | five  | 0 |    | 2 |  2
 5 | 0 | five  | 0 |    | 3 | -3
 5 | 0 | five  | 0 |    | 2 |  4
 5 | 0 | five  | 0 |    | 5 | -5
 5 | 0 | five  | 0 |    | 5 | -5
 5 | 0 | five  | 0 |    | 0 |   
 5 | 0 | five  | 0 |    |   |   
 5 | 0 | five  | 0 |    |   |  0
 6 | 6 | six   | 0 |    | 1 | -1
 6 | 6 | six   | 0 |    | 2 |  2
 6 | 6 | six   | 0 |    | 3 | -3
 6 | 6 | six   | 0 |    | 2 |  4
 6 | 6 | six   | 0 |    | 5 | -5
 6 | 6 | six   | 0 |    | 5 | -5
 6 | 6 | six   | 0 |    | 0 |   
 6 | 6 | six   | 0 |    |   |   
 6 | 6 | six   | 0 |    |   |  0
 7 | 7 | seven | 0 |    | 1 | -1
 7 | 7 | seven | 0 |    | 2 |  2
 7 | 7 | seven | 0 |    | 3 | -3
 7 | 7 | seven | 0 |    | 2 |  4
 7 | 7 | seven | 0 |    | 5 | -5
 7 | 7 | seven | 0 |    | 5 | -5
 7 | 7 | seven | 0 |    | 0 |   
 7 | 7 | seven | 0 |    |   |   
 7 | 7 | seven | 0 |    |   |  0
 8 | 8 | eight | 0 |    | 1 | -1
 8 | 8 | eight | 0 |    | 2 |  2
 8 | 8 | eight | 0 |    | 3 | -3
 8 | 8 | eight | 0 |    | 2 |  4
 8 | 8 | eight | 0 |    | 5 | -5
 8 | 8 | eight | 0 |    | 5 | -5
 8 | 8 | eight | 0 |    | 0 |   
 8 | 8 | eight | 0 |    |   |   
 8 | 8 | eight | 0 |    |   |  0
 0 |   | zero  | 0 |    | 1 | -1
 0 |   | zero  | 0 |    | 2 |  2
 0 |   | zero  | 0 |    | 3 | -3
 0 |   | zero  | 0 |    | 2 |  4
 0 |   | zero  | 0 |    | 5 | -5
 0 |   | zero  | 0 |    | 5 | -5
 0 |   | zero  | 0 |    | 0 |   
 0 |   | zero  | 0 |    |   |   
 0 |   | zero  | 0 |    |   |  0
   |   | null  | 0 |    | 1 | -1
   |   | null  | 0 |    | 2 |  2
   |   | null  | 0 |    | 3 | -3
   |   | null  | 0 |    | 2 |  4
   |   | null  | 0 |    | 5 | -5
   |   | null  | 0 |    | 5 | -5
   |   | null  | 0 |    | 0 |   
   |   | null  | 0 |    |   |   
   |   | null  | 0 |    |   |  0
   | 0 | zero  | 0 |    | 1 | -1
   | 0 | zero  | 0 |    | 2 |  2
   | 0 | zero  | 0 |    | 3 | -3
   | 0 | zero  | 0 |    | 2 |  4
   | 0 | zero  | 0 |    | 5 | -5
   | 0 | zero  | 0 |    | 5 | -5
   | 0 | zero  | 0 |    | 0 |   
   | 0 | zero  | 0 |    |   |   
   | 0 | zero  | 0 |    |   |  0
 1 | 4 | one   |   |    | 1 | -1
 1 | 4 | one   |   |    | 2 |  2
 1 | 4 | one   |   |    | 3 | -3
 1 | 4 | one   |   |    | 2 |  4
 1 | 4 | one   |   |    | 5 | -5
 1 | 4 | one   |   |    | 5 | -5
 1 | 4 | one   |   |    | 0 |   
 1 | 4 | one   |   |    |   |   
 1 | 4 | one   |   |    |   |  0
 2 | 3 | two   |   |    | 1 | -1
 2 | 3 | two   |   |    | 2 |  2
 2 | 3 | two   |   |    | 3 | -3
 2 | 3 | two   |   |    | 2 |  4
 2 | 3 | two   |   |    | 5 | -5
 2 | 3 | two   |   |    | 5 | -5
 2 | 3 | two   |   |    | 0 |   
 2 | 3 | two   |   |    |   |   
 2 | 3 | two   |   |    |   |  0
 3 | 2 | three |   |    | 1 | -1
 3 | 2 | three |   |    | 2 |  2
 3 | 2 | three |   |    | 3 | -3
 3 | 2 | three |   |    | 2 |  4
 3 | 2 | three |   |    | 5 | -5
 3 | 2 | three |   |    | 5 | -5
 3 | 2 | three |   |    | 0 |   
 3 | 2 | three |   |    |   |   
 3 | 2 | three |   |    |   |  0
 4 | 1 | four  |   |    | 1 | -1
 4 | 1 | four  |   |    | 2 |  2
 4 | 1 | four  |   |    | 3 | -3
 4 | 1 | four  |   |    | 2 |  4
 4 | 1 | four  |   |    | 5 | -5
 4 | 1 | four  |   |    | 5 | -5
 4 | 1 | four  |   |    | 0 |   
 4 | 1 | four  |   |    |   |   
 4 | 1 | four  |   |    |   |  0
 5 | 0 | five  |   |    | 1 | -1
 5 | 0 | five  |   |    | 2 |  2
 5 | 0 | five  |   |    | 3 | -3
 5 | 0 | five  |   |    | 2 |  4
 5 | 0 | five  |   |    | 5 | -5
 5 | 0 | five  |   |    | 5 | -5
 5 | 0 | five  |   |    | 0 |   
 5 | 0 | five  |   |    |   |   
 5 | 0 | five  |   |    |   |  0
 6 | 6 | six   |   |    | 1 | -1
 6 | 6 | six   |   |    | 2 |  2
 6 | 6 | six   |   |    | 3 | -3
 6 | 6 | six   |   |    | 2 |  4
 6 | 6 | six   |   |    | 5 | -5
 6 | 6 | six   |   |    | 5 | -5
 6 | 6 | six   |   |    | 0 |   
 6 | 6 | six   |   |    |   |   
 6 | 6 | six   |   |    |   |  0
 7 | 7 | seven |   |    | 1 | -1
 7 | 7 | seven |   |    | 2 |  2
 7 | 7 | seven |   |    | 3 | -3
 7 | 7 | seven |   |    | 2 |  4
 7 | 7 | seven |   |    | 5 | -5
 7 | 7 | seven |   |    | 5 | -5
 7 | 7 | seven |   |    | 0 |   
 7 | 7 | seven |   |    |   |   
 7 | 7 | seven |   |    |   |  0
 8 | 8 | eight |   |    | 1 | -1
 8 | 8 | eight |   |    | 2 |  2
 8 | 8 | eight |   |    | 3 | -3
 8 | 8 | eight |   |    | 2 |  4
 8 | 8 | eight |   |    | 5 | -5
 8 | 8 | eight |   |    | 5 | -5
 8 | 8 | eight |   |    | 0 |   
 8 | 8 | eight |   |    |   |   
 8 | 8 | eight |   |    |   |  0
 0 |   | zero  |   |    | 1 | -1
 0 |   | zero  |   |    | 2 |  2
 0 |   | zero  |   |    | 3 | -3
 0 |   | zero  |   |    | 2 |  4
 0 |   | zero  |   |    | 5 | -5
 0 |   | zero  |   |    | 5 | -5
 0 |   | zero  |   |    | 0 |   
 0 |   | zero  |   |    |   |   
 0 |   | zero  |   |    |   |  0
   |   | null  |   |    | 1 | -1
   |   | null  |   |    | 2 |  2
   |   | null  |   |    | 3 | -3
   |   | null  |   |    | 2 |  4
   |   | null  |   |    | 5 | -5
   |   | null  |   |    | 5 | -5
   |   | null  |   |    | 0 |   
   |   | null  |   |    |   |   
   |   | null  |   |    |   |  0
   | 0 | zero  |   |    | 1 | -1
   | 0 | zero  |   |    | 2 |  2
   | 0 | zero  |   |    | 3 | -3
   | 0 | zero  |   |    | 2 |  4
   | 0 | zero  |   |    | 5 | -5
   | 0 | zero  |   |    | 5 | -5
   | 0 | zero  |   |    | 0 |   
   | 0 | zero  |   |    |   |   
   | 0 | zero  |   |    |   |  0
 1 | 4 | one   |   |  0 | 1 | -1
 1 | 4 | one   |   |  0 | 2 |  2
 1 | 4 | one   |   |  0 | 3 | -3
 1 | 4 | one   |   |  0 | 2 |  4
 1 | 4 | one   |   |  0 | 5 | -5
 1 | 4 | one   |   |  0 | 5 | -5
 1 | 4 | one   |   |  0 | 0 |   
 1 | 4 | one   |   |  0 |   |   
 1 | 4 | one   |   |  0 |   |  0
 2 | 3 | two   |   |  0 | 1 | -1
 2 | 3 | two   |   |  0 | 2 |  2
 2 | 3 | two   |   |  0 | 3 | -3
 2 | 3 | two   |   |  0 | 2 |  4
 2 | 3 | two   |   |  0 | 5 | -5
 2 | 3 | two   |   |  0 | 5 | -5
 2 | 3 | two   |   |  0 | 0 |   
 2 | 3 | two   |   |  0 |   |   
 2 | 3 | two   |   |  0 |   |  0
 3 | 2 | three |   |  0 | 1 | -1
 3 | 2 | three |   |  0 | 2 |  2
 3 | 2 | three |   |  0 | 3 | -3
 3 | 2 | three |   |  0 | 2 |  4
 3 | 2 | three |   |  0 | 5 | -5
 3 | 2 | three |   |  0 | 5 | -5
 3 | 2 | three |   |  0 | 0 |   
 3 | 2 | three |   |  0 |   |   
 3 | 2 | three |   |  0 |   |  0
 4 | 1 | four  |   |  0 | 1 | -1
 4 | 1 | four  |   |  0 | 2 |  2
 4 | 1 | four  |   |  0 | 3 | -3
 4 | 1 | four  |   |  0 | 2 |  4
 4 | 1 | four  |   |  0 | 5 | -5
 4 | 1 | four  |   |  0 | 5 | -5
 4 | 1 | four  |   |  0 | 0 |   
 4 | 1 | four  |   |  0 |   |   
 4 | 1 | four  |   |  0 |   |  0
 5 | 0 | five  |   |  0 | 1 | -1
 5 | 0 | five  |   |  0 | 2 |  2
 5 | 0 | five  |   |  0 | 3 | -3
 5 | 0 | five  |   |  0 | 2 |  4
 5 | 0 | five  |   |  0 | 5 | -5
 5 | 0 | five  |   |  0 | 5 | -5
 5 | 0 | five  |   |  0 | 0 |   
 5 | 0 | five  |   |  0 |   |   
 5 | 0 | five  |   |  0 |   |  0
 6 | 6 | six   |   |  0 | 1 | -1
 6 | 6 | six   |   |  0 | 2 |  2
 6 | 6 | six   |   |  0 | 3 | -3
 6 | 6 | six   |   |  0 | 2 |  4
 6 | 6 | six   |   |  0 | 5 | -5
 6 | 6 | six   |   |  0 | 5 | -5
 6 | 6 | six   |   |  0 | 0 |   
 6 | 6 | six   |   |  0 |   |   
 6 | 6 | six   |   |  0 |   |  0
 7 | 7 | seven |   |  0 | 1 | -1
 7 | 7 | seven |   |  0 | 2 |  2
 7 | 7 | seven |   |  0 | 3 | -3
 7 | 7 | seven |   |  0 | 2 |  4
 7 | 7 | seven |   |  0 | 5 | -5
 7 | 7 | seven |   |  0 | 5 | -5
 7 | 7 | seven |   |  0 | 0 |   
 7 | 7 | seven |   |  0 |   |   
 7 | 7 | seven |   |  0 |   |  0
 8 | 8 | eight |   |  0 | 1 | -1
 8 | 8 | eight |   |  0 | 2 |  2
 8 | 8 | eight |   |  0 | 3 | -3
 8 | 8 | eight |   |  0 | 2 |  4
 8 | 8 | eight |   |  0 | 5 | -5
 8 | 8 | eight |   |  0 | 5 | -5
 8 | 8 | eight |   |  0 | 0 |   
 8 | 8 | eight |   |  0 |   |   
 8 | 8 | eight |   |  0 |   |  0
 0 |   | zero  |   |  0 | 1 | -1
 0 |   | zero  |   |  0 | 2 |  2
 0 |   | zero  |   |  0 | 3 | -3
 0 |   | zero  |   |  0 | 2 |  4
 0 |   | zero  |   |  0 | 5 | -5
 0 |   | zero  |   |  0 | 5 | -5
 0 |   | zero  |   |  0 | 0 |   
 0 |   | zero  |   |  0 |   |   
 0 |   | zero  |   |  0 |   |  0
   |   | null  |   |  0 | 1 | -1
   |   | null  |   |  0 | 2 |  2
   |   | null  |   |  0 | 3 | -3
   |   | null  |   |  0 | 2 |  4
   |   | null  |   |  0 | 5 | -5
   |   | null  |   |  0 | 5 | -5
   |   | null  |   |  0 | 0 |   
   |   | null  |   |  0 |   |   
   |   | null  |   |  0 |   |  0
   | 0 | zero  |   |  0 | 1 | -1
   | 0 | zero  |   |  0 | 2 |  2
   | 0 | zero  |   |  0 | 3 | -3
   | 0 | zero  |   |  0 | 2 |  4
   | 0 | zero  |   |  0 | 5 | -5
   | 0 | zero  |   |  0 | 5 | -5
   | 0 | zero  |   |  0 | 0 |   
   | 0 | zero  |   |  0 |   |   
   | 0 | zero  |   |  0 |   |  0
(891 rows)

--
--
-- Inner joins (equi-joins)
--
--
--
-- Inner joins (equi-joins) with USING clause
-- The USING syntax changes the shape of the resulting table
-- by including a column in the USING clause only once in the result.
--
-- Inner equi-join on specified column
SELECT *
  FROM J1_TBL INNER JOIN J2_TBL USING (i);
 i | j |   t   | k  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 5 | 0 | five  | -5
 5 | 0 | five  | -5
(7 rows)

-- Same as above, slightly different syntax
SELECT *
  FROM J1_TBL JOIN J2_TBL USING (i);
 i | j |   t   | k  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 5 | 0 | five  | -5
 5 | 0 | five  | -5
(7 rows)

SELECT *
  FROM J1_TBL t1 (a, b, c) JOIN J2_TBL t2 (a, d) USING (a)
  ORDER BY a, d;
 a | b |   c   | d  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 5 | 0 | five  | -5
 5 | 0 | five  | -5
(7 rows)

SELECT *
  FROM J1_TBL t1 (a, b, c) JOIN J2_TBL t2 (a, b) USING (b)
  ORDER BY b, t1.a;
 b | a |   c   | a 
---+---+-------+---
 0 | 5 | five  |  
 0 |   | zero  |  
 2 | 3 | three | 2
 4 | 1 | one   | 2
(4 rows)

-- test join using aliases
SELECT * FROM J1_TBL JOIN J2_TBL USING (i) WHERE J1_TBL.t = 'one';  -- ok
 i | j |  t  | k  
---+---+-----+----
 1 | 4 | one | -1
(1 row)

SELECT * FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE J1_TBL.t = 'one';  -- ok
 i | j |  t  | k  
---+---+-----+----
 1 | 4 | one | -1
(1 row)

SELECT * FROM (J1_TBL JOIN J2_TBL USING (i)) AS x WHERE J1_TBL.t = 'one';  -- error
ERROR:  invalid reference to FROM-clause entry for table "j1_tbl"
LINE 1: ... * FROM (J1_TBL JOIN J2_TBL USING (i)) AS x WHERE J1_TBL.t =...
                                                             ^
DETAIL:  There is an entry for table "j1_tbl", but it cannot be referenced from this part of the query.
SELECT * FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE x.i = 1;  -- ok
 i | j |  t  | k  
---+---+-----+----
 1 | 4 | one | -1
(1 row)

SELECT * FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE x.t = 'one';  -- error
ERROR:  column x.t does not exist
LINE 1: ...CT * FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE x.t = 'one...
                                                             ^
SELECT * FROM (J1_TBL JOIN J2_TBL USING (i) AS x) AS xx WHERE x.i = 1;  -- error (XXX could use better hint)
ERROR:  missing FROM-clause entry for table "x"
LINE 1: ...ROM (J1_TBL JOIN J2_TBL USING (i) AS x) AS xx WHERE x.i = 1;
                                                               ^
SELECT * FROM J1_TBL a1 JOIN J2_TBL a2 USING (i) AS a1;  -- error
ERROR:  table name "a1" specified more than once
SELECT x.* FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE J1_TBL.t = 'one';
 i 
---
 1
(1 row)

SELECT ROW(x.*) FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE J1_TBL.t = 'one';
 row 
-----
 (1)
(1 row)

SELECT row_to_json(x.*) FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE J1_TBL.t = 'one';
 row_to_json 
-------------
 {"i":1}
(1 row)

--
-- NATURAL JOIN
-- Inner equi-join on all columns with the same name
--
SELECT *
  FROM J1_TBL NATURAL JOIN J2_TBL;
 i | j |   t   | k  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 5 | 0 | five  | -5
 5 | 0 | five  | -5
(7 rows)

SELECT *
  FROM J1_TBL t1 (a, b, c) NATURAL JOIN J2_TBL t2 (a, d);
 a | b |   c   | d  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 5 | 0 | five  | -5
 5 | 0 | five  | -5
(7 rows)

SELECT *
  FROM J1_TBL t1 (a, b, c) NATURAL JOIN J2_TBL t2 (d, a);
 a | b |  c   | d 
---+---+------+---
 0 |   | zero |  
 2 | 3 | two  | 2
 4 | 1 | four | 2
(3 rows)

-- mismatch number of columns
-- currently, Postgres will fill in with underlying names
SELECT *
  FROM J1_TBL t1 (a, b) NATURAL JOIN J2_TBL t2 (a);
 a | b |   t   | k  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 5 | 0 | five  | -5
 5 | 0 | five  | -5
(7 rows)

--
-- Inner joins (equi-joins)
--
SELECT *
  FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i = J2_TBL.i);
 i | j |   t   | i | k  
---+---+-------+---+----
 0 |   | zero  | 0 |   
 1 | 4 | one   | 1 | -1
 2 | 3 | two   | 2 |  2
 2 | 3 | two   | 2 |  4
 3 | 2 | three | 3 | -3
 5 | 0 | five  | 5 | -5
 5 | 0 | five  | 5 | -5
(7 rows)

SELECT *
  FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i = J2_TBL.k);
 i | j |  t   | i | k 
---+---+------+---+---
 0 |   | zero |   | 0
 2 | 3 | two  | 2 | 2
 4 | 1 | four | 2 | 4
(3 rows)

--
-- Non-equi-joins
--
SELECT *
  FROM J1_TBL JOIN J2_TBL ON (J1_TBL.i <= J2_TBL.k);
 i | j |   t   | i | k 
---+---+-------+---+---
 1 | 4 | one   | 2 | 2
 2 | 3 | two   | 2 | 2
 0 |   | zero  | 2 | 2
 1 | 4 | one   | 2 | 4
 2 | 3 | two   | 2 | 4
 3 | 2 | three | 2 | 4
 4 | 1 | four  | 2 | 4
 0 |   | zero  | 2 | 4
 0 |   | zero  |   | 0
(9 rows)

--
-- Outer joins
-- Note that OUTER is a noise word
--
SELECT *
  FROM J1_TBL LEFT OUTER JOIN J2_TBL USING (i)
  ORDER BY i, k, t;
 i | j |   t   | k  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 4 | 1 | four  |   
 5 | 0 | five  | -5
 5 | 0 | five  | -5
 6 | 6 | six   |   
 7 | 7 | seven |   
 8 | 8 | eight |   
   |   | null  |   
   | 0 | zero  |   
(13 rows)

SELECT *
  FROM J1_TBL LEFT JOIN J2_TBL USING (i)
  ORDER BY i, k, t;
 i | j |   t   | k  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 4 | 1 | four  |   
 5 | 0 | five  | -5
 5 | 0 | five  | -5
 6 | 6 | six   |   
 7 | 7 | seven |   
 8 | 8 | eight |   
   |   | null  |   
   | 0 | zero  |   
(13 rows)

SELECT *
  FROM J1_TBL RIGHT OUTER JOIN J2_TBL USING (i);
 i | j |   t   | k  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 5 | 0 | five  | -5
 5 | 0 | five  | -5
   |   |       |   
   |   |       |  0
(9 rows)

SELECT *
  FROM J1_TBL RIGHT JOIN J2_TBL USING (i);
 i | j |   t   | k  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 5 | 0 | five  | -5
 5 | 0 | five  | -5
   |   |       |   
   |   |       |  0
(9 rows)

SELECT *
  FROM J1_TBL FULL OUTER JOIN J2_TBL USING (i)
  ORDER BY i, k, t;
 i | j |   t   | k  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 4 | 1 | four  |   
 5 | 0 | five  | -5
 5 | 0 | five  | -5
 6 | 6 | six   |   
 7 | 7 | seven |   
 8 | 8 | eight |   
   |   |       |  0
   |   | null  |   
   | 0 | zero  |   
   |   |       |   
(15 rows)

SELECT *
  FROM J1_TBL FULL JOIN J2_TBL USING (i)
  ORDER BY i, k, t;
 i | j |   t   | k  
---+---+-------+----
 0 |   | zero  |   
 1 | 4 | one   | -1
 2 | 3 | two   |  2
 2 | 3 | two   |  4
 3 | 2 | three | -3
 4 | 1 | four  |   
 5 | 0 | five  | -5
 5 | 0 | five  | -5
 6 | 6 | six   |   
 7 | 7 | seven |   
 8 | 8 | eight |   
   |   |       |  0
   |   | null  |   
   | 0 | zero  |   
   |   |       |   
(15 rows)

SELECT *
  FROM J1_TBL LEFT JOIN J2_TBL USING (i) WHERE (k = 1);
 i | j | t | k 
---+---+---+---
(0 rows)

SELECT *
  FROM J1_TBL LEFT JOIN J2_TBL USING (i) WHERE (i = 1);
 i | j |  t  | k  
---+---+-----+----
 1 | 4 | one | -1
(1 row)

--
-- semijoin selectivity for <>
--
explain (costs off)
select * from tenk1 a, tenk1 b
where exists(select * from tenk1 c
             where b.twothousand = c.twothousand and b.fivethous <> c.fivethous)
      and a.tenthous = b.tenthous and a.tenthous < 5000;
                  QUERY PLAN                   
-----------------------------------------------
 Hash Semi Join
   Hash Cond: (b.twothousand = c.twothousand)
   Join Filter: (b.fivethous <> c.fivethous)
   ->  Hash Join
         Hash Cond: (b.tenthous = a.tenthous)
         ->  Seq Scan on tenk1 b
         ->  Hash
               ->  Seq Scan on tenk1 a
                     Filter: (tenthous < 5000)
   ->  Hash
         ->  Seq Scan on tenk1 c
(11 rows)

--
-- More complicated constructs
--
--
-- Multiway full join
--
CREATE TABLE t1 (name TEXT, n INTEGER);
CREATE TABLE t2 (name TEXT, n INTEGER);
CREATE TABLE t3 (name TEXT, n INTEGER);
INSERT INTO t1 VALUES ( 'bb', 11 );
INSERT INTO t2 VALUES ( 'bb', 12 );
INSERT INTO t2 VALUES ( 'cc', 22 );
INSERT INTO t2 VALUES ( 'ee', 42 );
INSERT INTO t3 VALUES ( 'bb', 13 );
INSERT INTO t3 VALUES ( 'cc', 23 );
INSERT INTO t3 VALUES ( 'dd', 33 );
SELECT * FROM t1 FULL JOIN t2 USING (name) FULL JOIN t3 USING (name);
 name | n  | n  | n  
------+----+----+----
 bb   | 11 | 12 | 13
 cc   |    | 22 | 23
 dd   |    |    | 33
 ee   |    | 42 |   
(4 rows)

--
-- Test interactions of join syntax and subqueries
--
-- Basic cases (we expect planner to pull up the subquery here)
SELECT * FROM
(SELECT * FROM t2) as s2
INNER JOIN
(SELECT * FROM t3) s3
USING (name);
 name | n  | n  
------+----+----
 bb   | 12 | 13
 cc   | 22 | 23
(2 rows)

SELECT * FROM
(SELECT * FROM t2) as s2
LEFT JOIN
(SELECT * FROM t3) s3
USING (name);
 name | n  | n  
------+----+----
 bb   | 12 | 13
 cc   | 22 | 23
 ee   | 42 |   
(3 rows)

SELECT * FROM
(SELECT * FROM t2) as s2
FULL JOIN
(SELECT * FROM t3) s3
USING (name);
 name | n  | n  
------+----+----
 bb   | 12 | 13
 cc   | 22 | 23
 dd   |    | 33
 ee   | 42 |   
(4 rows)

-- Cases with non-nullable expressions in subquery results;
-- make sure these go to null as expected
SELECT * FROM
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
NATURAL INNER JOIN
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
 name | s2_n | s2_2 | s3_n | s3_2 
------+------+------+------+------
 bb   |   12 |    2 |   13 |    3
 cc   |   22 |    2 |   23 |    3
(2 rows)

SELECT * FROM
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
NATURAL LEFT JOIN
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
 name | s2_n | s2_2 | s3_n | s3_2 
------+------+------+------+------
 bb   |   12 |    2 |   13 |    3
 cc   |   22 |    2 |   23 |    3
 ee   |   42 |    2 |      |     
(3 rows)

SELECT * FROM
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
NATURAL FULL JOIN
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
 name | s2_n | s2_2 | s3_n | s3_2 
------+------+------+------+------
 bb   |   12 |    2 |   13 |    3
 cc   |   22 |    2 |   23 |    3
 dd   |      |      |   33 |    3
 ee   |   42 |    2 |      |     
(4 rows)

SELECT * FROM
(SELECT name, n as s1_n, 1 as s1_1 FROM t1) as s1
NATURAL INNER JOIN
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
NATURAL INNER JOIN
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
 name | s1_n | s1_1 | s2_n | s2_2 | s3_n | s3_2 
------+------+------+------+------+------+------
 bb   |   11 |    1 |   12 |    2 |   13 |    3
(1 row)

SELECT * FROM
(SELECT name, n as s1_n, 1 as s1_1 FROM t1) as s1
NATURAL FULL JOIN
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
NATURAL FULL JOIN
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
 name | s1_n | s1_1 | s2_n | s2_2 | s3_n | s3_2 
------+------+------+------+------+------+------
 bb   |   11 |    1 |   12 |    2 |   13 |    3
 cc   |      |      |   22 |    2 |   23 |    3
 dd   |      |      |      |      |   33 |    3
 ee   |      |      |   42 |    2 |      |     
(4 rows)

SELECT * FROM
(SELECT name, n as s1_n FROM t1) as s1
NATURAL FULL JOIN
  (SELECT * FROM
    (SELECT name, n as s2_n FROM t2) as s2
    NATURAL FULL JOIN
    (SELECT name, n as s3_n FROM t3) as s3
  ) ss2;
 name | s1_n | s2_n | s3_n 
------+------+------+------
 bb   |   11 |   12 |   13
 cc   |      |   22 |   23
 dd   |      |      |   33
 ee   |      |   42 |     
(4 rows)

SELECT * FROM
(SELECT name, n as s1_n FROM t1) as s1
NATURAL FULL JOIN
  (SELECT * FROM
    (SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
    NATURAL FULL JOIN
    (SELECT name, n as s3_n FROM t3) as s3
  ) ss2;
 name | s1_n | s2_n | s2_2 | s3_n 
------+------+------+------+------
 bb   |   11 |   12 |    2 |   13
 cc   |      |   22 |    2 |   23
 dd   |      |      |      |   33
 ee   |      |   42 |    2 |     
(4 rows)

-- Constants as join keys can also be problematic
SELECT * FROM
  (SELECT name, n as s1_n FROM t1) as s1
FULL JOIN
  (SELECT name, 2 as s2_n FROM t2) as s2
ON (s1_n = s2_n);
 name | s1_n | name | s2_n 
------+------+------+------
      |      | bb   |    2
      |      | cc   |    2
      |      | ee   |    2
 bb   |   11 |      |     
(4 rows)

-- Test for propagation of nullability constraints into sub-joins
create temp table x (x1 int, x2 int);
insert into x values (1,11);
insert into x values (2,22);
insert into x values (3,null);
insert into x values (4,44);
insert into x values (5,null);
create temp table y (y1 int, y2 int);
insert into y values (1,111);
insert into y values (2,222);
insert into y values (3,333);
insert into y values (4,null);
select * from x;
 x1 | x2 
----+----
  1 | 11
  2 | 22
  3 |   
  4 | 44
  5 |   
(5 rows)

select * from y;
 y1 | y2  
----+-----
  1 | 111
  2 | 222
  3 | 333
  4 |    
(4 rows)

select * from x left join y on (x1 = y1 and x2 is not null);
 x1 | x2 | y1 | y2  
----+----+----+-----
  1 | 11 |  1 | 111
  2 | 22 |  2 | 222
  3 |    |    |    
  4 | 44 |  4 |    
  5 |    |    |    
(5 rows)

select * from x left join y on (x1 = y1 and y2 is not null);
 x1 | x2 | y1 | y2  
----+----+----+-----
  1 | 11 |  1 | 111
  2 | 22 |  2 | 222
  3 |    |  3 | 333
  4 | 44 |    |    
  5 |    |    |    
(5 rows)

select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
on (x1 = xx1);
 x1 | x2 | y1 | y2  | xx1 | xx2 
----+----+----+-----+-----+-----
  1 | 11 |  1 | 111 |   1 |  11
  2 | 22 |  2 | 222 |   2 |  22
  3 |    |  3 | 333 |   3 |    
  4 | 44 |  4 |     |   4 |  44
  5 |    |    |     |   5 |    
(5 rows)

select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
on (x1 = xx1 and x2 is not null);
 x1 | x2 | y1 | y2  | xx1 | xx2 
----+----+----+-----+-----+-----
  1 | 11 |  1 | 111 |   1 |  11
  2 | 22 |  2 | 222 |   2 |  22
  3 |    |  3 | 333 |     |    
  4 | 44 |  4 |     |   4 |  44
  5 |    |    |     |     |    
(5 rows)

select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
on (x1 = xx1 and y2 is not null);
 x1 | x2 | y1 | y2  | xx1 | xx2 
----+----+----+-----+-----+-----
  1 | 11 |  1 | 111 |   1 |  11
  2 | 22 |  2 | 222 |   2 |  22
  3 |    |  3 | 333 |   3 |    
  4 | 44 |  4 |     |     |    
  5 |    |    |     |     |    
(5 rows)

select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
on (x1 = xx1 and xx2 is not null);
 x1 | x2 | y1 | y2  | xx1 | xx2 
----+----+----+-----+-----+-----
  1 | 11 |  1 | 111 |   1 |  11
  2 | 22 |  2 | 222 |   2 |  22
  3 |    |  3 | 333 |     |    
  4 | 44 |  4 |     |   4 |  44
  5 |    |    |     |     |    
(5 rows)

-- these should NOT give the same answers as above
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
on (x1 = xx1) where (x2 is not null);
 x1 | x2 | y1 | y2  | xx1 | xx2 
----+----+----+-----+-----+-----
  1 | 11 |  1 | 111 |   1 |  11
  2 | 22 |  2 | 222 |   2 |  22
  4 | 44 |  4 |     |   4 |  44
(3 rows)

select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
on (x1 = xx1) where (y2 is not null);
 x1 | x2 | y1 | y2  | xx1 | xx2 
----+----+----+-----+-----+-----
  1 | 11 |  1 | 111 |   1 |  11
  2 | 22 |  2 | 222 |   2 |  22
  3 |    |  3 | 333 |   3 |    
(3 rows)

select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
on (x1 = xx1) where (xx2 is not null);
 x1 | x2 | y1 | y2  | xx1 | xx2 
----+----+----+-----+-----+-----
  1 | 11 |  1 | 111 |   1 |  11
  2 | 22 |  2 | 222 |   2 |  22
  4 | 44 |  4 |     |   4 |  44
(3 rows)

--
-- regression test: check for bug with propagation of implied equality
-- to outside an IN
--
select count(*) from tenk1 a where unique1 in
  (select unique1 from tenk1 b join tenk1 c using (unique1)
   where b.unique2 = 42);
 count 
-------
     1
(1 row)

--
-- regression test: check for failure to generate a plan with multiple
-- degenerate IN clauses
--
select count(*) from tenk1 x where
  x.unique1 in (select a.f1 from int4_tbl a,float8_tbl b where a.f1=b.f1) and
  x.unique1 = 0 and
  x.unique1 in (select aa.f1 from int4_tbl aa,float8_tbl bb where aa.f1=bb.f1);
 count 
-------
     1
(1 row)

-- try that with GEQO too
begin;
set geqo = on;
set geqo_threshold = 2;
select count(*) from tenk1 x where
  x.unique1 in (select a.f1 from int4_tbl a,float8_tbl b where a.f1=b.f1) and
  x.unique1 = 0 and
  x.unique1 in (select aa.f1 from int4_tbl aa,float8_tbl bb where aa.f1=bb.f1);
 count 
-------
     1
(1 row)

rollback;
--
-- regression test: be sure we cope with proven-dummy append rels
--
explain (costs off)
select aa, bb, unique1, unique1
  from tenk1 right join b_star on aa = unique1
  where bb < bb and bb is null;
        QUERY PLAN        
--------------------------
 Result
   One-Time Filter: false
(2 rows)

select aa, bb, unique1, unique1
  from tenk1 right join b_star on aa = unique1
  where bb < bb and bb is null;
 aa | bb | unique1 | unique1 
----+----+---------+---------
(0 rows)

--
-- regression test: check handling of empty-FROM subquery underneath outer join
--
explain (costs off)
select * from int8_tbl i1 left join (int8_tbl i2 join
  (select 123 as x) ss on i2.q1 = x) on i1.q2 = i2.q2
order by 12;
                QUERY PLAN                 
-------------------------------------------
 Sort
   Sort Key: i1.q1, i1.q2
   ->  Hash Left Join
         Hash Cond: (i1.q2 = i2.q2)
         ->  Seq Scan on int8_tbl i1
         ->  Hash
               ->  Seq Scan on int8_tbl i2
                     Filter: (q1 = 123)
(8 rows)

select * from int8_tbl i1 left join (int8_tbl i2 join
  (select 123 as x) ss on i2.q1 = x) on i1.q2 = i2.q2
order by 12;
        q1        |        q2         | q1  |        q2        |  x  
------------------+-------------------+-----+------------------+-----
              123 |               456 | 123 |              456 | 123
              123 |  4567890123456789 | 123 | 4567890123456789 | 123
 4567890123456789 | -4567890123456789 |     |                  |    
 4567890123456789 |               123 |     |                  |    
 4567890123456789 |  4567890123456789 | 123 | 4567890123456789 | 123
(5 rows)

--
-- regression test: check a case where join_clause_is_movable_into()
-- used to give an imprecise result, causing an assertion failure
--
select count(*)
from
  (select t3.tenthous as x1, coalesce(t1.stringu1, t2.stringu1) as x2
   from tenk1 t1
   left join tenk1 t2 on t1.unique1 = t2.unique1
   join tenk1 t3 on t1.unique2 = t3.unique2) ss,
  tenk1 t4,
  tenk1 t5
where t4.thousand = t5.unique1 and ss.x1 = t4.tenthous and ss.x2 = t5.stringu1;
 count 
-------
  1000
(1 row)

--
-- regression test: check a case where we formerly missed including an EC
-- enforcement clause because it was expected to be handled at scan level
--
explain (costs off)
select a.f1, b.f1, t.thousand, t.tenthous from
  tenk1 t,
  (select sum(f1)+1 as f1 from int4_tbl i4a) a,
  (select sum(f1) as f1 from int4_tbl i4b) b
where b.f1 = t.thousand and a.f1 = b.f1 and (a.f1+b.f1+999) = t.tenthous;
                                                   QUERY PLAN                                                    
-----------------------------------------------------------------------------------------------------------------
 Nested Loop
   ->  Nested Loop
         Join Filter: ((sum(i4b.f1)) = ((sum(i4a.f1) + 1)))
         ->  Aggregate
               ->  Seq Scan on int4_tbl i4a
         ->  Aggregate
               ->  Seq Scan on int4_tbl i4b
   ->  Index Only Scan using tenk1_thous_tenthous on tenk1 t
         Index Cond: ((thousand = (sum(i4b.f1))) AND (tenthous = ((((sum(i4a.f1) + 1)) + (sum(i4b.f1))) + 999)))
(9 rows)

select a.f1, b.f1, t.thousand, t.tenthous from
  tenk1 t,
  (select sum(f1)+1 as f1 from int4_tbl i4a) a,
  (select sum(f1) as f1 from int4_tbl i4b) b
where b.f1 = t.thousand and a.f1 = b.f1 and (a.f1+b.f1+999) = t.tenthous;
 f1 | f1 | thousand | tenthous 
----+----+----------+----------
(0 rows)

--
-- Test hash joins with multiple hash keys and subplans.
--
-- First ensure we get a hash join with multiple hash keys.
explain (costs off)
select t1.unique1,t2.unique1 from tenk1 t1
inner join tenk1 t2 on t1.two = t2.two
  and t1.unique1 = (select min(unique1) from tenk1
                    where t2.unique1=unique1)
where t1.unique1 < 10 and t2.unique1 < 10
order by t1.unique1;
                                             QUERY PLAN                                             
----------------------------------------------------------------------------------------------------
 Sort
   Sort Key: t1.unique1
   ->  Hash Join
         Hash Cond: ((t1.two = t2.two) AND (t1.unique1 = (SubPlan 2)))
         ->  Bitmap Heap Scan on tenk1 t1
               Recheck Cond: (unique1 < 10)
               ->  Bitmap Index Scan on tenk1_unique1
                     Index Cond: (unique1 < 10)
         ->  Hash
               ->  Bitmap Heap Scan on tenk1 t2
                     Recheck Cond: (unique1 < 10)
                     ->  Bitmap Index Scan on tenk1_unique1
                           Index Cond: (unique1 < 10)
               SubPlan 2
                 ->  Result
                       InitPlan 1
                         ->  Limit
                               ->  Index Only Scan using tenk1_unique1 on tenk1
                                     Index Cond: ((unique1 IS NOT NULL) AND (unique1 = t2.unique1))
(19 rows)

-- Ensure we get the expected result
select t1.unique1,t2.unique1 from tenk1 t1
inner join tenk1 t2 on t1.two = t2.two
  and t1.unique1 = (select min(unique1) from tenk1
                    where t2.unique1=unique1)
where t1.unique1 < 10 and t2.unique1 < 10
order by t1.unique1;
 unique1 | unique1 
---------+---------
       0 |       0
       1 |       1
       2 |       2
       3 |       3
       4 |       4
       5 |       5
       6 |       6
       7 |       7
       8 |       8
       9 |       9
(10 rows)

--
-- checks for correct handling of quals in multiway outer joins
--
explain (costs off)
select t1.f1
from int4_tbl t1, int4_tbl t2
  left join int4_tbl t3 on t3.f1 > 0
  left join int4_tbl t4 on t3.f1 > 1
where t4.f1 is null;
                      QUERY PLAN                       
-------------------------------------------------------
 Nested Loop
   ->  Nested Loop Left Join
         Filter: (t4.f1 IS NULL)
         ->  Seq Scan on int4_tbl t2
         ->  Materialize
               ->  Nested Loop Left Join
                     Join Filter: (t3.f1 > 1)
                     ->  Seq Scan on int4_tbl t3
                           Filter: (f1 > 0)
                     ->  Materialize
                           ->  Seq Scan on int4_tbl t4
   ->  Seq Scan on int4_tbl t1
(12 rows)

select t1.f1
from int4_tbl t1, int4_tbl t2
  left join int4_tbl t3 on t3.f1 > 0
  left join int4_tbl t4 on t3.f1 > 1
where t4.f1 is null;
 f1 
----
(0 rows)

explain (costs off)
select *
from int4_tbl t1 left join int4_tbl t2 on true
  left join int4_tbl t3 on t2.f1 > 0
  left join int4_tbl t4 on t3.f1 > 0;
                      QUERY PLAN                       
-------------------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on int4_tbl t1
   ->  Materialize
         ->  Nested Loop Left Join
               Join Filter: (t3.f1 > 0)
               ->  Nested Loop Left Join
                     Join Filter: (t2.f1 > 0)
                     ->  Seq Scan on int4_tbl t2
                     ->  Materialize
                           ->  Seq Scan on int4_tbl t3
               ->  Materialize
                     ->  Seq Scan on int4_tbl t4
(12 rows)

explain (costs off)
select * from onek t1
  left join onek t2 on t1.unique1 = t2.unique1
  left join onek t3 on t2.unique1 != t3.unique1
  left join onek t4 on t3.unique1 = t4.unique1;
                     QUERY PLAN                     
----------------------------------------------------
 Nested Loop Left Join
   Join Filter: (t2.unique1 <> t3.unique1)
   ->  Hash Left Join
         Hash Cond: (t1.unique1 = t2.unique1)
         ->  Seq Scan on onek t1
         ->  Hash
               ->  Seq Scan on onek t2
   ->  Materialize
         ->  Hash Left Join
               Hash Cond: (t3.unique1 = t4.unique1)
               ->  Seq Scan on onek t3
               ->  Hash
                     ->  Seq Scan on onek t4
(13 rows)

explain (costs off)
select * from int4_tbl t1
  left join (select now() from int4_tbl t2
             left join int4_tbl t3 on t2.f1 = t3.f1
             left join int4_tbl t4 on t3.f1 = t4.f1) s on true
  inner join int4_tbl t5 on true;
                         QUERY PLAN                          
-------------------------------------------------------------
 Nested Loop
   ->  Nested Loop Left Join
         ->  Seq Scan on int4_tbl t1
         ->  Materialize
               ->  Hash Left Join
                     Hash Cond: (t3.f1 = t4.f1)
                     ->  Hash Left Join
                           Hash Cond: (t2.f1 = t3.f1)
                           ->  Seq Scan on int4_tbl t2
                           ->  Hash
                                 ->  Seq Scan on int4_tbl t3
                     ->  Hash
                           ->  Seq Scan on int4_tbl t4
   ->  Materialize
         ->  Seq Scan on int4_tbl t5
(15 rows)

explain (costs off)
select * from int4_tbl t1
  left join int4_tbl t2 on true
  left join int4_tbl t3 on true
  left join int4_tbl t4 on t2.f1 = t3.f1;
                   QUERY PLAN                    
-------------------------------------------------
 Nested Loop Left Join
   Join Filter: (t2.f1 = t3.f1)
   ->  Nested Loop Left Join
         ->  Nested Loop Left Join
               ->  Seq Scan on int4_tbl t1
               ->  Materialize
                     ->  Seq Scan on int4_tbl t2
         ->  Materialize
               ->  Seq Scan on int4_tbl t3
   ->  Materialize
         ->  Seq Scan on int4_tbl t4
(11 rows)

explain (costs off)
select * from int4_tbl t1
  left join int4_tbl t2 on true
  left join int4_tbl t3 on t2.f1 = t3.f1
  left join int4_tbl t4 on t3.f1 != t4.f1;
                      QUERY PLAN                       
-------------------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on int4_tbl t1
   ->  Materialize
         ->  Nested Loop Left Join
               Join Filter: (t3.f1 <> t4.f1)
               ->  Hash Left Join
                     Hash Cond: (t2.f1 = t3.f1)
                     ->  Seq Scan on int4_tbl t2
                     ->  Hash
                           ->  Seq Scan on int4_tbl t3
               ->  Materialize
                     ->  Seq Scan on int4_tbl t4
(12 rows)

explain (costs off)
select * from int4_tbl t1
  left join (int4_tbl t2 left join int4_tbl t3 on t2.f1 > 0) on t2.f1 > 1
  left join int4_tbl t4 on t2.f1 > 2 and t3.f1 > 3
where t1.f1 = coalesce(t2.f1, 1);
                     QUERY PLAN                     
----------------------------------------------------
 Nested Loop Left Join
   Join Filter: ((t2.f1 > 2) AND (t3.f1 > 3))
   ->  Nested Loop Left Join
         Join Filter: (t2.f1 > 0)
         ->  Nested Loop Left Join
               Filter: (t1.f1 = COALESCE(t2.f1, 1))
               ->  Seq Scan on int4_tbl t1
               ->  Materialize
                     ->  Seq Scan on int4_tbl t2
                           Filter: (f1 > 1)
         ->  Materialize
               ->  Seq Scan on int4_tbl t3
   ->  Materialize
         ->  Seq Scan on int4_tbl t4
(14 rows)

explain (costs off)
select * from int4_tbl t1
  left join ((select t2.f1 from int4_tbl t2
                left join int4_tbl t3 on t2.f1 > 0
                where t3.f1 is null) s
             left join tenk1 t4 on s.f1 > 1)
    on s.f1 = t1.f1;
                   QUERY PLAN                    
-------------------------------------------------
 Hash Right Join
   Hash Cond: (t2.f1 = t1.f1)
   ->  Nested Loop Left Join
         Join Filter: (t2.f1 > 1)
         ->  Nested Loop Left Join
               Join Filter: (t2.f1 > 0)
               Filter: (t3.f1 IS NULL)
               ->  Seq Scan on int4_tbl t2
               ->  Materialize
                     ->  Seq Scan on int4_tbl t3
         ->  Seq Scan on tenk1 t4
   ->  Hash
         ->  Seq Scan on int4_tbl t1
(13 rows)

explain (costs off)
select * from int4_tbl t1
  left join ((select t2.f1 from int4_tbl t2
                left join int4_tbl t3 on t2.f1 > 0
                where t2.f1 <> coalesce(t3.f1, -1)) s
             left join tenk1 t4 on s.f1 > 1)
    on s.f1 = t1.f1;
                           QUERY PLAN                            
-----------------------------------------------------------------
 Nested Loop Left Join
   Join Filter: (t2.f1 > 1)
   ->  Hash Right Join
         Hash Cond: (t2.f1 = t1.f1)
         ->  Nested Loop Left Join
               Join Filter: (t2.f1 > 0)
               Filter: (t2.f1 <> COALESCE(t3.f1, '-1'::integer))
               ->  Seq Scan on int4_tbl t2
               ->  Materialize
                     ->  Seq Scan on int4_tbl t3
         ->  Hash
               ->  Seq Scan on int4_tbl t1
   ->  Materialize
         ->  Seq Scan on tenk1 t4
(14 rows)

explain (costs off)
select * from onek t1
    left join onek t2 on t1.unique1 = t2.unique1
    left join onek t3 on t2.unique1 = t3.unique1
    left join onek t4 on t3.unique1 = t4.unique1 and t2.unique2 = t4.unique2;
                               QUERY PLAN                               
------------------------------------------------------------------------
 Hash Left Join
   Hash Cond: ((t3.unique1 = t4.unique1) AND (t2.unique2 = t4.unique2))
   ->  Hash Left Join
         Hash Cond: (t2.unique1 = t3.unique1)
         ->  Hash Left Join
               Hash Cond: (t1.unique1 = t2.unique1)
               ->  Seq Scan on onek t1
               ->  Hash
                     ->  Seq Scan on onek t2
         ->  Hash
               ->  Seq Scan on onek t3
   ->  Hash
         ->  Seq Scan on onek t4
(13 rows)

explain (costs off)
select * from int8_tbl t1 left join
    (int8_tbl t2 left join int8_tbl t3 full join int8_tbl t4 on false on false)
    left join int8_tbl t5 on t2.q1 = t5.q1
on t2.q2 = 123;
                    QUERY PLAN                    
--------------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on int8_tbl t1
   ->  Materialize
         ->  Nested Loop Left Join
               Join Filter: (t2.q1 = t5.q1)
               ->  Nested Loop Left Join
                     Join Filter: false
                     ->  Seq Scan on int8_tbl t2
                           Filter: (q2 = 123)
                     ->  Result
                           One-Time Filter: false
               ->  Seq Scan on int8_tbl t5
(12 rows)

explain (costs off)
select * from int8_tbl t1
    left join int8_tbl t2 on true
    left join lateral
      (select * from int8_tbl t3 where t3.q1 = t2.q1 offset 0) s
      on t2.q1 = 1;
                QUERY PLAN                 
-------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on int8_tbl t1
   ->  Materialize
         ->  Nested Loop Left Join
               Join Filter: (t2.q1 = 1)
               ->  Seq Scan on int8_tbl t2
               ->  Seq Scan on int8_tbl t3
                     Filter: (q1 = t2.q1)
(8 rows)

explain (costs off)
select * from int8_tbl t1
    left join int8_tbl t2 on true
    left join lateral
      (select * from generate_series(t2.q1, 100)) s
      on t2.q1 = 1;
                     QUERY PLAN                     
----------------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on int8_tbl t1
   ->  Materialize
         ->  Nested Loop Left Join
               Join Filter: (t2.q1 = 1)
               ->  Seq Scan on int8_tbl t2
               ->  Function Scan on generate_series
(7 rows)

explain (costs off)
select * from int8_tbl t1
    left join int8_tbl t2 on true
    left join lateral
      (select t2.q1 from int8_tbl t3) s
      on t2.q1 = 1;
                QUERY PLAN                 
-------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on int8_tbl t1
   ->  Materialize
         ->  Nested Loop Left Join
               Join Filter: (t2.q1 = 1)
               ->  Seq Scan on int8_tbl t2
               ->  Seq Scan on int8_tbl t3
(7 rows)

explain (costs off)
select * from onek t1
    left join onek t2 on true
    left join lateral
      (select * from onek t3 where t3.two = t2.two offset 0) s
      on t2.unique1 = 1;
                    QUERY PLAN                    
--------------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on onek t1
   ->  Materialize
         ->  Nested Loop Left Join
               Join Filter: (t2.unique1 = 1)
               ->  Seq Scan on onek t2
               ->  Memoize
                     Cache Key: t2.two
                     Cache Mode: binary
                     ->  Seq Scan on onek t3
                           Filter: (two = t2.two)
(11 rows)

--
-- check a case where we formerly got confused by conflicting sort orders
-- in redundant merge join path keys
--
explain (costs off)
select * from
  j1_tbl full join
  (select * from j2_tbl order by j2_tbl.i desc, j2_tbl.k asc) j2_tbl
  on j1_tbl.i = j2_tbl.i and j1_tbl.i = j2_tbl.k;
                           QUERY PLAN                            
-----------------------------------------------------------------
 Merge Full Join
   Merge Cond: ((j2_tbl.i = j1_tbl.i) AND (j2_tbl.k = j1_tbl.i))
   ->  Sort
         Sort Key: j2_tbl.i DESC, j2_tbl.k
         ->  Seq Scan on j2_tbl
   ->  Sort
         Sort Key: j1_tbl.i DESC
         ->  Seq Scan on j1_tbl
(8 rows)

select * from
  j1_tbl full join
  (select * from j2_tbl order by j2_tbl.i desc, j2_tbl.k asc) j2_tbl
  on j1_tbl.i = j2_tbl.i and j1_tbl.i = j2_tbl.k;
 i | j |   t   | i | k  
---+---+-------+---+----
   |   |       |   |  0
   |   |       |   |   
   | 0 | zero  |   |   
   |   | null  |   |   
 8 | 8 | eight |   |   
 7 | 7 | seven |   |   
 6 | 6 | six   |   |   
   |   |       | 5 | -5
   |   |       | 5 | -5
 5 | 0 | five  |   |   
 4 | 1 | four  |   |   
   |   |       | 3 | -3
 3 | 2 | three |   |   
 2 | 3 | two   | 2 |  2
   |   |       | 2 |  4
   |   |       | 1 | -1
   |   |       | 0 |   
 1 | 4 | one   |   |   
 0 |   | zero  |   |   
(19 rows)

--
-- a different check for handling of redundant sort keys in merge joins
--
explain (costs off)
select count(*) from
  (select * from tenk1 x order by x.thousand, x.twothousand, x.fivethous) x
  left join
  (select * from tenk1 y order by y.unique2) y
  on x.thousand = y.unique2 and x.twothousand = y.hundred and x.fivethous = y.unique2;
                                    QUERY PLAN                                    
----------------------------------------------------------------------------------
 Aggregate
   ->  Merge Left Join
         Merge Cond: (x.thousand = y.unique2)
         Join Filter: ((x.twothousand = y.hundred) AND (x.fivethous = y.unique2))
         ->  Sort
               Sort Key: x.thousand, x.twothousand, x.fivethous
               ->  Seq Scan on tenk1 x
         ->  Materialize
               ->  Index Scan using tenk1_unique2 on tenk1 y
(9 rows)

select count(*) from
  (select * from tenk1 x order by x.thousand, x.twothousand, x.fivethous) x
  left join
  (select * from tenk1 y order by y.unique2) y
  on x.thousand = y.unique2 and x.twothousand = y.hundred and x.fivethous = y.unique2;
 count 
-------
 10000
(1 row)

set enable_hashjoin = 0;
set enable_nestloop = 0;
set enable_hashagg = 0;
--
-- Check that we use the pathkeys from a prefix of the group by / order by
-- clause for the join pathkeys when that prefix covers all join quals.  We
-- expect this to lead to an incremental sort for the group by / order by.
--
explain (costs off)
select x.thousand, x.twothousand, count(*)
from tenk1 x inner join tenk1 y on x.thousand = y.thousand
group by x.thousand, x.twothousand
order by x.thousand desc, x.twothousand;
                                    QUERY PLAN                                    
----------------------------------------------------------------------------------
 GroupAggregate
   Group Key: x.thousand, x.twothousand
   ->  Incremental Sort
         Sort Key: x.thousand DESC, x.twothousand
         Presorted Key: x.thousand
         ->  Merge Join
               Merge Cond: (y.thousand = x.thousand)
               ->  Index Only Scan Backward using tenk1_thous_tenthous on tenk1 y
               ->  Sort
                     Sort Key: x.thousand DESC
                     ->  Seq Scan on tenk1 x
(11 rows)

reset enable_hashagg;
reset enable_nestloop;
reset enable_hashjoin;
--
-- Clean up
--
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
DROP TABLE J1_TBL;
DROP TABLE J2_TBL;
-- Both DELETE and UPDATE allow the specification of additional tables
-- to "join" against to determine which rows should be modified.
CREATE TEMP TABLE t1 (a int, b int);
CREATE TEMP TABLE t2 (a int, b int);
CREATE TEMP TABLE t3 (x int, y int);
INSERT INTO t1 VALUES (510);
INSERT INTO t1 VALUES (1520);
INSERT INTO t1 VALUES (100100);
INSERT INTO t1 VALUES (2001000);
INSERT INTO t2 VALUES (2002000);
INSERT INTO t3 VALUES (520);
INSERT INTO t3 VALUES (67);
INSERT INTO t3 VALUES (78);
INSERT INTO t3 VALUES (500100);
DELETE FROM t3 USING t1 table1 WHERE t3.x = table1.a;
SELECT * FROM t3;
  x  |  y  
-----+-----
   6 |   7
   7 |   8
 500 | 100
(3 rows)

DELETE FROM t3 USING t1 JOIN t2 USING (a) WHERE t3.x > t1.a;
SELECT * FROM t3;
 x | y 
---+---
 6 | 7
 7 | 8
(2 rows)

DELETE FROM t3 USING t3 t3_other WHERE t3.x = t3_other.x AND t3.y = t3_other.y;
SELECT * FROM t3;
 x | y 
---+---
(0 rows)

-- Test join against inheritance tree
create temp table t2a () inherits (t2);
insert into t2a values (2002001);
select * from t1 left join t2 on (t1.a = t2.a);
  a  |  b   |  a  |  b   
-----+------+-----+------
   5 |   10 |     |     
  15 |   20 |     |     
 100 |  100 |     |     
 200 | 1000 | 200 | 2000
 200 | 1000 | 200 | 2001
(5 rows)

-- Test matching of column name with wrong alias
select t1.x from t1 join t3 on (t1.a = t3.x);
ERROR:  column t1.x does not exist
LINE 1: select t1.x from t1 join t3 on (t1.a = t3.x);
               ^
HINT:  Perhaps you meant to reference the column "t3.x".
-- Test matching of locking clause with wrong alias
select t1.*, t2.*, unnamed_join.* from
  t1 join t2 on (t1.a = t2.a), t3 as unnamed_join
  for update of unnamed_join;
 a | b | a | b | x | y 
---+---+---+---+---+---
(0 rows)

select foo.*, unnamed_join.* from
  t1 join t2 using (a) as foo, t3 as unnamed_join
  for update of unnamed_join;
 a | x | y 
---+---+---
(0 rows)

select foo.*, unnamed_join.* from
  t1 join t2 using (a) as foo, t3 as unnamed_join
  for update of foo;
ERROR:  FOR UPDATE cannot be applied to a join
LINE 3:   for update of foo;
                        ^
select bar.*, unnamed_join.* from
  (t1 join t2 using (a) as foo) as bar, t3 as unnamed_join
  for update of foo;
ERROR:  relation "foo" in FOR UPDATE clause not found in FROM clause
LINE 3:   for update of foo;
                        ^
select bar.*, unnamed_join.* from
  (t1 join t2 using (a) as foo) as bar, t3 as unnamed_join
  for update of bar;
ERROR:  FOR UPDATE cannot be applied to a join
LINE 3:   for update of bar;
                        ^
--
-- regression test for 8.1 merge right join bug
--
CREATE TEMP TABLE tt1 ( tt1_id int4, joincol int4 );
INSERT INTO tt1 VALUES (111);
INSERT INTO tt1 VALUES (2, NULL);
CREATE TEMP TABLE tt2 ( tt2_id int4, joincol int4 );
INSERT INTO tt2 VALUES (2111);
INSERT INTO tt2 VALUES (2211);
set enable_hashjoin to off;
set enable_nestloop to off;
-- these should give the same results
select tt1.*, tt2.* from tt1 left join tt2 on tt1.joincol = tt2.joincol;
 tt1_id | joincol | tt2_id | joincol 
--------+---------+--------+---------
      1 |      11 |     21 |      11
      1 |      11 |     22 |      11
      2 |         |        |        
(3 rows)

select tt1.*, tt2.* from tt2 right join tt1 on tt1.joincol = tt2.joincol;
 tt1_id | joincol | tt2_id | joincol 
--------+---------+--------+---------
      1 |      11 |     21 |      11
      1 |      11 |     22 |      11
      2 |         |        |        
(3 rows)

reset enable_hashjoin;
reset enable_nestloop;
--
-- regression test for bug #18522 (merge-right-anti-join in inner_unique cases)
--
create temp table tbl_ra(a int unique, b int);
insert into tbl_ra select i, i%100 from generate_series(1,1000)i;
create index on tbl_ra (b);
analyze tbl_ra;
set enable_hashjoin to off;
set enable_nestloop to off;
-- ensure we get a merge right anti join
explain (costs off)
select * from tbl_ra t1
where not exists (select 1 from tbl_ra t2 where t2.b = t1.a) and t1.b < 2;
                      QUERY PLAN                       
-------------------------------------------------------
 Merge Right Anti Join
   Merge Cond: (t2.b = t1.a)
   ->  Index Only Scan using tbl_ra_b_idx on tbl_ra t2
   ->  Sort
         Sort Key: t1.a
         ->  Bitmap Heap Scan on tbl_ra t1
               Recheck Cond: (b < 2)
               ->  Bitmap Index Scan on tbl_ra_b_idx
                     Index Cond: (b < 2)
(9 rows)

-- and check we get the expected results
select * from tbl_ra t1
where not exists (select 1 from tbl_ra t2 where t2.b = t1.a) and t1.b < 2;
  a   | b 
------+---
  100 | 0
  101 | 1
  200 | 0
  201 | 1
  300 | 0
  301 | 1
  400 | 0
  401 | 1
  500 | 0
  501 | 1
  600 | 0
  601 | 1
  700 | 0
  701 | 1
  800 | 0
  801 | 1
  900 | 0
  901 | 1
 1000 | 0
(19 rows)

reset enable_hashjoin;
reset enable_nestloop;
--
-- regression test for bug with hash-right-semi join
--
create temp table tbl_rs(a int, b int);
insert into tbl_rs select i, i from generate_series(1,10)i;
analyze tbl_rs;
-- ensure we get a hash right semi join
explain (costs off)
select * from tbl_rs t1 join
  lateral (select * from tbl_rs t2 where t2.a in
            (select t1.a+t3.a from tbl_rs t3) and t2.a < 5)
  on true;
                QUERY PLAN                 
-------------------------------------------
 Nested Loop
   ->  Seq Scan on tbl_rs t1
   ->  Hash Right Semi Join
         Hash Cond: ((t1.a + t3.a) = t2.a)
         ->  Seq Scan on tbl_rs t3
         ->  Hash
               ->  Seq Scan on tbl_rs t2
                     Filter: (a < 5)
(8 rows)

-- and check we get the expected results
select * from tbl_rs t1 join
  lateral (select * from tbl_rs t2 where t2.a in
            (select t1.a+t3.a from tbl_rs t3) and t2.a < 5)
  on true;
 a | b | a | b 
---+---+---+---
 1 | 1 | 2 | 2
 1 | 1 | 3 | 3
 1 | 1 | 4 | 4
 2 | 2 | 3 | 3
 2 | 2 | 4 | 4
 3 | 3 | 4 | 4
(6 rows)

--
-- regression test for bug with parallel-hash-right-semi join
--
begin;
-- encourage use of parallel plans
set local parallel_setup_cost=0;
set local parallel_tuple_cost=0;
set local min_parallel_table_scan_size=0;
set local max_parallel_workers_per_gather=4;
-- ensure we don't get parallel hash right semi join
explain (costs off)
select * from tenk1 t1
where exists (select 1 from tenk1 t2 where fivethous = t1.fivethous)
and t1.fivethous < 5;
                    QUERY PLAN                    
--------------------------------------------------
 Gather
   Workers Planned: 4
   ->  Parallel Hash Semi Join
         Hash Cond: (t1.fivethous = t2.fivethous)
         ->  Parallel Seq Scan on tenk1 t1
               Filter: (fivethous < 5)
         ->  Parallel Hash
               ->  Parallel Seq Scan on tenk1 t2
(8 rows)

rollback;
--
-- regression test for bug #13908 (hash join with skew tuples & nbatch increase)
--
set work_mem to '64kB';
set enable_mergejoin to off;
set enable_memoize to off;
explain (costs off)
select count(*) from tenk1 a, tenk1 b
  where a.hundred = b.thousand and (b.fivethous % 10) < 10;
                         QUERY PLAN                         
------------------------------------------------------------
 Aggregate
   ->  Hash Join
         Hash Cond: (a.hundred = b.thousand)
         ->  Index Only Scan using tenk1_hundred on tenk1 a
         ->  Hash
               ->  Seq Scan on tenk1 b
                     Filter: ((fivethous % 10) < 10)
(7 rows)

select count(*) from tenk1 a, tenk1 b
  where a.hundred = b.thousand and (b.fivethous % 10) < 10;
 count  
--------
 100000
(1 row)

reset work_mem;
reset enable_mergejoin;
reset enable_memoize;
--
-- regression test for 8.2 bug with improper re-ordering of left joins
--
create temp table tt3(f1 int, f2 text);
insert into tt3 select x, repeat('xyzzy', 100) from generate_series(1,10000) x;
analyze tt3;
create temp table tt4(f1 int);
insert into tt4 values (0),(1),(9999);
analyze tt4;
set enable_nestloop to off;
EXPLAIN (COSTS OFF)
SELECT a.f1
FROM tt4 a
LEFT JOIN (
        SELECT b.f1
        FROM tt3 b LEFT JOIN tt3 c ON (b.f1 = c.f1)
        WHERE COALESCE(c.f1, 0) = 0
) AS d ON (a.f1 = d.f1)
WHERE COALESCE(d.f1, 0) = 0
ORDER BY 1;
                  QUERY PLAN                   
-----------------------------------------------
 Sort
   Sort Key: a.f1
   ->  Hash Right Join
         Hash Cond: (b.f1 = a.f1)
         Filter: (COALESCE(b.f1, 0) = 0)
         ->  Hash Left Join
               Hash Cond: (b.f1 = c.f1)
               Filter: (COALESCE(c.f1, 0) = 0)
               ->  Seq Scan on tt3 b
               ->  Hash
                     ->  Seq Scan on tt3 c
         ->  Hash
               ->  Seq Scan on tt4 a
(13 rows)

SELECT a.f1
FROM tt4 a
LEFT JOIN (
        SELECT b.f1
        FROM tt3 b LEFT JOIN tt3 c ON (b.f1 = c.f1)
        WHERE COALESCE(c.f1, 0) = 0
) AS d ON (a.f1 = d.f1)
WHERE COALESCE(d.f1, 0) = 0
ORDER BY 1;
  f1  
------
    0
    1
 9999
(3 rows)

reset enable_nestloop;
--
-- basic semijoin and antijoin recognition tests
--
explain (costs off)
select a.* from tenk1 a
where unique1 in (select unique2 from tenk1 b);
                         QUERY PLAN                         
------------------------------------------------------------
 Hash Semi Join
   Hash Cond: (a.unique1 = b.unique2)
   ->  Seq Scan on tenk1 a
   ->  Hash
         ->  Index Only Scan using tenk1_unique2 on tenk1 b
(5 rows)

-- sadly, this is not an antijoin
explain (costs off)
select a.* from tenk1 a
where unique1 not in (select unique2 from tenk1 b);
                        QUERY PLAN                         
-----------------------------------------------------------
 Seq Scan on tenk1 a
   Filter: (NOT (ANY (unique1 = (hashed SubPlan 1).col1)))
   SubPlan 1
     ->  Index Only Scan using tenk1_unique2 on tenk1 b
(4 rows)

explain (costs off)
select a.* from tenk1 a
where exists (select 1 from tenk1 b where a.unique1 = b.unique2);
                         QUERY PLAN                         
------------------------------------------------------------
 Hash Semi Join
   Hash Cond: (a.unique1 = b.unique2)
   ->  Seq Scan on tenk1 a
   ->  Hash
         ->  Index Only Scan using tenk1_unique2 on tenk1 b
(5 rows)

explain (costs off)
select a.* from tenk1 a
where not exists (select 1 from tenk1 b where a.unique1 = b.unique2);
                         QUERY PLAN                         
------------------------------------------------------------
 Hash Anti Join
   Hash Cond: (a.unique1 = b.unique2)
   ->  Seq Scan on tenk1 a
   ->  Hash
         ->  Index Only Scan using tenk1_unique2 on tenk1 b
(5 rows)

explain (costs off)
select a.* from tenk1 a left join tenk1 b on a.unique1 = b.unique2
where b.unique2 is null;
                         QUERY PLAN                         
------------------------------------------------------------
 Hash Anti Join
   Hash Cond: (a.unique1 = b.unique2)
   ->  Seq Scan on tenk1 a
   ->  Hash
         ->  Index Only Scan using tenk1_unique2 on tenk1 b
(5 rows)

-- check that we avoid de-duplicating columns redundantly
set enable_memoize to off;
explain (costs off)
select 1 from tenk1
where (hundred, thousand) in (select twothousand, twothousand from onek);
                   QUERY PLAN                    
-------------------------------------------------
 Hash Join
   Hash Cond: (tenk1.hundred = onek.twothousand)
   ->  Seq Scan on tenk1
         Filter: (hundred = thousand)
   ->  Hash
         ->  HashAggregate
               Group Key: onek.twothousand
               ->  Seq Scan on onek
(8 rows)

reset enable_memoize;
--
-- regression test for bogus RTE_GROUP entries
--
explain (costs off)
select a.* from tenk1 a
where exists (select 1 from tenk1 b where a.unique1 = b.unique2 group by b.unique1);
                         QUERY PLAN                         
------------------------------------------------------------
 Hash Semi Join
   Hash Cond: (a.unique1 = b.unique2)
   ->  Seq Scan on tenk1 a
   ->  Hash
         ->  Index Only Scan using tenk1_unique2 on tenk1 b
(5 rows)

--
-- regression test for proper handling of outer joins within antijoins
--
create temp table tt4x(c1 int, c2 int, c3 int);
explain (costs off)
select * from tt4x t1
where not exists (
  select 1 from tt4x t2
    left join tt4x t3 on t2.c3 = t3.c1
    left join ( select t5.c1 as c1
                from tt4x t4 left join tt4x t5 on t4.c2 = t5.c1
              ) a1 on t3.c2 = a1.c1
  where t1.c1 = t2.c2
);
                       QUERY PLAN                        
---------------------------------------------------------
 Hash Anti Join
   Hash Cond: (t1.c1 = t2.c2)
   ->  Seq Scan on tt4x t1
   ->  Hash
         ->  Merge Right Join
               Merge Cond: (t5.c1 = t3.c2)
               ->  Merge Join
                     Merge Cond: (t4.c2 = t5.c1)
                     ->  Sort
                           Sort Key: t4.c2
                           ->  Seq Scan on tt4x t4
                     ->  Sort
                           Sort Key: t5.c1
                           ->  Seq Scan on tt4x t5
               ->  Sort
                     Sort Key: t3.c2
                     ->  Merge Left Join
                           Merge Cond: (t2.c3 = t3.c1)
                           ->  Sort
                                 Sort Key: t2.c3
                                 ->  Seq Scan on tt4x t2
                           ->  Sort
                                 Sort Key: t3.c1
                                 ->  Seq Scan on tt4x t3
(24 rows)

--
-- regression test for problems of the sort depicted in bug #3494
--
create temp table tt5(f1 int, f2 int);
create temp table tt6(f1 int, f2 int);
insert into tt5 values(110);
insert into tt5 values(111);
insert into tt6 values(19);
insert into tt6 values(12);
insert into tt6 values(29);
select * from tt5,tt6 where tt5.f1 = tt6.f1 and tt5.f1 = tt5.f2 - tt6.f2;
 f1 | f2 | f1 | f2 
----+----+----+----
  1 | 10 |  1 |  9
(1 row)

--
-- regression test for problems of the sort depicted in bug #3588
--
create temp table xx (pkxx int);
create temp table yy (pkyy int, pkxx int);
insert into xx values (1);
insert into xx values (2);
insert into xx values (3);
insert into yy values (1011);
insert into yy values (2012);
insert into yy values (301, NULL);
select yy.pkyy as yy_pkyy, yy.pkxx as yy_pkxx, yya.pkyy as yya_pkyy,
       xxa.pkxx as xxa_pkxx, xxb.pkxx as xxb_pkxx
from yy
     left join (SELECT * FROM yy where pkyy = 101) as yya ON yy.pkyy = yya.pkyy
     left join xx xxa on yya.pkxx = xxa.pkxx
     left join xx xxb on coalesce (xxa.pkxx, 1) = xxb.pkxx;
 yy_pkyy | yy_pkxx | yya_pkyy | xxa_pkxx | xxb_pkxx 
---------+---------+----------+----------+----------
     101 |       1 |      101 |        1 |        1
     201 |       2 |          |          |        1
     301 |         |          |          |        1
(3 rows)

--
-- regression test for improper pushing of constants across outer-join clauses
-- (as seen in early 8.2.x releases)
--
create temp table zt1 (f1 int primary key);
create temp table zt2 (f2 int primary key);
create temp table zt3 (f3 int primary key);
insert into zt1 values(53);
insert into zt2 values(53);
select * from
  zt2 left join zt3 on (f2 = f3)
      left join zt1 on (f3 = f1)
where f2 = 53;
 f2 | f3 | f1 
----+----+----
 53 |    |   
(1 row)

create temp view zv1 as select *,'dummy'::text AS junk from zt1;
select * from
  zt2 left join zt3 on (f2 = f3)
      left join zv1 on (f3 = f1)
where f2 = 53;
 f2 | f3 | f1 | junk 
----+----+----+------
 53 |    |    | 
(1 row)

--
-- regression test for improper extraction of OR indexqual conditions
-- (as seen in early 8.3.x releases)
--
select a.unique2, a.ten, b.tenthous, b.unique2, b.hundred
from tenk1 a left join tenk1 b on a.unique2 = b.tenthous
where a.unique1 = 42 and
      ((b.unique2 is null and a.ten = 2) or b.hundred = 3);
 unique2 | ten | tenthous | unique2 | hundred 
---------+-----+----------+---------+---------
(0 rows)

--
-- test proper positioning of one-time quals in EXISTS (8.4devel bug)
--
prepare foo(bool) as
  select count(*) from tenk1 a left join tenk1 b
    on (a.unique2 = b.unique1 and exists
        (select 1 from tenk1 c where c.thousand = b.unique2 and $1));
execute foo(true);
 count 
-------
 10000
(1 row)

execute foo(false);
 count 
-------
 10000
(1 row)

--
-- test for sane behavior with noncanonical merge clauses, per bug #4926
--
begin;
set enable_mergejoin = 1;
set enable_hashjoin = 0;
set enable_nestloop = 0;
create temp table a (i integer);
create temp table b (x integer, y integer);
select * from a left join b on i = x and i = y and x = i;
 i | x | y 
---+---+---
(0 rows)

rollback;
--
-- test handling of merge clauses using record_ops
--
begin;
create type mycomptype as (id int, v bigint);
create temp table tidv (idv mycomptype);
create index on tidv (idv);
explain (costs off)
select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv;
                        QUERY PLAN                        
----------------------------------------------------------
 Merge Join
   Merge Cond: (a.idv = b.idv)
   ->  Index Only Scan using tidv_idv_idx on tidv a
   ->  Materialize
         ->  Index Only Scan using tidv_idv_idx on tidv b
(5 rows)

set enable_mergejoin = 0;
set enable_hashjoin = 0;
explain (costs off)
select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv;
                     QUERY PLAN                     
----------------------------------------------------
 Nested Loop
   ->  Seq Scan on tidv a
   ->  Index Only Scan using tidv_idv_idx on tidv b
         Index Cond: (idv = a.idv)
(4 rows)

rollback;
--
-- test NULL behavior of whole-row Vars, per bug #5025
--
select t1.q2, count(t2.*)
from int8_tbl t1 left join int8_tbl t2 on (t1.q2 = t2.q1)
group by t1.q2 order by 1;
        q2         | count 
-------------------+-------
 -4567890123456789 |     0
               123 |     2
               456 |     0
  4567890123456789 |     6
(4 rows)

select t1.q2, count(t2.*)
from int8_tbl t1 left join (select * from int8_tbl) t2 on (t1.q2 = t2.q1)
group by t1.q2 order by 1;
        q2         | count 
-------------------+-------
 -4567890123456789 |     0
               123 |     2
               456 |     0
  4567890123456789 |     6
(4 rows)

select t1.q2, count(t2.*)
from int8_tbl t1 left join (select * from int8_tbl offset 0) t2 on (t1.q2 = t2.q1)
group by t1.q2 order by 1;
        q2         | count 
-------------------+-------
 -4567890123456789 |     0
               123 |     2
               456 |     0
  4567890123456789 |     6
(4 rows)

select t1.q2, count(t2.*)
from int8_tbl t1 left join
  (select q1, case when q2=1 then 1 else q2 end as q2 from int8_tbl) t2
  on (t1.q2 = t2.q1)
group by t1.q2 order by 1;
        q2         | count 
-------------------+-------
 -4567890123456789 |     0
               123 |     2
               456 |     0
  4567890123456789 |     6
(4 rows)

--
-- test incorrect failure to NULL pulled-up subexpressions
--
begin;
create temp table a (
     code char not null,
     constraint a_pk primary key (code)
);
create temp table b (
     a char not null,
     num integer not null,
     constraint b_pk primary key (a, num)
);
create temp table c (
     name char not null,
     a char,
     constraint c_pk primary key (name)
);
insert into a (code) values ('p');
insert into a (code) values ('q');
insert into b (a, num) values ('p', 1);
insert into b (a, num) values ('p', 2);
insert into c (name, a) values ('A', 'p');
insert into c (name, a) values ('B', 'q');
insert into c (name, a) values ('C', null);
select c.name, ss.code, ss.b_cnt, ss.const
from c left join
  (select a.code, coalesce(b_grp.cnt, 0) as b_cnt, -1 as const
   from a left join
     (select count(1) as cnt, b.a from b group by b.a) as b_grp
     on a.code = b_grp.a
  ) as ss
  on (c.a = ss.code)
order by c.name;
 name | code | b_cnt | const 
------+------+-------+-------
 A    | p    |     2 |    -1
 B    | q    |     0 |    -1
 C    |      |       |      
(3 rows)

rollback;
--
-- test incorrect handling of placeholders that only appear in targetlists,
-- per bug #6154
--
SELECT * FROM
( SELECT 1 as key1 ) sub1
LEFT JOIN
( SELECT sub3.key3, sub4.value2, COALESCE(sub4.value2, 66) as value3 FROM
    ( SELECT 1 as key3 ) sub3
    LEFT JOIN
    ( SELECT sub5.key5, COALESCE(sub6.value1, 1) as value2 FROM
        ( SELECT 1 as key5 ) sub5
        LEFT JOIN
        ( SELECT 2 as key6, 42 as value1 ) sub6
        ON sub5.key5 = sub6.key6
    ) sub4
    ON sub4.key5 = sub3.key3
) sub2
ON sub1.key1 = sub2.key3;
 key1 | key3 | value2 | value3 
------+------+--------+--------
    1 |    1 |      1 |      1
(1 row)

-- test the path using join aliases, too
SELECT * FROM
( SELECT 1 as key1 ) sub1
LEFT JOIN
( SELECT sub3.key3, value2, COALESCE(value2, 66) as value3 FROM
    ( SELECT 1 as key3 ) sub3
    LEFT JOIN
    ( SELECT sub5.key5, COALESCE(sub6.value1, 1) as value2 FROM
        ( SELECT 1 as key5 ) sub5
        LEFT JOIN
        ( SELECT 2 as key6, 42 as value1 ) sub6
        ON sub5.key5 = sub6.key6
    ) sub4
    ON sub4.key5 = sub3.key3
) sub2
ON sub1.key1 = sub2.key3;
 key1 | key3 | value2 | value3 
------+------+--------+--------
    1 |    1 |      1 |      1
(1 row)

--
-- test case where a PlaceHolderVar is used as a nestloop parameter
--
EXPLAIN (COSTS OFF)
SELECT qq, unique1
  FROM
  ( SELECT COALESCE(q1, 0) AS qq FROM int8_tbl a ) AS ss1
  FULL OUTER JOIN
  ( SELECT COALESCE(q2, -1) AS qq FROM int8_tbl b ) AS ss2
  USING (qq)
  INNER JOIN tenk1 c ON qq = unique2;
                                               QUERY PLAN                                                
---------------------------------------------------------------------------------------------------------
 Nested Loop
   ->  Hash Full Join
         Hash Cond: ((COALESCE(a.q1, '0'::bigint)) = (COALESCE(b.q2, '-1'::bigint)))
         ->  Seq Scan on int8_tbl a
         ->  Hash
               ->  Seq Scan on int8_tbl b
   ->  Index Scan using tenk1_unique2 on tenk1 c
         Index Cond: (unique2 = COALESCE((COALESCE(a.q1, '0'::bigint)), (COALESCE(b.q2, '-1'::bigint))))
(8 rows)

SELECT qq, unique1
  FROM
  ( SELECT COALESCE(q1, 0) AS qq FROM int8_tbl a ) AS ss1
  FULL OUTER JOIN
  ( SELECT COALESCE(q2, -1) AS qq FROM int8_tbl b ) AS ss2
  USING (qq)
  INNER JOIN tenk1 c ON qq = unique2;
 qq  | unique1 
-----+---------
 123 |    4596
 123 |    4596
 456 |    7318
(3 rows)

--
-- nested nestloops can require nested PlaceHolderVars
--
create temp table nt1 (
  id int primary key,
  a1 boolean,
  a2 boolean
);
create temp table nt2 (
  id int primary key,
  nt1_id int,
  b1 boolean,
  b2 boolean,
  foreign key (nt1_id) references nt1(id)
);
create temp table nt3 (
  id int primary key,
  nt2_id int,
  c1 boolean,
  foreign key (nt2_id) references nt2(id)
);
insert into nt1 values (1,true,true);
insert into nt1 values (2,true,false);
insert into nt1 values (3,false,false);
insert into nt2 values (1,1,true,true);
insert into nt2 values (2,2,true,false);
insert into nt2 values (3,3,false,false);
insert into nt3 values (1,1,true);
insert into nt3 values (2,2,false);
insert into nt3 values (3,3,true);
explain (costs off)
select nt3.id
from nt3 as nt3
  left join
    (select nt2.*, (nt2.b1 and ss1.a3) AS b3
     from nt2 as nt2
       left join
         (select nt1.*, (nt1.id is not null) as a3 from nt1) as ss1
         on ss1.id = nt2.nt1_id
    ) as ss2
    on ss2.id = nt3.nt2_id
where nt3.id = 1 and ss2.b3;
                  QUERY PLAN                   
-----------------------------------------------
 Nested Loop
   ->  Nested Loop
         ->  Index Scan using nt3_pkey on nt3
               Index Cond: (id = 1)
         ->  Index Scan using nt2_pkey on nt2
               Index Cond: (id = nt3.nt2_id)
   ->  Index Only Scan using nt1_pkey on nt1
         Index Cond: (id = nt2.nt1_id)
         Filter: (nt2.b1 AND (id IS NOT NULL))
(9 rows)

select nt3.id
from nt3 as nt3
  left join
    (select nt2.*, (nt2.b1 and ss1.a3) AS b3
     from nt2 as nt2
       left join
         (select nt1.*, (nt1.id is not null) as a3 from nt1) as ss1
         on ss1.id = nt2.nt1_id
    ) as ss2
    on ss2.id = nt3.nt2_id
where nt3.id = 1 and ss2.b3;
 id 
----
  1
(1 row)

--
-- test case where a PlaceHolderVar is propagated into a subquery
--
explain (costs off)
select * from
  int8_tbl t1 left join
  (select q1 as x, 42 as y from int8_tbl t2) ss
  on t1.q2 = ss.x
where
  1 = (select 1 from int8_tbl t3 where ss.y is not null limit 1)
order by 1,2;
                        QUERY PLAN                         
-----------------------------------------------------------
 Sort
   Sort Key: t1.q1, t1.q2
   ->  Hash Left Join
         Hash Cond: (t1.q2 = t2.q1)
         Filter: (1 = (SubPlan 1))
         ->  Seq Scan on int8_tbl t1
         ->  Hash
               ->  Seq Scan on int8_tbl t2
         SubPlan 1
           ->  Limit
                 ->  Result
                       One-Time Filter: ((42) IS NOT NULL)
                       ->  Seq Scan on int8_tbl t3
(13 rows)

select * from
  int8_tbl t1 left join
  (select q1 as x, 42 as y from int8_tbl t2) ss
  on t1.q2 = ss.x
where
  1 = (select 1 from int8_tbl t3 where ss.y is not null limit 1)
order by 1,2;
        q1        |        q2        |        x         | y  
------------------+------------------+------------------+----
              123 | 4567890123456789 | 4567890123456789 | 42
              123 | 4567890123456789 | 4567890123456789 | 42
              123 | 4567890123456789 | 4567890123456789 | 42
 4567890123456789 |              123 |              123 | 42
 4567890123456789 |              123 |              123 | 42
 4567890123456789 | 4567890123456789 | 4567890123456789 | 42
 4567890123456789 | 4567890123456789 | 4567890123456789 | 42
 4567890123456789 | 4567890123456789 | 4567890123456789 | 42
(8 rows)

--
-- variant where a PlaceHolderVar is needed at a join, but not above the join
--
explain (costs off)
select * from
  int4_tbl as i41,
  lateral
    (select 1 as x from
      (select i41.f1 as lat,
              i42.f1 as loc from
         int8_tbl as i81, int4_tbl as i42) as ss1
      right join int4_tbl as i43 on (i43.f1 > 1)
      where ss1.loc = ss1.lat) as ss2
where i41.f1 > 0;
                    QUERY PLAN                    
--------------------------------------------------
 Nested Loop
   ->  Nested Loop
         ->  Seq Scan on int4_tbl i41
               Filter: (f1 > 0)
         ->  Nested Loop
               Join Filter: (i42.f1 = i41.f1)
               ->  Seq Scan on int8_tbl i81
               ->  Materialize
                     ->  Seq Scan on int4_tbl i42
   ->  Materialize
         ->  Seq Scan on int4_tbl i43
               Filter: (f1 > 1)
(12 rows)

select * from
  int4_tbl as i41,
  lateral
    (select 1 as x from
      (select i41.f1 as lat,
              i42.f1 as loc from
         int8_tbl as i81, int4_tbl as i42) as ss1
      right join int4_tbl as i43 on (i43.f1 > 1)
      where ss1.loc = ss1.lat) as ss2
where i41.f1 > 0;
     f1     | x 
------------+---
     123456 | 1
     123456 | 1
     123456 | 1
     123456 | 1
     123456 | 1
     123456 | 1
     123456 | 1
     123456 | 1
     123456 | 1
     123456 | 1
 2147483647 | 1
 2147483647 | 1
 2147483647 | 1
 2147483647 | 1
 2147483647 | 1
 2147483647 | 1
 2147483647 | 1
 2147483647 | 1
 2147483647 | 1
 2147483647 | 1
(20 rows)

--
-- test the corner cases FULL JOIN ON TRUE and FULL JOIN ON FALSE
--
select * from int4_tbl a full join int4_tbl b on true;
     f1      |     f1      
-------------+-------------
           0 |           0
           0 |      123456
           0 |     -123456
           0 |  2147483647
           0 | -2147483647
      123456 |           0
      123456 |      123456
      123456 |     -123456
      123456 |  2147483647
      123456 | -2147483647
     -123456 |           0
     -123456 |      123456
     -123456 |     -123456
     -123456 |  2147483647
     -123456 | -2147483647
  2147483647 |           0
  2147483647 |      123456
  2147483647 |     -123456
  2147483647 |  2147483647
  2147483647 | -2147483647
 -2147483647 |           0
 -2147483647 |      123456
 -2147483647 |     -123456
 -2147483647 |  2147483647
 -2147483647 | -2147483647
(25 rows)

select * from int4_tbl a full join int4_tbl b on false;
     f1      |     f1      
-------------+-------------
             |           0
             |      123456
             |     -123456
             |  2147483647
             | -2147483647
           0 |            
      123456 |            
     -123456 |            
  2147483647 |            
 -2147483647 |            
(10 rows)

--
-- test for ability to use a cartesian join when necessary
--
create temp table q1 as select 1 as q1;
create temp table q2 as select 0 as q2;
analyze q1;
analyze q2;
explain (costs off)
select * from
  tenk1 join int4_tbl on f1 = twothousand,
  q1, q2
where q1 = thousand or q2 = thousand;
                               QUERY PLAN                               
------------------------------------------------------------------------
 Hash Join
   Hash Cond: (tenk1.twothousand = int4_tbl.f1)
   ->  Nested Loop
         ->  Nested Loop
               ->  Seq Scan on q1
               ->  Seq Scan on q2
         ->  Bitmap Heap Scan on tenk1
               Recheck Cond: ((q1.q1 = thousand) OR (q2.q2 = thousand))
               ->  Bitmap Index Scan on tenk1_thous_tenthous
                     Index Cond: (thousand = ANY (ARRAY[q1.q1, q2.q2]))
   ->  Hash
         ->  Seq Scan on int4_tbl
(12 rows)

explain (costs off)
select * from
  tenk1 join int4_tbl on f1 = twothousand,
  q1, q2
where thousand = (q1 + q2);
                          QUERY PLAN                          
--------------------------------------------------------------
 Hash Join
   Hash Cond: (tenk1.twothousand = int4_tbl.f1)
   ->  Nested Loop
         ->  Nested Loop
               ->  Seq Scan on q1
               ->  Seq Scan on q2
         ->  Bitmap Heap Scan on tenk1
               Recheck Cond: (thousand = (q1.q1 + q2.q2))
               ->  Bitmap Index Scan on tenk1_thous_tenthous
                     Index Cond: (thousand = (q1.q1 + q2.q2))
   ->  Hash
         ->  Seq Scan on int4_tbl
(12 rows)

--
-- test ability to generate a suitable plan for a star-schema query
--
explain (costs off)
select * from
  tenk1, int8_tbl a, int8_tbl b
where thousand = a.q1 and tenthous = b.q1 and a.q2 = 1 and b.q2 = 2;
                             QUERY PLAN                              
---------------------------------------------------------------------
 Nested Loop
   ->  Seq Scan on int8_tbl b
         Filter: (q2 = 2)
   ->  Nested Loop
         ->  Seq Scan on int8_tbl a
               Filter: (q2 = 1)
         ->  Index Scan using tenk1_thous_tenthous on tenk1
               Index Cond: ((thousand = a.q1) AND (tenthous = b.q1))
(8 rows)

--
-- test a corner case in which we shouldn't apply the star-schema optimization
--
explain (costs off)
select t1.unique2, t1.stringu1, t2.unique1, t2.stringu2 from
  tenk1 t1
  inner join int4_tbl i1
    left join (select v1.x2, v2.y1, 11 AS d1
               from (select 1,0 from onerow) v1(x1,x2)
               left join (select 3,1 from onerow) v2(y1,y2)
               on v1.x1 = v2.y2) subq1
    on (i1.f1 = subq1.x2)
  on (t1.unique2 = subq1.d1)
  left join tenk1 t2
  on (subq1.y1 = t2.unique1)
where t1.unique2 < 42 and t1.stringu1 > t2.stringu2;
                              QUERY PLAN                               
-----------------------------------------------------------------------
 Nested Loop
   ->  Nested Loop
         Join Filter: (t1.stringu1 > t2.stringu2)
         ->  Nested Loop
               ->  Nested Loop
                     ->  Seq Scan on onerow
                     ->  Seq Scan on onerow onerow_1
               ->  Index Scan using tenk1_unique2 on tenk1 t1
                     Index Cond: ((unique2 = (11)) AND (unique2 < 42))
         ->  Index Scan using tenk1_unique1 on tenk1 t2
               Index Cond: (unique1 = (3))
   ->  Seq Scan on int4_tbl i1
         Filter: (f1 = 0)
(13 rows)

select t1.unique2, t1.stringu1, t2.unique1, t2.stringu2 from
  tenk1 t1
  inner join int4_tbl i1
    left join (select v1.x2, v2.y1, 11 AS d1
               from (select 1,0 from onerow) v1(x1,x2)
               left join (select 3,1 from onerow) v2(y1,y2)
               on v1.x1 = v2.y2) subq1
    on (i1.f1 = subq1.x2)
  on (t1.unique2 = subq1.d1)
  left join tenk1 t2
  on (subq1.y1 = t2.unique1)
where t1.unique2 < 42 and t1.stringu1 > t2.stringu2;
 unique2 | stringu1 | unique1 | stringu2 
---------+----------+---------+----------
      11 | WFAAAA   |       3 | LKIAAA
(1 row)

-- variant that isn't quite a star-schema case
explain (verbose, costs off)
select ss1.d1 from
  tenk1 as t1
  inner join tenk1 as t2
  on t1.tenthous = t2.ten
  inner join
    int8_tbl as i8
    left join int4_tbl as i4
      inner join (select 64::information_schema.cardinal_number as d1
                  from tenk1 t3,
                       lateral (select abs(t3.unique1) + random()) ss0(x)
                  where t3.fivethous < 0) as ss1
      on i4.f1 = ss1.d1
    on i8.q1 = i4.f1
  on t1.tenthous = ss1.d1
where t1.unique1 < i4.f1;
                                                                                                             QUERY PLAN                                                                                                              
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop
   Output: (64)::information_schema.cardinal_number
   Join Filter: (t1.tenthous = ((64)::information_schema.cardinal_number)::integer)
   ->  Seq Scan on public.tenk1 t3
         Output: t3.unique1, t3.unique2, t3.two, t3.four, t3.ten, t3.twenty, t3.hundred, t3.thousand, t3.twothousand, t3.fivethous, t3.tenthous, t3.odd, t3.even, t3.stringu1, t3.stringu2, t3.string4
         Filter: (t3.fivethous < 0)
   ->  Nested Loop
         Output: t1.tenthous, t2.ten
         ->  Nested Loop
               Output: t1.tenthous, t2.ten, i4.f1
               Join Filter: (t1.unique1 < i4.f1)
               ->  Hash Join
                     Output: t1.tenthous, t1.unique1, t2.ten
                     Hash Cond: (t2.ten = t1.tenthous)
                     ->  Seq Scan on public.tenk1 t2
                           Output: t2.unique1, t2.unique2, t2.two, t2.four, t2.ten, t2.twenty, t2.hundred, t2.thousand, t2.twothousand, t2.fivethous, t2.tenthous, t2.odd, t2.even, t2.stringu1, t2.stringu2, t2.string4
                     ->  Hash
                           Output: t1.tenthous, t1.unique1
                           ->  Nested Loop
                                 Output: t1.tenthous, t1.unique1
                                 ->  Subquery Scan on ss0
                                       Output: ss0.x, (64)::information_schema.cardinal_number
                                       ->  Result
                                             Output: ((abs(t3.unique1))::double precision + random())
                                 ->  Index Scan using tenk1_thous_tenthous on public.tenk1 t1
                                       Output: t1.unique1, t1.unique2, t1.two, t1.four, t1.ten, t1.twenty, t1.hundred, t1.thousand, t1.twothousand, t1.fivethous, t1.tenthous, t1.odd, t1.even, t1.stringu1, t1.stringu2, t1.string4
                                       Index Cond: (t1.tenthous = (((64)::information_schema.cardinal_number))::integer)
               ->  Seq Scan on public.int4_tbl i4
                     Output: i4.f1
                     Filter: (i4.f1 = ((64)::information_schema.cardinal_number)::integer)
         ->  Seq Scan on public.int8_tbl i8
               Output: i8.q1, i8.q2
               Filter: (i8.q1 = ((64)::information_schema.cardinal_number)::integer)
(33 rows)

select ss1.d1 from
  tenk1 as t1
  inner join tenk1 as t2
  on t1.tenthous = t2.ten
  inner join
    int8_tbl as i8
    left join int4_tbl as i4
      inner join (select 64::information_schema.cardinal_number as d1
                  from tenk1 t3,
                       lateral (select abs(t3.unique1) + random()) ss0(x)
                  where t3.fivethous < 0) as ss1
      on i4.f1 = ss1.d1
    on i8.q1 = i4.f1
  on t1.tenthous = ss1.d1
where t1.unique1 < i4.f1;
 d1 
----
(0 rows)

-- this variant is foldable by the remove-useless-RESULT-RTEs code
explain (costs off)
select t1.unique2, t1.stringu1, t2.unique1, t2.stringu2 from
  tenk1 t1
  inner join int4_tbl i1
    left join (select v1.x2, v2.y1, 11 AS d1
               from (values(1,0)) v1(x1,x2)
               left join (values(3,1)) v2(y1,y2)
               on v1.x1 = v2.y2) subq1
    on (i1.f1 = subq1.x2)
  on (t1.unique2 = subq1.d1)
  left join tenk1 t2
  on (subq1.y1 = t2.unique1)
where t1.unique2 < 42 and t1.stringu1 > t2.stringu2;
                           QUERY PLAN                            
-----------------------------------------------------------------
 Nested Loop
   Join Filter: (t1.stringu1 > t2.stringu2)
   ->  Nested Loop
         ->  Seq Scan on int4_tbl i1
               Filter: (f1 = 0)
         ->  Index Scan using tenk1_unique2 on tenk1 t1
               Index Cond: ((unique2 = (11)) AND (unique2 < 42))
   ->  Index Scan using tenk1_unique1 on tenk1 t2
         Index Cond: (unique1 = (3))
(9 rows)

select t1.unique2, t1.stringu1, t2.unique1, t2.stringu2 from
  tenk1 t1
  inner join int4_tbl i1
    left join (select v1.x2, v2.y1, 11 AS d1
               from (values(1,0)) v1(x1,x2)
               left join (values(3,1)) v2(y1,y2)
               on v1.x1 = v2.y2) subq1
    on (i1.f1 = subq1.x2)
  on (t1.unique2 = subq1.d1)
  left join tenk1 t2
  on (subq1.y1 = t2.unique1)
where t1.unique2 < 42 and t1.stringu1 > t2.stringu2;
 unique2 | stringu1 | unique1 | stringu2 
---------+----------+---------+----------
      11 | WFAAAA   |       3 | LKIAAA
(1 row)

-- Here's a variant that we can't fold too aggressively, though,
-- or we end up with noplace to evaluate the lateral PHV
explain (verbose, costs off)
select * from
  (select 1 as x) ss1 left join (select 2 as y) ss2 on (true),
  lateral (select ss2.y as z limit 1) ss3;
        QUERY PLAN         
---------------------------
 Nested Loop
   Output: 1, (2), ((2))
   ->  Result
         Output: 2
   ->  Limit
         Output: ((2))
         ->  Result
               Output: (2)
(8 rows)

select * from
  (select 1 as x) ss1 left join (select 2 as y) ss2 on (true),
  lateral (select ss2.y as z limit 1) ss3;
 x | y | z 
---+---+---
 1 | 2 | 2
(1 row)

-- This example demonstrates the folly of our old "have_dangerous_phv" logic
begin;
set local from_collapse_limit to 2;
explain (verbose, costs off)
select * from int8_tbl t1
  left join
    (select coalesce(t2.q1 + x, 0) from int8_tbl t2,
       lateral (select t3.q1 as x from int8_tbl t3,
                  lateral (select t2.q1, t3.q1 offset 0) s))
  on true;
                            QUERY PLAN                            
------------------------------------------------------------------
 Nested Loop Left Join
   Output: t1.q1, t1.q2, (COALESCE((t2.q1 + t3.q1), '0'::bigint))
   ->  Seq Scan on public.int8_tbl t1
         Output: t1.q1, t1.q2
   ->  Materialize
         Output: (COALESCE((t2.q1 + t3.q1), '0'::bigint))
         ->  Nested Loop
               Output: COALESCE((t2.q1 + t3.q1), '0'::bigint)
               ->  Seq Scan on public.int8_tbl t2
                     Output: t2.q1, t2.q2
               ->  Nested Loop
                     Output: t3.q1
                     ->  Seq Scan on public.int8_tbl t3
                           Output: t3.q1, t3.q2
                     ->  Result
                           Output: NULL::bigint, NULL::bigint
(16 rows)

rollback;
-- ... not that the initial replacement didn't have some bugs too
begin;
create temp table t(i int primary key);
explain (verbose, costs off)
select * from t t1
    left join (select 1 as x, * from t t2(i2)) t2ss on t1.i = t2ss.i2
    left join t t3(i3) on false
    left join t t4(i4) on t4.i4 > t2ss.x;
                        QUERY PLAN                        
----------------------------------------------------------
 Nested Loop Left Join
   Output: t1.i, (1), t2.i2, i3, t4.i4
   ->  Nested Loop Left Join
         Output: t1.i, t2.i2, (1), i3
         Join Filter: false
         ->  Hash Left Join
               Output: t1.i, t2.i2, (1)
               Inner Unique: true
               Hash Cond: (t1.i = t2.i2)
               ->  Seq Scan on pg_temp.t t1
                     Output: t1.i
               ->  Hash
                     Output: t2.i2, (1)
                     ->  Seq Scan on pg_temp.t t2
                           Output: t2.i2, 1
         ->  Result
               Output: i3
               One-Time Filter: false
   ->  Memoize
         Output: t4.i4
         Cache Key: (1)
         Cache Mode: binary
         ->  Index Only Scan using t_pkey on pg_temp.t t4
               Output: t4.i4
               Index Cond: (t4.i4 > (1))
(25 rows)

explain (verbose, costs off)
select * from
     (select k from
         (select i, coalesce(i, j) as k from
             (select i from t union all select 0)
             join (select 1 as j limit 1) on i = j)
         right join (select 2 as x) on true
         join (select 3 as y) on i is not null
     ),
     lateral (select k as kl limit 1);
                            QUERY PLAN                             
-------------------------------------------------------------------
 Nested Loop
   Output: COALESCE(t.i, (1)), ((COALESCE(t.i, (1))))
   ->  Limit
         Output: 1
         ->  Result
               Output: 1
   ->  Nested Loop
         Output: t.i, ((COALESCE(t.i, (1))))
         ->  Result
               Output: t.i, COALESCE(t.i, (1))
               ->  Append
                     ->  Index Only Scan using t_pkey on pg_temp.t
                           Output: t.i
                           Index Cond: (t.i = (1))
                     ->  Result
                           Output: 0
                           One-Time Filter: ((1) = 0)
         ->  Limit
               Output: ((COALESCE(t.i, (1))))
               ->  Result
                     Output: (COALESCE(t.i, (1)))
(21 rows)

rollback;
-- PHVs containing SubLinks are quite tricky to get right
explain (verbose, costs off)
select *
from int8_tbl i8
  inner join
    (select (select true) as x
       from int4_tbl i4, lateral (select i4.f1 as y limit 1) ss1
       where i4.f1 = 0) ss2 on true
  right join (select false as z) ss3 on true,
  lateral (select i8.q2 as q2l where x limit 1) ss4
where i8.q2 = 123;
                           QUERY PLAN                           
----------------------------------------------------------------
 Nested Loop
   Output: i8.q1, i8.q2, (InitPlan 1).col1, false, (i8.q2)
   InitPlan 1
     ->  Result
           Output: true
   InitPlan 2
     ->  Result
           Output: true
   ->  Seq Scan on public.int4_tbl i4
         Output: i4.f1
         Filter: (i4.f1 = 0)
   ->  Nested Loop
         Output: i8.q1, i8.q2, (i8.q2)
         ->  Subquery Scan on ss1
               Output: ss1.y, (InitPlan 1).col1
               ->  Limit
                     Output: NULL::integer
                     ->  Result
                           Output: NULL::integer
         ->  Nested Loop
               Output: i8.q1, i8.q2, (i8.q2)
               ->  Seq Scan on public.int8_tbl i8
                     Output: i8.q1, i8.q2
                     Filter: (i8.q2 = 123)
               ->  Limit
                     Output: (i8.q2)
                     ->  Result
                           Output: i8.q2
                           One-Time Filter: ((InitPlan 1).col1)
(29 rows)

explain (verbose, costs off)
select *
from int8_tbl i8
  inner join
    (select (select true) as x
       from int4_tbl i4, lateral (select 1 as y limit 1) ss1
       where i4.f1 = 0) ss2 on true
  right join (select false as z) ss3 on true,
  lateral (select i8.q2 as q2l where x limit 1) ss4
where i8.q2 = 123;
                           QUERY PLAN                           
----------------------------------------------------------------
 Nested Loop
   Output: i8.q1, i8.q2, (InitPlan 1).col1, false, (i8.q2)
   InitPlan 1
     ->  Result
           Output: true
   InitPlan 2
     ->  Result
           Output: true
   ->  Limit
         Output: NULL::integer
         ->  Result
               Output: NULL::integer
   ->  Nested Loop
         Output: i8.q1, i8.q2, (i8.q2)
         ->  Seq Scan on public.int4_tbl i4
               Output: i4.f1, (InitPlan 1).col1
               Filter: (i4.f1 = 0)
         ->  Nested Loop
               Output: i8.q1, i8.q2, (i8.q2)
               ->  Seq Scan on public.int8_tbl i8
                     Output: i8.q1, i8.q2
                     Filter: (i8.q2 = 123)
               ->  Limit
                     Output: (i8.q2)
                     ->  Result
                           Output: i8.q2
                           One-Time Filter: ((InitPlan 1).col1)
(27 rows)

-- Test proper handling of appendrel PHVs during useless-RTE removal
explain (costs off)
select * from
  (select 0 as z) as t1
  left join
  (select true as a) as t2
  on true,
  lateral (select true as b
           union all
           select a as b) as t3
where b;
              QUERY PLAN               
---------------------------------------
 Nested Loop
   ->  Result
   ->  Append
         ->  Result
         ->  Result
               One-Time Filter: (true)
(6 rows)

select * from
  (select 0 as z) as t1
  left join
  (select true as a) as t2
  on true,
  lateral (select true as b
           union all
           select a as b) as t3
where b;
 z | a | b 
---+---+---
 0 | t | t
 0 | t | t
(2 rows)

-- Test PHV in a semijoin qual, which confused useless-RTE removal (bug #17700)
explain (verbose, costs off)
with ctetable as not materialized ( select 1 as f1 )
select * from ctetable c1
where f1 in ( select c3.f1 from ctetable c2 full join ctetable c3 on true );
         QUERY PLAN         
----------------------------
 Result
   Output: 1
   One-Time Filter: (1 = 1)
(3 rows)

with ctetable as not materialized ( select 1 as f1 )
select * from ctetable c1
where f1 in ( select c3.f1 from ctetable c2 full join ctetable c3 on true );
 f1 
----
  1
(1 row)

-- Test PHV that winds up in a Result node, despite having nonempty nullingrels
explain (verbose, costs off)
select table_catalog, table_name
from int4_tbl t1
  inner join (int8_tbl t2
              left join information_schema.column_udt_usage on null)
  on null;
                                                    QUERY PLAN                                                     
-------------------------------------------------------------------------------------------------------------------
 Result
   Output: (current_database())::information_schema.sql_identifier, (c.relname)::information_schema.sql_identifier
   One-Time Filter: false
(3 rows)

-- Test handling of qual pushdown to appendrel members with non-Var outputs
explain (verbose, costs off)
select * from int4_tbl left join (
  select text 'foo' union all select text 'bar'
) ss(x) on true
where ss.x is null;
               QUERY PLAN                
-----------------------------------------
 Nested Loop Left Join
   Output: int4_tbl.f1, ('foo'::text)
   Filter: (('foo'::text) IS NULL)
   ->  Seq Scan on public.int4_tbl
         Output: int4_tbl.f1
   ->  Materialize
         Output: ('foo'::text)
         ->  Append
               ->  Result
                     Output: 'foo'::text
               ->  Result
                     Output: 'bar'::text
(12 rows)

-- Test computation of varnullingrels when translating appendrel Var
begin;
create temp table t_append (a int not null, b int);
insert into t_append values (11);
insert into t_append values (23);
explain (verbose, costs off)
select t1.a, s.a from t_append t1
  left join t_append t2 on t1.a = t2.b
  join lateral (
    select t1.a as a union all select t2.a as a
  ) s on true
where s.a is not null;
                    QUERY PLAN                     
---------------------------------------------------
 Nested Loop
   Output: t1.a, (t1.a)
   ->  Merge Left Join
         Output: t1.a, t2.a
         Merge Cond: (t1.a = t2.b)
         ->  Sort
               Output: t1.a
               Sort Key: t1.a
               ->  Seq Scan on pg_temp.t_append t1
                     Output: t1.a
         ->  Sort
               Output: t2.a, t2.b
               Sort Key: t2.b
               ->  Seq Scan on pg_temp.t_append t2
                     Output: t2.a, t2.b
   ->  Append
         ->  Result
               Output: t1.a
         ->  Result
               Output: t2.a
               One-Time Filter: (t2.a IS NOT NULL)
(21 rows)

select t1.a, s.a from t_append t1
  left join t_append t2 on t1.a = t2.b
  join lateral (
    select t1.a as a union all select t2.a as a
  ) s on true
where s.a is not null;
 a | a 
---+---
 1 | 1
 1 | 1
 2 | 2
(3 rows)

rollback;
--
-- test inlining of immutable functions
--
create function f_immutable_int4(i integer) returns integer as
$$ begin return i; end; $$ language plpgsql immutable;
-- check optimization of function scan with join
explain (costs off)
select unique1 from tenk1, (select * from f_immutable_int4(1) x) x
where x = unique1;
                  QUERY PLAN                  
----------------------------------------------
 Index Only Scan using tenk1_unique1 on tenk1
   Index Cond: (unique1 = 1)
(2 rows)

explain (verbose, costs off)
select unique1, x.*
from tenk1, (select *, random() from f_immutable_int4(1) x) x
where x = unique1;
                        QUERY PLAN                         
-----------------------------------------------------------
 Nested Loop
   Output: tenk1.unique1, (1), (random())
   ->  Result
         Output: 1, random()
   ->  Index Only Scan using tenk1_unique1 on public.tenk1
         Output: tenk1.unique1
         Index Cond: (tenk1.unique1 = (1))
(7 rows)

explain (costs off)
select unique1 from tenk1, f_immutable_int4(1) x where x = unique1;
                  QUERY PLAN                  
----------------------------------------------
 Index Only Scan using tenk1_unique1 on tenk1
   Index Cond: (unique1 = 1)
(2 rows)

explain (costs off)
select unique1 from tenk1, lateral f_immutable_int4(1) x where x = unique1;
                  QUERY PLAN                  
----------------------------------------------
 Index Only Scan using tenk1_unique1 on tenk1
   Index Cond: (unique1 = 1)
(2 rows)

explain (costs off)
select unique1 from tenk1, lateral f_immutable_int4(1) x where x in (select 17);
        QUERY PLAN        
--------------------------
 Result
   One-Time Filter: false
(2 rows)

explain (costs off)
select unique1, x from tenk1 join f_immutable_int4(1) x on unique1 = x;
                  QUERY PLAN                  
----------------------------------------------
 Index Only Scan using tenk1_unique1 on tenk1
   Index Cond: (unique1 = 1)
(2 rows)

explain (costs off)
select unique1, x from tenk1 left join f_immutable_int4(1) x on unique1 = x;
                     QUERY PLAN                     
----------------------------------------------------
 Nested Loop Left Join
   Join Filter: (tenk1.unique1 = 1)
   ->  Index Only Scan using tenk1_unique1 on tenk1
   ->  Materialize
         ->  Result
(5 rows)

explain (costs off)
select unique1, x from tenk1 right join f_immutable_int4(1) x on unique1 = x;
                     QUERY PLAN                     
----------------------------------------------------
 Nested Loop Left Join
   ->  Result
   ->  Index Only Scan using tenk1_unique1 on tenk1
         Index Cond: (unique1 = 1)
(4 rows)

explain (costs off)
select unique1, x from tenk1 full join f_immutable_int4(1) x on unique1 = x;
                     QUERY PLAN                     
----------------------------------------------------
 Merge Full Join
   Merge Cond: (tenk1.unique1 = (1))
   ->  Index Only Scan using tenk1_unique1 on tenk1
   ->  Sort
         Sort Key: (1)
         ->  Result
(6 rows)

-- check that pullup of a const function allows further const-folding
explain (costs off)
select unique1 from tenk1, f_immutable_int4(1) x where x = 42;
        QUERY PLAN        
--------------------------
 Result
   One-Time Filter: false
(2 rows)

-- test inlining of immutable functions with PlaceHolderVars
explain (costs off)
select nt3.id
from nt3 as nt3
  left join
    (select nt2.*, (nt2.b1 or i4 = 42) AS b3
     from nt2 as nt2
       left join
         f_immutable_int4(0) i4
         on i4 = nt2.nt1_id
    ) as ss2
    on ss2.id = nt3.nt2_id
where nt3.id = 1 and ss2.b3;
                  QUERY PLAN                  
----------------------------------------------
 Nested Loop Left Join
   Filter: ((nt2.b1 OR ((0) = 42)))
   ->  Index Scan using nt3_pkey on nt3
         Index Cond: (id = 1)
   ->  Nested Loop Left Join
         Join Filter: (0 = nt2.nt1_id)
         ->  Index Scan using nt2_pkey on nt2
               Index Cond: (id = nt3.nt2_id)
         ->  Result
(9 rows)

drop function f_immutable_int4(int);
-- test inlining when function returns composite
create function mki8(bigint, bigint) returns int8_tbl as
$$select row($1,$2)::int8_tbl$$ language sql;
create function mki4(int) returns int4_tbl as
$$select row($1)::int4_tbl$$ language sql;
explain (verbose, costs off)
select * from mki8(1,2);
             QUERY PLAN             
------------------------------------
 Function Scan on mki8
   Output: q1, q2
   Function Call: '(1,2)'::int8_tbl
(3 rows)

select * from mki8(1,2);
 q1 | q2 
----+----
  1 |  2
(1 row)

explain (verbose, costs off)
select * from mki4(42);
            QUERY PLAN             
-----------------------------------
 Function Scan on mki4
   Output: f1
   Function Call: '(42)'::int4_tbl
(3 rows)

select * from mki4(42);
 f1 
----
 42
(1 row)

drop function mki8(bigint, bigint);
drop function mki4(int);
-- test const-folding of a whole-row Var into a per-field Var
-- (need to inline a function to reach this case, else parser does it)
create function f_field_select(t onek) returns int4 as
$$ select t.unique2; $$ language sql immutable;
explain (verbose, costs off)
select (t2.*).unique1, f_field_select(t2) from tenk1 t1
    left join onek t2 on t1.unique1 = t2.unique1
    left join int8_tbl t3 on true;
                             QUERY PLAN                             
--------------------------------------------------------------------
 Nested Loop Left Join
   Output: t2.unique1, t2.unique2
   ->  Hash Left Join
         Output: t2.unique1, t2.unique2
         Hash Cond: (t1.unique1 = t2.unique1)
         ->  Index Only Scan using tenk1_unique1 on public.tenk1 t1
               Output: t1.unique1
         ->  Hash
               Output: t2.unique1, t2.unique2
               ->  Seq Scan on public.onek t2
                     Output: t2.unique1, t2.unique2
   ->  Materialize
         ->  Seq Scan on public.int8_tbl t3
(13 rows)

drop function f_field_select(t onek);
--
-- test extraction of restriction OR clauses from join OR clause
-- (we used to only do this for indexable clauses)
--
explain (costs off)
select * from tenk1 a join tenk1 b on
  (a.unique1 = 1 and b.unique1 = 2) or (a.unique2 = 3 and b.hundred = 4);
                                           QUERY PLAN                                            
-------------------------------------------------------------------------------------------------
 Nested Loop
   Join Filter: (((a.unique1 = 1) AND (b.unique1 = 2)) OR ((a.unique2 = 3) AND (b.hundred = 4)))
   ->  Bitmap Heap Scan on tenk1 b
         Recheck Cond: ((unique1 = 2) OR (hundred = 4))
         ->  BitmapOr
               ->  Bitmap Index Scan on tenk1_unique1
                     Index Cond: (unique1 = 2)
               ->  Bitmap Index Scan on tenk1_hundred
                     Index Cond: (hundred = 4)
   ->  Materialize
         ->  Bitmap Heap Scan on tenk1 a
               Recheck Cond: ((unique1 = 1) OR (unique2 = 3))
               ->  BitmapOr
                     ->  Bitmap Index Scan on tenk1_unique1
                           Index Cond: (unique1 = 1)
                     ->  Bitmap Index Scan on tenk1_unique2
                           Index Cond: (unique2 = 3)
(17 rows)

explain (costs off)
select * from tenk1 a join tenk1 b on
  (a.unique1 = 1 and b.unique1 = 2) or (a.unique2 = 3 and b.ten = 4);
                                         QUERY PLAN                                          
---------------------------------------------------------------------------------------------
 Nested Loop
   Join Filter: (((a.unique1 = 1) AND (b.unique1 = 2)) OR ((a.unique2 = 3) AND (b.ten = 4)))
   ->  Seq Scan on tenk1 b
         Filter: ((unique1 = 2) OR (ten = 4))
   ->  Materialize
         ->  Bitmap Heap Scan on tenk1 a
               Recheck Cond: ((unique1 = 1) OR (unique2 = 3))
               ->  BitmapOr
                     ->  Bitmap Index Scan on tenk1_unique1
                           Index Cond: (unique1 = 1)
                     ->  Bitmap Index Scan on tenk1_unique2
                           Index Cond: (unique2 = 3)
(12 rows)

explain (costs off)
select * from tenk1 a join tenk1 b on
  (a.unique1 = 1 and b.unique1 = 2) or
  ((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4);
                                                      QUERY PLAN                                                      
----------------------------------------------------------------------------------------------------------------------
 Nested Loop
   Join Filter: (((a.unique1 = 1) AND (b.unique1 = 2)) OR (((a.unique2 = 3) OR (a.unique2 = 7)) AND (b.hundred = 4)))
   ->  Bitmap Heap Scan on tenk1 b
         Recheck Cond: ((unique1 = 2) OR (hundred = 4))
         ->  BitmapOr
               ->  Bitmap Index Scan on tenk1_unique1
                     Index Cond: (unique1 = 2)
               ->  Bitmap Index Scan on tenk1_hundred
                     Index Cond: (hundred = 4)
   ->  Materialize
         ->  Bitmap Heap Scan on tenk1 a
               Recheck Cond: ((unique1 = 1) OR ((unique2 = 3) OR (unique2 = 7)))
               Filter: ((unique1 = 1) OR (unique2 = 3) OR (unique2 = 7))
               ->  BitmapOr
                     ->  Bitmap Index Scan on tenk1_unique1
                           Index Cond: (unique1 = 1)
                     ->  Bitmap Index Scan on tenk1_unique2
                           Index Cond: (unique2 = ANY ('{3,7}'::integer[]))
(18 rows)

explain (costs off)
select * from tenk1 a join tenk1 b on
  (a.unique1 = 1 and b.unique1 = 2) or
  ((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4);
                                                      QUERY PLAN                                                      
----------------------------------------------------------------------------------------------------------------------
 Nested Loop
   Join Filter: (((a.unique1 = 1) AND (b.unique1 = 2)) OR (((a.unique2 = 3) OR (a.unique2 = 7)) AND (b.hundred = 4)))
   ->  Bitmap Heap Scan on tenk1 b
         Recheck Cond: ((unique1 = 2) OR (hundred = 4))
         ->  BitmapOr
               ->  Bitmap Index Scan on tenk1_unique1
                     Index Cond: (unique1 = 2)
               ->  Bitmap Index Scan on tenk1_hundred
                     Index Cond: (hundred = 4)
   ->  Materialize
         ->  Bitmap Heap Scan on tenk1 a
               Recheck Cond: ((unique1 = 1) OR ((unique2 = 3) OR (unique2 = 7)))
               Filter: ((unique1 = 1) OR (unique2 = 3) OR (unique2 = 7))
               ->  BitmapOr
                     ->  Bitmap Index Scan on tenk1_unique1
                           Index Cond: (unique1 = 1)
                     ->  Bitmap Index Scan on tenk1_unique2
                           Index Cond: (unique2 = ANY ('{3,7}'::integer[]))
(18 rows)

explain (costs off)
select * from tenk1 a join tenk1 b on
  (a.unique1 < 20 or a.unique1 = 3 or a.unique1 = 1 and b.unique1 = 2) or
  ((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4);
                                                                         QUERY PLAN                                                                          
-------------------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop
   Join Filter: ((a.unique1 < 20) OR (a.unique1 = 3) OR ((a.unique1 = 1) AND (b.unique1 = 2)) OR (((a.unique2 = 3) OR (a.unique2 = 7)) AND (b.hundred = 4)))
   ->  Seq Scan on tenk1 b
   ->  Materialize
         ->  Bitmap Heap Scan on tenk1 a
               Recheck Cond: ((unique1 < 20) OR ((unique1 = 3) OR (unique1 = 1)) OR ((unique2 = 3) OR (unique2 = 7)))
               Filter: ((unique1 < 20) OR (unique1 = 3) OR (unique1 = 1) OR (unique2 = 3) OR (unique2 = 7))
               ->  BitmapOr
                     ->  Bitmap Index Scan on tenk1_unique1
                           Index Cond: (unique1 < 20)
                     ->  Bitmap Index Scan on tenk1_unique1
                           Index Cond: (unique1 = ANY ('{3,1}'::integer[]))
                     ->  Bitmap Index Scan on tenk1_unique2
                           Index Cond: (unique2 = ANY ('{3,7}'::integer[]))
(14 rows)

--
-- test placement of movable quals in a parameterized join tree
--
explain (costs off)
select * from tenk1 t1 left join
  (tenk1 t2 join tenk1 t3 on t2.thousand = t3.unique2)
  on t1.hundred = t2.hundred and t1.ten = t3.ten
where t1.unique1 = 1;
                       QUERY PLAN                       
--------------------------------------------------------
 Nested Loop Left Join
   ->  Index Scan using tenk1_unique1 on tenk1 t1
         Index Cond: (unique1 = 1)
   ->  Nested Loop
         Join Filter: (t1.ten = t3.ten)
         ->  Bitmap Heap Scan on tenk1 t2
               Recheck Cond: (t1.hundred = hundred)
               ->  Bitmap Index Scan on tenk1_hundred
                     Index Cond: (hundred = t1.hundred)
         ->  Index Scan using tenk1_unique2 on tenk1 t3
               Index Cond: (unique2 = t2.thousand)
(11 rows)

explain (costs off)
select * from tenk1 t1 left join
  (tenk1 t2 join tenk1 t3 on t2.thousand = t3.unique2)
  on t1.hundred = t2.hundred and t1.ten + t2.ten = t3.ten
where t1.unique1 = 1;
                       QUERY PLAN                       
--------------------------------------------------------
 Nested Loop Left Join
   ->  Index Scan using tenk1_unique1 on tenk1 t1
         Index Cond: (unique1 = 1)
   ->  Nested Loop
         Join Filter: ((t1.ten + t2.ten) = t3.ten)
         ->  Bitmap Heap Scan on tenk1 t2
               Recheck Cond: (t1.hundred = hundred)
               ->  Bitmap Index Scan on tenk1_hundred
                     Index Cond: (hundred = t1.hundred)
         ->  Index Scan using tenk1_unique2 on tenk1 t3
               Index Cond: (unique2 = t2.thousand)
(11 rows)

explain (costs off)
select count(*) from
  tenk1 a join tenk1 b on a.unique1 = b.unique2
  left join tenk1 c on a.unique2 = b.unique1 and c.thousand = a.thousand
  join int4_tbl on b.thousand = f1;
                               QUERY PLAN                                
-------------------------------------------------------------------------
 Aggregate
   ->  Nested Loop Left Join
         Join Filter: (a.unique2 = b.unique1)
         ->  Nested Loop
               ->  Nested Loop
                     ->  Seq Scan on int4_tbl
                     ->  Bitmap Heap Scan on tenk1 b
                           Recheck Cond: (thousand = int4_tbl.f1)
                           ->  Bitmap Index Scan on tenk1_thous_tenthous
                                 Index Cond: (thousand = int4_tbl.f1)
               ->  Index Scan using tenk1_unique1 on tenk1 a
                     Index Cond: (unique1 = b.unique2)
         ->  Index Only Scan using tenk1_thous_tenthous on tenk1 c
               Index Cond: (thousand = a.thousand)
(14 rows)

select count(*) from
  tenk1 a join tenk1 b on a.unique1 = b.unique2
  left join tenk1 c on a.unique2 = b.unique1 and c.thousand = a.thousand
  join int4_tbl on b.thousand = f1;
 count 
-------
    10
(1 row)

explain (costs off)
select b.unique1 from
  tenk1 a join tenk1 b on a.unique1 = b.unique2
  left join tenk1 c on b.unique1 = 42 and c.thousand = a.thousand
  join int4_tbl i1 on b.thousand = f1
  right join int4_tbl i2 on i2.f1 = b.tenthous
  order by 1;
                                       QUERY PLAN                                        
-----------------------------------------------------------------------------------------
 Sort
   Sort Key: b.unique1
   ->  Nested Loop Left Join
         ->  Seq Scan on int4_tbl i2
         ->  Nested Loop Left Join
               Join Filter: (b.unique1 = 42)
               ->  Nested Loop
                     ->  Nested Loop
                           ->  Seq Scan on int4_tbl i1
                           ->  Index Scan using tenk1_thous_tenthous on tenk1 b
                                 Index Cond: ((thousand = i1.f1) AND (tenthous = i2.f1))
                     ->  Index Scan using tenk1_unique1 on tenk1 a
                           Index Cond: (unique1 = b.unique2)
               ->  Index Only Scan using tenk1_thous_tenthous on tenk1 c
                     Index Cond: (thousand = a.thousand)
(15 rows)

select b.unique1 from
  tenk1 a join tenk1 b on a.unique1 = b.unique2
  left join tenk1 c on b.unique1 = 42 and c.thousand = a.thousand
  join int4_tbl i1 on b.thousand = f1
  right join int4_tbl i2 on i2.f1 = b.tenthous
  order by 1;
 unique1 
---------
       0
        
        
        
        
(5 rows)

explain (costs off)
select * from
(
  select unique1, q1, coalesce(unique1, -1) + q1 as fault
  from int8_tbl left join tenk1 on (q2 = unique2)
) ss
where fault = 122
order by fault;
                                QUERY PLAN                                
--------------------------------------------------------------------------
 Nested Loop Left Join
   Filter: ((COALESCE(tenk1.unique1, '-1'::integer) + int8_tbl.q1) = 122)
   ->  Seq Scan on int8_tbl
   ->  Index Scan using tenk1_unique2 on tenk1
         Index Cond: (unique2 = int8_tbl.q2)
(5 rows)

select * from
(
  select unique1, q1, coalesce(unique1, -1) + q1 as fault
  from int8_tbl left join tenk1 on (q2 = unique2)
) ss
where fault = 122
order by fault;
 unique1 | q1  | fault 
---------+-----+-------
         | 123 |   122
(1 row)

explain (costs off)
select * from
(values (1, array[10,20]), (2, array[20,30])) as v1(v1x,v1ys)
left join (values (110), (220)) as v2(v2x,v2y) on v2x = v1x
left join unnest(v1ys) as u1(u1y) on u1y = v2y;
                         QUERY PLAN                          
-------------------------------------------------------------
 Nested Loop Left Join
   ->  Values Scan on "*VALUES*"
   ->  Hash Right Join
         Hash Cond: (u1.u1y = "*VALUES*_1".column2)
         Filter: ("*VALUES*_1".column1 = "*VALUES*".column1)
         ->  Function Scan on unnest u1
         ->  Hash
               ->  Values Scan on "*VALUES*_1"
(8 rows)

select * from
(values (1, array[10,20]), (2, array[20,30])) as v1(v1x,v1ys)
left join (values (110), (220)) as v2(v2x,v2y) on v2x = v1x
left join unnest(v1ys) as u1(u1y) on u1y = v2y;
 v1x |  v1ys   | v2x | v2y | u1y 
-----+---------+-----+-----+-----
   1 | {10,20} |   1 |  10 |  10
   2 | {20,30} |   2 |  20 |  20
(2 rows)

--
-- test handling of potential equivalence clauses above outer joins
--
explain (costs off)
select q1, unique2, thousand, hundred
  from int8_tbl a left join tenk1 b on q1 = unique2
  where coalesce(thousand,123) = q1 and q1 = coalesce(hundred,123);
                                                QUERY PLAN                                                
----------------------------------------------------------------------------------------------------------
 Nested Loop Left Join
   Filter: ((COALESCE(b.thousand, 123) = COALESCE(b.hundred, 123)) AND (a.q1 = COALESCE(b.hundred, 123)))
   ->  Seq Scan on int8_tbl a
   ->  Index Scan using tenk1_unique2 on tenk1 b
         Index Cond: (unique2 = a.q1)
(5 rows)

select q1, unique2, thousand, hundred
  from int8_tbl a left join tenk1 b on q1 = unique2
  where coalesce(thousand,123) = q1 and q1 = coalesce(hundred,123);
 q1 | unique2 | thousand | hundred 
----+---------+----------+---------
(0 rows)

explain (costs off)
select f1, unique2, case when unique2 is null then f1 else 0 end
  from int4_tbl a left join tenk1 b on f1 = unique2
  where (case when unique2 is null then f1 else 0 end) = 0;
                             QUERY PLAN                             
--------------------------------------------------------------------
 Nested Loop Left Join
   Filter: (CASE WHEN (b.unique2 IS NULL) THEN a.f1 ELSE 0 END = 0)
   ->  Seq Scan on int4_tbl a
   ->  Index Only Scan using tenk1_unique2 on tenk1 b
         Index Cond: (unique2 = a.f1)
(5 rows)

select f1, unique2, case when unique2 is null then f1 else 0 end
  from int4_tbl a left join tenk1 b on f1 = unique2
  where (case when unique2 is null then f1 else 0 end) = 0;
 f1 | unique2 | case 
----+---------+------
  0 |       0 |    0
(1 row)

--
-- another case with equivalence clauses above outer joins (bug #8591)
--
explain (costs off)
select a.unique1, b.unique1, c.unique1, coalesce(b.twothousand, a.twothousand)
  from tenk1 a left join tenk1 b on b.thousand = a.unique1                        left join tenk1 c on c.unique2 = coalesce(b.twothousand, a.twothousand)
  where a.unique2 < 10 and coalesce(b.twothousand, a.twothousand) = 44;
                          QUERY PLAN                           
---------------------------------------------------------------
 Nested Loop Left Join
   ->  Nested Loop Left Join
         Filter: (COALESCE(b.twothousand, a.twothousand) = 44)
         ->  Index Scan using tenk1_unique2 on tenk1 a
               Index Cond: (unique2 < 10)
         ->  Bitmap Heap Scan on tenk1 b
               Recheck Cond: (thousand = a.unique1)
               ->  Bitmap Index Scan on tenk1_thous_tenthous
                     Index Cond: (thousand = a.unique1)
   ->  Index Scan using tenk1_unique2 on tenk1 c
         Index Cond: (unique2 = 44)
(11 rows)

select a.unique1, b.unique1, c.unique1, coalesce(b.twothousand, a.twothousand)
  from tenk1 a left join tenk1 b on b.thousand = a.unique1                        left join tenk1 c on c.unique2 = coalesce(b.twothousand, a.twothousand)
  where a.unique2 < 10 and coalesce(b.twothousand, a.twothousand) = 44;
 unique1 | unique1 | unique1 | coalesce 
---------+---------+---------+----------
(0 rows)

-- related case
explain (costs off)
select * from int8_tbl t1 left join int8_tbl t2 on t1.q2 = t2.q1,
  lateral (select * from int8_tbl t3 where t2.q1 = t2.q2) ss;
                QUERY PLAN                 
-------------------------------------------
 Nested Loop
   ->  Hash Left Join
         Hash Cond: (t1.q2 = t2.q1)
         Filter: (t2.q1 = t2.q2)
         ->  Seq Scan on int8_tbl t1
         ->  Hash
               ->  Seq Scan on int8_tbl t2
   ->  Seq Scan on int8_tbl t3
(8 rows)

select * from int8_tbl t1 left join int8_tbl t2 on t1.q2 = t2.q1,
  lateral (select * from int8_tbl t3 where t2.q1 = t2.q2) ss;
        q1        |        q2        |        q1        |        q2        |        q1        |        q2         
------------------+------------------+------------------+------------------+------------------+-------------------
              123 | 4567890123456789 | 4567890123456789 | 4567890123456789 |              123 |               456
              123 | 4567890123456789 | 4567890123456789 | 4567890123456789 |              123 |  4567890123456789
              123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 |               123
              123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 |  4567890123456789
              123 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789
 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 |              123 |               456
 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 |              123 |  4567890123456789
 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 |               123
 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 |  4567890123456789
 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789
(10 rows)

--
-- check handling of join aliases when flattening multiple levels of subquery
--
explain (verbose, costs off)
select foo1.join_key as foo1_id, foo3.join_key AS foo3_id, bug_field from
  (values (0),(1)) foo1(join_key)
left join
  (select join_key, bug_field from
    (select ss1.join_key, ss1.bug_field from
      (select f1 as join_key, 666 as bug_field from int4_tbl i1) ss1
    ) foo2
   left join
    (select unique2 as join_key from tenk1 i2) ss2
   using (join_key)
  ) foo3
using (join_key);
                                QUERY PLAN                                
--------------------------------------------------------------------------
 Nested Loop Left Join
   Output: "*VALUES*".column1, i1.f1, (666)
   Join Filter: ("*VALUES*".column1 = i1.f1)
   ->  Values Scan on "*VALUES*"
         Output: "*VALUES*".column1
   ->  Materialize
         Output: i1.f1, (666)
         ->  Nested Loop Left Join
               Output: i1.f1, 666
               ->  Seq Scan on public.int4_tbl i1
                     Output: i1.f1
               ->  Index Only Scan using tenk1_unique2 on public.tenk1 i2
                     Output: i2.unique2
                     Index Cond: (i2.unique2 = i1.f1)
(14 rows)

select foo1.join_key as foo1_id, foo3.join_key AS foo3_id, bug_field from
  (values (0),(1)) foo1(join_key)
left join
  (select join_key, bug_field from
    (select ss1.join_key, ss1.bug_field from
      (select f1 as join_key, 666 as bug_field from int4_tbl i1) ss1
    ) foo2
   left join
    (select unique2 as join_key from tenk1 i2) ss2
   using (join_key)
  ) foo3
using (join_key);
 foo1_id | foo3_id | bug_field 
---------+---------+-----------
       0 |       0 |       666
       1 |         |          
(2 rows)

--
-- check handling of a variable-free join alias
--
explain (verbose, costs off)
select * from
int4_tbl i0 left join
( (select *, 123 as x from int4_tbl i1) ss1
  left join
  (select *, q2 as x from int8_tbl i2) ss2
  using (x)
) ss0
on (i0.f1 = ss0.f1)
order by i0.f1, x;
                         QUERY PLAN                          
-------------------------------------------------------------
 Sort
   Output: i0.f1, ('123'::bigint), i1.f1, i2.q1, i2.q2
   Sort Key: i0.f1, ('123'::bigint)
   ->  Hash Right Join
         Output: i0.f1, ('123'::bigint), i1.f1, i2.q1, i2.q2
         Hash Cond: (i1.f1 = i0.f1)
         ->  Nested Loop Left Join
               Output: i1.f1, i2.q1, i2.q2, '123'::bigint
               ->  Seq Scan on public.int4_tbl i1
                     Output: i1.f1
               ->  Materialize
                     Output: i2.q1, i2.q2
                     ->  Seq Scan on public.int8_tbl i2
                           Output: i2.q1, i2.q2
                           Filter: (123 = i2.q2)
         ->  Hash
               Output: i0.f1
               ->  Seq Scan on public.int4_tbl i0
                     Output: i0.f1
(19 rows)

select * from
int4_tbl i0 left join
( (select *, 123 as x from int4_tbl i1) ss1
  left join
  (select *, q2 as x from int8_tbl i2) ss2
  using (x)
) ss0
on (i0.f1 = ss0.f1)
order by i0.f1, x;
     f1      |  x  |     f1      |        q1        | q2  
-------------+-----+-------------+------------------+-----
 -2147483647 | 123 | -2147483647 | 4567890123456789 | 123
     -123456 | 123 |     -123456 | 4567890123456789 | 123
           0 | 123 |           0 | 4567890123456789 | 123
      123456 | 123 |      123456 | 4567890123456789 | 123
  2147483647 | 123 |  2147483647 | 4567890123456789 | 123
(5 rows)

--
-- test successful handling of nested outer joins with degenerate join quals
--
explain (verbose, costs off)
select t1.* from
  text_tbl t1
  left join (select *, '***'::text as d1 from int8_tbl i8b1) b1
    left join int8_tbl i8
      left join (select *, null::int as d2 from int8_tbl i8b2) b2
      on (i8.q1 = b2.q1)
    on (b2.d2 = b1.q2)
  on (t1.f1 = b1.d1)
  left join int4_tbl i4
  on (i8.q2 = i4.f1);
                              QUERY PLAN                              
----------------------------------------------------------------------
 Hash Left Join
   Output: t1.f1
   Hash Cond: (i8.q2 = i4.f1)
   ->  Nested Loop Left Join
         Output: t1.f1, i8.q2
         Join Filter: (t1.f1 = '***'::text)
         ->  Seq Scan on public.text_tbl t1
               Output: t1.f1
         ->  Materialize
               Output: i8.q2
               ->  Hash Right Join
                     Output: i8.q2
                     Hash Cond: ((NULL::integer) = i8b1.q2)
                     ->  Hash Join
                           Output: i8.q2, (NULL::integer)
                           Hash Cond: (i8.q1 = i8b2.q1)
                           ->  Seq Scan on public.int8_tbl i8
                                 Output: i8.q1, i8.q2
                           ->  Hash
                                 Output: i8b2.q1, (NULL::integer)
                                 ->  Seq Scan on public.int8_tbl i8b2
                                       Output: i8b2.q1, NULL::integer
                     ->  Hash
                           Output: i8b1.q2
                           ->  Seq Scan on public.int8_tbl i8b1
                                 Output: i8b1.q2
   ->  Hash
         Output: i4.f1
         ->  Seq Scan on public.int4_tbl i4
               Output: i4.f1
(30 rows)

select t1.* from
  text_tbl t1
  left join (select *, '***'::text as d1 from int8_tbl i8b1) b1
    left join int8_tbl i8
      left join (select *, null::int as d2 from int8_tbl i8b2) b2
      on (i8.q1 = b2.q1)
    on (b2.d2 = b1.q2)
  on (t1.f1 = b1.d1)
  left join int4_tbl i4
  on (i8.q2 = i4.f1);
        f1         
-------------------
 doh!
 hi de ho neighbor
(2 rows)

explain (verbose, costs off)
select t1.* from
  text_tbl t1
  left join (select *, '***'::text as d1 from int8_tbl i8b1) b1
    left join int8_tbl i8
      left join (select *, null::int as d2 from int8_tbl i8b2, int4_tbl i4b2) b2
      on (i8.q1 = b2.q1)
    on (b2.d2 = b1.q2)
  on (t1.f1 = b1.d1)
  left join int4_tbl i4
  on (i8.q2 = i4.f1);
                                 QUERY PLAN                                 
----------------------------------------------------------------------------
 Hash Left Join
   Output: t1.f1
   Hash Cond: (i8.q2 = i4.f1)
   ->  Nested Loop Left Join
         Output: t1.f1, i8.q2
         Join Filter: (t1.f1 = '***'::text)
         ->  Seq Scan on public.text_tbl t1
               Output: t1.f1
         ->  Materialize
               Output: i8.q2
               ->  Hash Right Join
                     Output: i8.q2
                     Hash Cond: ((NULL::integer) = i8b1.q2)
                     ->  Hash Right Join
                           Output: i8.q2, (NULL::integer)
                           Hash Cond: (i8b2.q1 = i8.q1)
                           ->  Nested Loop
                                 Output: i8b2.q1, NULL::integer
                                 ->  Seq Scan on public.int8_tbl i8b2
                                       Output: i8b2.q1, i8b2.q2
                                 ->  Materialize
                                       ->  Seq Scan on public.int4_tbl i4b2
                           ->  Hash
                                 Output: i8.q1, i8.q2
                                 ->  Seq Scan on public.int8_tbl i8
                                       Output: i8.q1, i8.q2
                     ->  Hash
                           Output: i8b1.q2
                           ->  Seq Scan on public.int8_tbl i8b1
                                 Output: i8b1.q2
   ->  Hash
         Output: i4.f1
         ->  Seq Scan on public.int4_tbl i4
               Output: i4.f1
(34 rows)

select t1.* from
  text_tbl t1
  left join (select *, '***'::text as d1 from int8_tbl i8b1) b1
    left join int8_tbl i8
      left join (select *, null::int as d2 from int8_tbl i8b2, int4_tbl i4b2) b2
      on (i8.q1 = b2.q1)
    on (b2.d2 = b1.q2)
  on (t1.f1 = b1.d1)
  left join int4_tbl i4
  on (i8.q2 = i4.f1);
        f1         
-------------------
 doh!
 hi de ho neighbor
(2 rows)

explain (verbose, costs off)
select t1.* from
  text_tbl t1
  left join (select *, '***'::text as d1 from int8_tbl i8b1) b1
    left join int8_tbl i8
      left join (select *, null::int as d2 from int8_tbl i8b2, int4_tbl i4b2
                 where q1 = f1) b2
      on (i8.q1 = b2.q1)
    on (b2.d2 = b1.q2)
  on (t1.f1 = b1.d1)
  left join int4_tbl i4
  on (i8.q2 = i4.f1);
                                 QUERY PLAN                                 
----------------------------------------------------------------------------
 Hash Left Join
   Output: t1.f1
   Hash Cond: (i8.q2 = i4.f1)
   ->  Nested Loop Left Join
         Output: t1.f1, i8.q2
         Join Filter: (t1.f1 = '***'::text)
         ->  Seq Scan on public.text_tbl t1
               Output: t1.f1
         ->  Materialize
               Output: i8.q2
               ->  Hash Right Join
                     Output: i8.q2
                     Hash Cond: ((NULL::integer) = i8b1.q2)
                     ->  Hash Right Join
                           Output: i8.q2, (NULL::integer)
                           Hash Cond: (i8b2.q1 = i8.q1)
                           ->  Hash Join
                                 Output: i8b2.q1, NULL::integer
                                 Hash Cond: (i8b2.q1 = i4b2.f1)
                                 ->  Seq Scan on public.int8_tbl i8b2
                                       Output: i8b2.q1, i8b2.q2
                                 ->  Hash
                                       Output: i4b2.f1
                                       ->  Seq Scan on public.int4_tbl i4b2
                                             Output: i4b2.f1
                           ->  Hash
                                 Output: i8.q1, i8.q2
                                 ->  Seq Scan on public.int8_tbl i8
                                       Output: i8.q1, i8.q2
                     ->  Hash
                           Output: i8b1.q2
                           ->  Seq Scan on public.int8_tbl i8b1
                                 Output: i8b1.q2
   ->  Hash
         Output: i4.f1
         ->  Seq Scan on public.int4_tbl i4
               Output: i4.f1
(37 rows)

select t1.* from
  text_tbl t1
  left join (select *, '***'::text as d1 from int8_tbl i8b1) b1
    left join int8_tbl i8
      left join (select *, null::int as d2 from int8_tbl i8b2, int4_tbl i4b2
                 where q1 = f1) b2
      on (i8.q1 = b2.q1)
    on (b2.d2 = b1.q2)
  on (t1.f1 = b1.d1)
  left join int4_tbl i4
  on (i8.q2 = i4.f1);
        f1         
-------------------
 doh!
 hi de ho neighbor
(2 rows)

explain (verbose, costs off)
select * from
  text_tbl t1
  inner join int8_tbl i8
  on i8.q2 = 456
  right join text_tbl t2
  on t1.f1 = 'doh!'
  left join int4_tbl i4
  on i8.q1 = i4.f1;
                       QUERY PLAN                       
--------------------------------------------------------
 Nested Loop Left Join
   Output: t1.f1, i8.q1, i8.q2, t2.f1, i4.f1
   ->  Seq Scan on public.text_tbl t2
         Output: t2.f1
   ->  Materialize
         Output: i8.q1, i8.q2, i4.f1, t1.f1
         ->  Nested Loop
               Output: i8.q1, i8.q2, i4.f1, t1.f1
               ->  Nested Loop Left Join
                     Output: i8.q1, i8.q2, i4.f1
                     Join Filter: (i8.q1 = i4.f1)
                     ->  Seq Scan on public.int8_tbl i8
                           Output: i8.q1, i8.q2
                           Filter: (i8.q2 = 456)
                     ->  Seq Scan on public.int4_tbl i4
                           Output: i4.f1
               ->  Seq Scan on public.text_tbl t1
                     Output: t1.f1
                     Filter: (t1.f1 = 'doh!'::text)
(19 rows)

select * from
  text_tbl t1
  inner join int8_tbl i8
  on i8.q2 = 456
  right join text_tbl t2
  on t1.f1 = 'doh!'
  left join int4_tbl i4
  on i8.q1 = i4.f1;
  f1  | q1  | q2  |        f1         | f1 
------+-----+-----+-------------------+----
 doh! | 123 | 456 | doh!              |   
 doh! | 123 | 456 | hi de ho neighbor |   
(2 rows)

-- check handling of a variable-free qual for a non-commutable outer join
explain (costs off)
select nspname
from (select 1 as x) ss1
left join
( select n.nspname, c.relname
  from pg_class c left join pg_namespace n on n.oid = c.relnamespace
  where c.relkind = 'r'
) ss2 on false;
           QUERY PLAN           
--------------------------------
 Nested Loop Left Join
   Join Filter: false
   ->  Result
   ->  Result
         One-Time Filter: false
(5 rows)

-- check handling of apparently-commutable outer joins with non-commutable
-- joins between them
explain (costs off)
select 1 from
  int4_tbl i4
  left join int8_tbl i8 on i4.f1 is not null
  left join (select 1 as a) ss1 on null
  join int4_tbl i42 on ss1.a is null or i8.q1 <> i8.q2
  right join (select 2 as b) ss2
  on ss2.b < i4.f1;
                        QUERY PLAN                         
-----------------------------------------------------------
 Nested Loop Left Join
   ->  Result
   ->  Nested Loop
         ->  Nested Loop Left Join
               Join Filter: NULL::boolean
               Filter: (((1) IS NULL) OR (i8.q1 <> i8.q2))
               ->  Nested Loop Left Join
                     Join Filter: (i4.f1 IS NOT NULL)
                     ->  Seq Scan on int4_tbl i4
                           Filter: (2 < f1)
                     ->  Materialize
                           ->  Seq Scan on int8_tbl i8
               ->  Result
                     One-Time Filter: false
         ->  Materialize
               ->  Seq Scan on int4_tbl i42
(16 rows)

--
-- test for appropriate join order in the presence of lateral references
--
explain (verbose, costs off)
select * from
  text_tbl t1
  left join int8_tbl i8
  on i8.q2 = 123,
  lateral (select i8.q1, t2.f1 from text_tbl t2 limit 1) as ss
where t1.f1 = ss.f1;
                    QUERY PLAN                    
--------------------------------------------------
 Nested Loop
   Output: t1.f1, i8.q1, i8.q2, (i8.q1), t2.f1
   Join Filter: (t1.f1 = t2.f1)
   ->  Nested Loop Left Join
         Output: t1.f1, i8.q1, i8.q2
         ->  Seq Scan on public.text_tbl t1
               Output: t1.f1
         ->  Materialize
               Output: i8.q1, i8.q2
               ->  Seq Scan on public.int8_tbl i8
                     Output: i8.q1, i8.q2
                     Filter: (i8.q2 = 123)
   ->  Memoize
         Output: (i8.q1), t2.f1
         Cache Key: i8.q1
         Cache Mode: binary
         ->  Limit
               Output: (i8.q1), t2.f1
               ->  Seq Scan on public.text_tbl t2
                     Output: i8.q1, t2.f1
(20 rows)

select * from
  text_tbl t1
  left join int8_tbl i8
  on i8.q2 = 123,
  lateral (select i8.q1, t2.f1 from text_tbl t2 limit 1) as ss
where t1.f1 = ss.f1;
  f1  |        q1        | q2  |        q1        |  f1  
------+------------------+-----+------------------+------
 doh! | 4567890123456789 | 123 | 4567890123456789 | doh!
(1 row)

explain (verbose, costs off)
select * from
  text_tbl t1
  left join int8_tbl i8
  on i8.q2 = 123,
  lateral (select i8.q1, t2.f1 from text_tbl t2 limit 1) as ss1,
  lateral (select ss1.* from text_tbl t3 limit 1) as ss2
where t1.f1 = ss2.f1;
                            QUERY PLAN                             
-------------------------------------------------------------------
 Nested Loop
   Output: t1.f1, i8.q1, i8.q2, (i8.q1), t2.f1, ((i8.q1)), (t2.f1)
   Join Filter: (t1.f1 = (t2.f1))
   ->  Nested Loop
         Output: t1.f1, i8.q1, i8.q2, (i8.q1), t2.f1
         ->  Nested Loop Left Join
               Output: t1.f1, i8.q1, i8.q2
               ->  Seq Scan on public.text_tbl t1
                     Output: t1.f1
               ->  Materialize
                     Output: i8.q1, i8.q2
                     ->  Seq Scan on public.int8_tbl i8
                           Output: i8.q1, i8.q2
                           Filter: (i8.q2 = 123)
         ->  Memoize
               Output: (i8.q1), t2.f1
               Cache Key: i8.q1
               Cache Mode: binary
               ->  Limit
                     Output: (i8.q1), t2.f1
                     ->  Seq Scan on public.text_tbl t2
                           Output: i8.q1, t2.f1
   ->  Memoize
         Output: ((i8.q1)), (t2.f1)
         Cache Key: (i8.q1), t2.f1
         Cache Mode: binary
         ->  Limit
               Output: ((i8.q1)), (t2.f1)
               ->  Seq Scan on public.text_tbl t3
                     Output: (i8.q1), t2.f1
(30 rows)

select * from
  text_tbl t1
  left join int8_tbl i8
  on i8.q2 = 123,
  lateral (select i8.q1, t2.f1 from text_tbl t2 limit 1) as ss1,
  lateral (select ss1.* from text_tbl t3 limit 1) as ss2
where t1.f1 = ss2.f1;
  f1  |        q1        | q2  |        q1        |  f1  |        q1        |  f1  
------+------------------+-----+------------------+------+------------------+------
 doh! | 4567890123456789 | 123 | 4567890123456789 | doh! | 4567890123456789 | doh!
(1 row)

explain (verbose, costs off)
select 1 from
  text_tbl as tt1
  inner join text_tbl as tt2 on (tt1.f1 = 'foo')
  left join text_tbl as tt3 on (tt3.f1 = 'foo')
  left join text_tbl as tt4 on (tt3.f1 = tt4.f1),
  lateral (select tt4.f1 as c0 from text_tbl as tt5 limit 1) as ss1
where tt1.f1 = ss1.c0;
                        QUERY PLAN                        
----------------------------------------------------------
 Nested Loop
   Output: 1
   ->  Nested Loop Left Join
         Output: tt1.f1, tt4.f1
         ->  Nested Loop
               Output: tt1.f1
               ->  Seq Scan on public.text_tbl tt1
                     Output: tt1.f1
                     Filter: (tt1.f1 = 'foo'::text)
               ->  Seq Scan on public.text_tbl tt2
                     Output: tt2.f1
         ->  Materialize
               Output: tt4.f1
               ->  Nested Loop Left Join
                     Output: tt4.f1
                     ->  Seq Scan on public.text_tbl tt3
                           Output: tt3.f1
                           Filter: (tt3.f1 = 'foo'::text)
                     ->  Seq Scan on public.text_tbl tt4
                           Output: tt4.f1
                           Filter: (tt4.f1 = 'foo'::text)
   ->  Memoize
         Output: ss1.c0
         Cache Key: tt4.f1
         Cache Mode: binary
         ->  Subquery Scan on ss1
               Output: ss1.c0
               Filter: (ss1.c0 = 'foo'::text)
               ->  Limit
                     Output: (tt4.f1)
                     ->  Seq Scan on public.text_tbl tt5
                           Output: tt4.f1
(32 rows)

select 1 from
  text_tbl as tt1
  inner join text_tbl as tt2 on (tt1.f1 = 'foo')
  left join text_tbl as tt3 on (tt3.f1 = 'foo')
  left join text_tbl as tt4 on (tt3.f1 = tt4.f1),
  lateral (select tt4.f1 as c0 from text_tbl as tt5 limit 1) as ss1
where tt1.f1 = ss1.c0;
 ?column? 
----------
(0 rows)

explain (verbose, costs off)
select 1 from
  int4_tbl as i4
  inner join
    ((select 42 as n from int4_tbl x1 left join int8_tbl x2 on f1 = q1) as ss1
     right join (select 1 as z) as ss2 on true)
  on false,
  lateral (select i4.f1, ss1.n from int8_tbl as i8 limit 1) as ss3;
        QUERY PLAN        
--------------------------
 Result
   Output: 1
   One-Time Filter: false
(3 rows)

select 1 from
  int4_tbl as i4
  inner join
    ((select 42 as n from int4_tbl x1 left join int8_tbl x2 on f1 = q1) as ss1
     right join (select 1 as z) as ss2 on true)
  on false,
  lateral (select i4.f1, ss1.n from int8_tbl as i8 limit 1) as ss3;
 ?column? 
----------
(0 rows)

--
-- check a case where we formerly generated invalid parameterized paths
--
begin;
create temp table t (a int unique);
explain (costs off)
select 1 from t t1
  join lateral (select t1.a from (select 1) foo offset 0) as s1 on true
  join
    (select 1 from t t2
       inner join (t t3
                   left join (t t4 left join t t5 on t4.a = 1)
                   on t3.a = t4.a)
       on false
     where t3.a = coalesce(t5.a,1)) as s2
  on true;
        QUERY PLAN        
--------------------------
 Result
   One-Time Filter: false
(2 rows)

rollback;
--
-- check a case in which a PlaceHolderVar forces join order
--
explain (verbose, costs off)
select ss2.* from
  int4_tbl i41
  left join int8_tbl i8
    join (select i42.f1 as c1, i43.f1 as c2, 42 as c3
          from int4_tbl i42, int4_tbl i43) ss1
    on i8.q1 = ss1.c2
  on i41.f1 = ss1.c1,
  lateral (select i41.*, i8.*, ss1.* from text_tbl limit 1) ss2
where ss1.c2 = 0;
                               QUERY PLAN                               
------------------------------------------------------------------------
 Nested Loop
   Output: (i41.f1), (i8.q1), (i8.q2), (i42.f1), (i43.f1), ((42))
   ->  Hash Join
         Output: i41.f1, i42.f1, i8.q1, i8.q2, i43.f1, 42
         Hash Cond: (i41.f1 = i42.f1)
         ->  Nested Loop
               Output: i8.q1, i8.q2, i43.f1, i41.f1
               ->  Nested Loop
                     Output: i8.q1, i8.q2, i43.f1
                     ->  Seq Scan on public.int8_tbl i8
                           Output: i8.q1, i8.q2
                           Filter: (i8.q1 = 0)
                     ->  Seq Scan on public.int4_tbl i43
                           Output: i43.f1
                           Filter: (i43.f1 = 0)
               ->  Seq Scan on public.int4_tbl i41
                     Output: i41.f1
         ->  Hash
               Output: i42.f1
               ->  Seq Scan on public.int4_tbl i42
                     Output: i42.f1
   ->  Limit
         Output: (i41.f1), (i8.q1), (i8.q2), (i42.f1), (i43.f1), ((42))
         ->  Seq Scan on public.text_tbl
               Output: i41.f1, i8.q1, i8.q2, i42.f1, i43.f1, (42)
(25 rows)

select ss2.* from
  int4_tbl i41
  left join int8_tbl i8
    join (select i42.f1 as c1, i43.f1 as c2, 42 as c3
          from int4_tbl i42, int4_tbl i43) ss1
    on i8.q1 = ss1.c2
  on i41.f1 = ss1.c1,
  lateral (select i41.*, i8.*, ss1.* from text_tbl limit 1) ss2
where ss1.c2 = 0;
 f1 | q1 | q2 | c1 | c2 | c3 
----+----+----+----+----+----
(0 rows)

--
-- test successful handling of full join underneath left join (bug #14105)
--
explain (costs off)
select * from
  (select 1 as id) as xx
  left join
    (tenk1 as a1 full join (select 1 as id) as yy on (a1.unique1 = yy.id))
  on (xx.id = coalesce(yy.id));
              QUERY PLAN               
---------------------------------------
 Nested Loop Left Join
   ->  Result
   ->  Hash Full Join
         Hash Cond: (a1.unique1 = (1))
         Filter: (1 = COALESCE((1)))
         ->  Seq Scan on tenk1 a1
         ->  Hash
               ->  Result
(8 rows)

select * from
  (select 1 as id) as xx
  left join
    (tenk1 as a1 full join (select 1 as id) as yy on (a1.unique1 = yy.id))
  on (xx.id = coalesce(yy.id));
 id | unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 | id 
----+---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------+----
  1 |       1 |    2838 |   1 |    1 |   1 |      1 |       1 |        1 |           1 |         1 |        1 |   2 |    3 | BAAAAA   | EFEAAA   | OOOOxx  |  1
(1 row)

--
-- test ability to push constants through outer join clauses
--
explain (costs off)
  select * from int4_tbl a left join tenk1 b on f1 = unique2 where f1 = 0;
                   QUERY PLAN                    
-------------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on int4_tbl a
         Filter: (f1 = 0)
   ->  Index Scan using tenk1_unique2 on tenk1 b
         Index Cond: (unique2 = 0)
(5 rows)

explain (costs off)
  select * from tenk1 a full join tenk1 b using(unique2) where unique2 = 42;
                   QUERY PLAN                    
-------------------------------------------------
 Merge Full Join
   ->  Index Scan using tenk1_unique2 on tenk1 a
         Index Cond: (unique2 = 42)
   ->  Index Scan using tenk1_unique2 on tenk1 b
         Index Cond: (unique2 = 42)
(5 rows)

--
-- test that quals attached to an outer join have correct semantics,
-- specifically that they don't re-use expressions computed below the join;
-- we force a mergejoin so that coalesce(b.q1, 1) appears as a join input
--
set enable_hashjoin to off;
set enable_nestloop to off;
explain (verbose, costs off)
  select a.q2, b.q1
    from int8_tbl a left join int8_tbl b on a.q2 = coalesce(b.q1, 1)
    where coalesce(b.q1, 1) > 0;
                       QUERY PLAN                        
---------------------------------------------------------
 Merge Left Join
   Output: a.q2, b.q1
   Merge Cond: (a.q2 = (COALESCE(b.q1, '1'::bigint)))
   Filter: (COALESCE(b.q1, '1'::bigint) > 0)
   ->  Sort
         Output: a.q2
         Sort Key: a.q2
         ->  Seq Scan on public.int8_tbl a
               Output: a.q2
   ->  Sort
         Output: b.q1, (COALESCE(b.q1, '1'::bigint))
         Sort Key: (COALESCE(b.q1, '1'::bigint))
         ->  Seq Scan on public.int8_tbl b
               Output: b.q1, COALESCE(b.q1, '1'::bigint)
(14 rows)

select a.q2, b.q1
  from int8_tbl a left join int8_tbl b on a.q2 = coalesce(b.q1, 1)
  where coalesce(b.q1, 1) > 0;
        q2         |        q1        
-------------------+------------------
 -4567890123456789 |                 
               123 |              123
               123 |              123
               456 |                 
  4567890123456789 | 4567890123456789
  4567890123456789 | 4567890123456789
  4567890123456789 | 4567890123456789
  4567890123456789 | 4567890123456789
  4567890123456789 | 4567890123456789
  4567890123456789 | 4567890123456789
(10 rows)

reset enable_hashjoin;
reset enable_nestloop;
--
-- test join strength reduction with a SubPlan providing the proof
--
explain (costs off)
select a.unique1, b.unique2
  from onek a left join onek b on a.unique1 = b.unique2
  where (b.unique2, random() > 0) = any (select q1, random() > 0 from int8_tbl c where c.q1 < b.unique1);
                                                    QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Hash Join
   Hash Cond: (b.unique2 = a.unique1)
   ->  Seq Scan on onek b
         Filter: (ANY ((unique2 = (SubPlan 1).col1) AND ((random() > '0'::double precision) = (SubPlan 1).col2)))
         SubPlan 1
           ->  Seq Scan on int8_tbl c
                 Filter: (q1 < b.unique1)
   ->  Hash
         ->  Index Only Scan using onek_unique1 on onek a
(9 rows)

select a.unique1, b.unique2
  from onek a left join onek b on a.unique1 = b.unique2
  where (b.unique2, random() > 0) = any (select q1, random() > 0 from int8_tbl c where c.q1 < b.unique1);
 unique1 | unique2 
---------+---------
     123 |     123
(1 row)

--
-- test full-join strength reduction
--
explain (costs off)
select a.unique1, b.unique2
  from onek a full join onek b on a.unique1 = b.unique2
  where a.unique1 = 42;
                     QUERY PLAN                     
----------------------------------------------------
 Nested Loop Left Join
   ->  Index Only Scan using onek_unique1 on onek a
         Index Cond: (unique1 = 42)
   ->  Index Only Scan using onek_unique2 on onek b
         Index Cond: (unique2 = 42)
(5 rows)

select a.unique1, b.unique2
  from onek a full join onek b on a.unique1 = b.unique2
  where a.unique1 = 42;
 unique1 | unique2 
---------+---------
      42 |      42
(1 row)

explain (costs off)
select a.unique1, b.unique2
  from onek a full join onek b on a.unique1 = b.unique2
  where b.unique2 = 43;
                     QUERY PLAN                     
----------------------------------------------------
 Nested Loop Left Join
   ->  Index Only Scan using onek_unique2 on onek b
         Index Cond: (unique2 = 43)
   ->  Index Only Scan using onek_unique1 on onek a
         Index Cond: (unique1 = 43)
(5 rows)

select a.unique1, b.unique2
  from onek a full join onek b on a.unique1 = b.unique2
  where b.unique2 = 43;
 unique1 | unique2 
---------+---------
      43 |      43
(1 row)

explain (costs off)
select a.unique1, b.unique2
  from onek a full join onek b on a.unique1 = b.unique2
  where a.unique1 = 42 and b.unique2 = 42;
                     QUERY PLAN                     
----------------------------------------------------
 Nested Loop
   ->  Index Only Scan using onek_unique1 on onek a
         Index Cond: (unique1 = 42)
   ->  Index Only Scan using onek_unique2 on onek b
         Index Cond: (unique2 = 42)
(5 rows)

select a.unique1, b.unique2
  from onek a full join onek b on a.unique1 = b.unique2
  where a.unique1 = 42 and b.unique2 = 42;
 unique1 | unique2 
---------+---------
      42 |      42
(1 row)

--
-- test result-RTE removal underneath a full join
--
explain (costs off)
select * from
  (select * from int8_tbl i81 join (values(123,2)) v(v1,v2) on q2=v1) ss1
full join
  (select * from (values(456,2)) w(v1,v2) join int8_tbl i82 on q2=v1) ss2
on true;
              QUERY PLAN              
--------------------------------------
 Merge Full Join
   ->  Seq Scan on int8_tbl i81
         Filter: (q2 = 123)
   ->  Materialize
         ->  Seq Scan on int8_tbl i82
               Filter: (q2 = 456)
(6 rows)

select * from
  (select * from int8_tbl i81 join (values(123,2)) v(v1,v2) on q2=v1) ss1
full join
  (select * from (values(456,2)) w(v1,v2) join int8_tbl i82 on q2=v1) ss2
on true;
        q1        | q2  | v1  | v2 | v1  | v2 | q1  | q2  
------------------+-----+-----+----+-----+----+-----+-----
 4567890123456789 | 123 | 123 |  2 | 456 |  2 | 123 | 456
(1 row)

--
-- test join removal
--
begin;
CREATE TEMP TABLE a (id int PRIMARY KEY, b_id int);
CREATE TEMP TABLE b (id int PRIMARY KEY, c_id int);
CREATE TEMP TABLE c (id int PRIMARY KEY);
CREATE TEMP TABLE d (a int, b int);
CREATE TEMP TABLE e (id1 int, id2 int, PRIMARY KEY(id1, id2));
INSERT INTO a VALUES (00), (1, NULL);
INSERT INTO b VALUES (00), (1, NULL);
INSERT INTO c VALUES (0), (1);
INSERT INTO d VALUES (1,3), (2,2), (3,1);
INSERT INTO e VALUES (0,0), (2,2), (3,1);
-- all these cases should be optimizable into a simple seqscan
explain (costs off) SELECT a.* FROM a LEFT JOIN b ON a.b_id = b.id;
  QUERY PLAN   
---------------
 Seq Scan on a
(1 row)

explain (costs off) SELECT b.* FROM b LEFT JOIN c ON b.c_id = c.id;
  QUERY PLAN   
---------------
 Seq Scan on b
(1 row)

explain (costs off)
  SELECT a.* FROM a LEFT JOIN (b left join c on b.c_id = c.id)
  ON (a.b_id = b.id);
  QUERY PLAN   
---------------
 Seq Scan on a
(1 row)

explain (costs off)
  SELECT a.* FROM a LEFT JOIN b ON a.id = b.id
  LEFT JOIN e ON e.id1 = a.b_id AND b.c_id = e.id2;
  QUERY PLAN   
---------------
 Seq Scan on a
(1 row)

-- check optimization of outer join within another special join
explain (costs off)
select id from a where id in (
 select b.id from b left join c on b.id = c.id
);
         QUERY PLAN         
----------------------------
 Hash Join
   Hash Cond: (a.id = b.id)
   ->  Seq Scan on a
   ->  Hash
         ->  Seq Scan on b
(5 rows)

-- check optimization with oddly-nested outer joins
explain (costs off)
select a1.id from
  (a a1 left join a a2 on true)
  left join
  (a a3 left join a a4 on a3.id = a4.id)
  on a2.id = a3.id;
          QUERY PLAN          
------------------------------
 Nested Loop Left Join
   ->  Seq Scan on a a1
   ->  Materialize
         ->  Seq Scan on a a2
(4 rows)

explain (costs off)
select a1.id from
  (a a1 left join a a2 on a1.id = a2.id)
  left join
  (a a3 left join a a4 on a3.id = a4.id)
  on a2.id = a3.id;
    QUERY PLAN    
------------------
 Seq Scan on a a1
(1 row)

explain (costs off)
select 1 from a t1
    left join a t2 on true
   inner join a t3 on true
    left join a t4 on t2.id = t4.id and t2.id = t3.id;
             QUERY PLAN             
------------------------------------
 Nested Loop
   ->  Nested Loop Left Join
         ->  Seq Scan on a t1
         ->  Materialize
               ->  Seq Scan on a t2
   ->  Materialize
         ->  Seq Scan on a t3
(7 rows)

-- another example (bug #17781)
explain (costs off)
select ss1.f1
from int4_tbl as t1
  left join (int4_tbl as t2
             right join int4_tbl as t3 on null
             left join (int4_tbl as t4
                        right join int8_tbl as t5 on null)
               on t2.f1 = t4.f1
             left join ((select null as f1 from int4_tbl as t6) as ss1
                        inner join int8_tbl as t7 on null)
               on t5.q1 = t7.q2)
    on false;
           QUERY PLAN           
--------------------------------
 Nested Loop Left Join
   Join Filter: false
   ->  Seq Scan on int4_tbl t1
   ->  Result
         One-Time Filter: false
(5 rows)

-- variant with Var rather than PHV coming from t6
explain (costs off)
select ss1.f1
from int4_tbl as t1
  left join (int4_tbl as t2
             right join int4_tbl as t3 on null
             left join (int4_tbl as t4
                        right join int8_tbl as t5 on null)
               on t2.f1 = t4.f1
             left join ((select f1 from int4_tbl as t6) as ss1
                        inner join int8_tbl as t7 on null)
               on t5.q1 = t7.q2)
    on false;
           QUERY PLAN           
--------------------------------
 Nested Loop Left Join
   Join Filter: false
   ->  Seq Scan on int4_tbl t1
   ->  Result
         One-Time Filter: false
(5 rows)

-- per further discussion of bug #17781
explain (costs off)
select ss1.x
from (select f1/2 as x from int4_tbl i4 left join a on a.id = i4.f1) ss1
     right join int8_tbl i8 on true
where current_user is not null;  -- this is to add a Result node
                  QUERY PLAN                   
-----------------------------------------------
 Result
   One-Time Filter: (CURRENT_USER IS NOT NULL)
   ->  Nested Loop Left Join
         ->  Seq Scan on int8_tbl i8
         ->  Materialize
               ->  Seq Scan on int4_tbl i4
(6 rows)

-- and further discussion of bug #17781
explain (costs off)
select *
from int8_tbl t1
  left join (int8_tbl t2 left join onek t3 on t2.q1 > t3.unique1)
    on t1.q2 = t2.q2
  left join onek t4
    on t2.q2 < t3.unique2;
                   QUERY PLAN                    
-------------------------------------------------
 Nested Loop Left Join
   Join Filter: (t2.q2 < t3.unique2)
   ->  Nested Loop Left Join
         Join Filter: (t2.q1 > t3.unique1)
         ->  Hash Left Join
               Hash Cond: (t1.q2 = t2.q2)
               ->  Seq Scan on int8_tbl t1
               ->  Hash
                     ->  Seq Scan on int8_tbl t2
         ->  Materialize
               ->  Seq Scan on onek t3
   ->  Materialize
         ->  Seq Scan on onek t4
(13 rows)

-- bug #19460: we need to clean up RestrictInfos more than we had been doing
explain (costs off)
select * from
  (select 1::int as id) as lhs
full join
  (select dummy_source.id
   from (select null::int as id) as dummy_source
   left join (select a.id from a where a.id = 42) as sub
   on sub.id = dummy_source.id
  ) as rhs
on lhs.id = rhs.id;
              QUERY PLAN              
--------------------------------------
 Hash Full Join
   Hash Cond: ((1) = (NULL::integer))
   ->  Result
   ->  Hash
         ->  Result
(5 rows)

explain (costs off)
select * from
  (select 1::int as id) as lhs
full join
  (select dummy_source.id
   from (select 2::int as id) as dummy_source
   left join (select a.id from a) as sub
   on sub.id = dummy_source.id
  ) as rhs
on lhs.id = rhs.id;
        QUERY PLAN        
--------------------------
 Hash Full Join
   Hash Cond: ((1) = (2))
   ->  Result
   ->  Hash
         ->  Result
(5 rows)

-- More tests of correct placement of pseudoconstant quals
-- simple constant-false condition
explain (costs off)
select * from int8_tbl t1 left join
  (int8_tbl t2 inner join int8_tbl t3 on false
   left join int8_tbl t4 on t2.q2 = t4.q2)
on t1.q1 = t2.q1;
              QUERY PLAN              
--------------------------------------
 Hash Left Join
   Hash Cond: (t1.q1 = q1)
   ->  Seq Scan on int8_tbl t1
   ->  Hash
         ->  Result
               One-Time Filter: false
(6 rows)

-- deduce constant-false from an EquivalenceClass
explain (costs off)
select * from int8_tbl t1 left join
  (int8_tbl t2 inner join int8_tbl t3 on (t2.q1-t3.q2) = 0 and (t2.q1-t3.q2) = 1
   left join int8_tbl t4 on t2.q2 = t4.q2)
on t1.q1 = t2.q1;
              QUERY PLAN              
--------------------------------------
 Hash Left Join
   Hash Cond: (t1.q1 = q1)
   ->  Seq Scan on int8_tbl t1
   ->  Hash
         ->  Result
               One-Time Filter: false
(6 rows)

-- pseudoconstant based on an outer-level Param
explain (costs off)
select exists(
  select * from int8_tbl t1 left join
    (int8_tbl t2 inner join int8_tbl t3 on x0.f1 = 1
     left join int8_tbl t4 on t2.q2 = t4.q2)
  on t1.q1 = t2.q1
) from int4_tbl x0;
                             QUERY PLAN                              
---------------------------------------------------------------------
 Seq Scan on int4_tbl x0
   SubPlan 1
     ->  Nested Loop Left Join
           Join Filter: (t2.q2 = t4.q2)
           ->  Nested Loop Left Join
                 Join Filter: (t1.q1 = t2.q1)
                 ->  Seq Scan on int8_tbl t1
                 ->  Materialize
                       ->  Result
                             One-Time Filter: (x0.f1 = 1)
                             ->  Nested Loop
                                   ->  Seq Scan on int8_tbl t2
                                   ->  Materialize
                                         ->  Seq Scan on int8_tbl t3
           ->  Materialize
                 ->  Seq Scan on int8_tbl t4
(16 rows)

-- check that join removal works for a left join when joining a subquery
-- that is guaranteed to be unique by its GROUP BY clause
explain (costs off)
select d.* from d left join (select * from b group by b.id, b.c_id) s
  on d.a = s.id and d.b = s.c_id;
  QUERY PLAN   
---------------
 Seq Scan on d
(1 row)

-- similarly, but keying off a DISTINCT clause
explain (costs off)
select d.* from d left join (select distinct * from b) s
  on d.a = s.id and d.b = s.c_id;
  QUERY PLAN   
---------------
 Seq Scan on d
(1 row)

-- join removal is not possible when the GROUP BY contains a column that is
-- not in the join condition.  (Note: as of 9.6, we notice that b.id is a
-- primary key and so drop b.c_id from the GROUP BY of the resulting plan;
-- but this happens too late for join removal in the outer plan level.)
explain (costs off)
select d.* from d left join (select * from b group by b.id, b.c_id) s
  on d.a = s.id;
                QUERY PLAN                
------------------------------------------
 Merge Right Join
   Merge Cond: (b.id = d.a)
   ->  Group
         Group Key: b.id
         ->  Index Scan using b_pkey on b
   ->  Sort
         Sort Key: d.a
         ->  Seq Scan on d
(8 rows)

-- similarly, but keying off a DISTINCT clause
explain (costs off)
select d.* from d left join (select distinct * from b) s
  on d.a = s.id;
              QUERY PLAN              
--------------------------------------
 Merge Right Join
   Merge Cond: (b.id = d.a)
   ->  Unique
         ->  Sort
               Sort Key: b.id, b.c_id
               ->  Seq Scan on b
   ->  Sort
         Sort Key: d.a
         ->  Seq Scan on d
(9 rows)

-- join removal is not possible here
explain (costs off)
select 1 from a t1
  left join (a t2 left join a t3 on t2.id = 1) on t2.id = 1;
                       QUERY PLAN                       
--------------------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on a t1
   ->  Materialize
         ->  Nested Loop Left Join
               Join Filter: (t2.id = 1)
               ->  Index Only Scan using a_pkey on a t2
                     Index Cond: (id = 1)
               ->  Seq Scan on a t3
(8 rows)

-- check join removal works when uniqueness of the join condition is enforced
-- by a UNION
explain (costs off)
select d.* from d left join (select id from a union select id from b) s
  on d.a = s.id;
  QUERY PLAN   
---------------
 Seq Scan on d
(1 row)

-- check join removal with a cross-type comparison operator
explain (costs off)
select i8.* from int8_tbl i8 left join (select f1 from int4_tbl group by f1) i4
  on i8.q1 = i4.f1;
       QUERY PLAN        
-------------------------
 Seq Scan on int8_tbl i8
(1 row)

-- check join removal with lateral references
explain (costs off)
select 1 from (select a.id FROM a left join b on a.b_id = b.id) q,
     lateral generate_series(1, q.id) gs(i) where q.id = gs.i;
                QUERY PLAN                 
-------------------------------------------
 Nested Loop
   ->  Seq Scan on a
   ->  Function Scan on generate_series gs
         Filter: (a.id = i)
(4 rows)

-- check join removal within RHS of an outer join
explain (costs off)
select c.id, ss.a from c
  left join (select d.a from onerow, d left join b on d.a = b.id) ss
  on c.id = ss.a;
           QUERY PLAN           
--------------------------------
 Hash Right Join
   Hash Cond: (d.a = c.id)
   ->  Nested Loop
         ->  Seq Scan on onerow
         ->  Seq Scan on d
   ->  Hash
         ->  Seq Scan on c
(7 rows)

-- check the case when the placeholder relates to an outer join and its
-- inner in the press field but actually uses only the outer side of the join
explain (costs off)
SELECT q.val FROM b LEFT JOIN (
  SELECT (q1.z IS NOT NULL) AS val
  FROM b LEFT JOIN (
    SELECT (t1.b_id IS NOT NULL) AS z FROM a t1 LEFT JOIN a t2 USING (id)
    ) AS q1
  ON true
) AS q ON true;
                QUERY PLAN                
------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on b
   ->  Materialize
         ->  Nested Loop Left Join
               ->  Seq Scan on b b_1
               ->  Materialize
                     ->  Seq Scan on a t1
(7 rows)

CREATE TEMP TABLE parted_b (id int PRIMARY KEY) partition by range(id);
CREATE TEMP TABLE parted_b1 partition of parted_b for values from (0) to (10);
-- test join removals on a partitioned table
explain (costs off)
select a.* from a left join parted_b pb on a.b_id = pb.id;
  QUERY PLAN   
---------------
 Seq Scan on a
(1 row)

rollback;
create temp table parent (k int primary key, pd int);
create temp table child (k int unique, cd int);
insert into parent values (110), (220), (330);
insert into child values (1100), (4400);
-- this case is optimizable
select p.* from parent p left join child c on (p.k = c.k);
 k | pd 
---+----
 1 | 10
 2 | 20
 3 | 30
(3 rows)

explain (costs off)
  select p.* from parent p left join child c on (p.k = c.k);
      QUERY PLAN      
----------------------
 Seq Scan on parent p
(1 row)

-- this case is not
select p.*, linked from parent p
  left join (select c.*, true as linked from child c) as ss
  on (p.k = ss.k);
 k | pd | linked 
---+----+--------
 1 | 10 | t
 2 | 20 | 
 3 | 30 | 
(3 rows)

explain (costs off)
  select p.*, linked from parent p
    left join (select c.*, true as linked from child c) as ss
    on (p.k = ss.k);
           QUERY PLAN            
---------------------------------
 Hash Left Join
   Hash Cond: (p.k = c.k)
   ->  Seq Scan on parent p
   ->  Hash
         ->  Seq Scan on child c
(5 rows)

-- check for a 9.0rc1 bug: join removal breaks pseudoconstant qual handling
select p.* from
  parent p left join child c on (p.k = c.k)
  where p.k = 1 and p.k = 2;
 k | pd 
---+----
(0 rows)

explain (costs off)
select p.* from
  parent p left join child c on (p.k = c.k)
  where p.k = 1 and p.k = 2;
        QUERY PLAN        
--------------------------
 Result
   One-Time Filter: false
(2 rows)

select p.* from
  (parent p left join child c on (p.k = c.k)) join parent x on p.k = x.k
  where p.k = 1 and p.k = 2;
 k | pd 
---+----
(0 rows)

explain (costs off)
select p.* from
  (parent p left join child c on (p.k = c.k)) join parent x on p.k = x.k
  where p.k = 1 and p.k = 2;
        QUERY PLAN        
--------------------------
 Result
   One-Time Filter: false
(2 rows)

-- bug 5255: this is not optimizable by join removal
begin;
CREATE TEMP TABLE a (id int PRIMARY KEY);
CREATE TEMP TABLE b (id int PRIMARY KEY, a_id int);
INSERT INTO a VALUES (0), (1);
INSERT INTO b VALUES (00), (1, NULL);
SELECT * FROM b LEFT JOIN a ON (b.a_id = a.id) WHERE (a.id IS NULL OR a.id > 0);
 id | a_id | id 
----+------+----
  1 |      |   
(1 row)

SELECT b.* FROM b LEFT JOIN a ON (b.a_id = a.id) WHERE (a.id IS NULL OR a.id > 0);
 id | a_id 
----+------
  1 |     
(1 row)

rollback;
-- another join removal bug: this is not optimizable, either
begin;
create temp table innertab (id int8 primary key, dat1 int8);
insert into innertab values(12342);
SELECT * FROM
    (SELECT 1 AS x) ss1
  LEFT JOIN
    (SELECT q1, q2, COALESCE(dat1, q1) AS y
     FROM int8_tbl LEFT JOIN innertab ON q2 = id) ss2
  ON true;
 x |        q1        |        q2         |        y         
---+------------------+-------------------+------------------
 1 |              123 |               456 |              123
 1 |              123 |  4567890123456789 |              123
 1 | 4567890123456789 |               123 |               42
 1 | 4567890123456789 |  4567890123456789 | 4567890123456789
 1 | 4567890123456789 | -4567890123456789 | 4567890123456789
(5 rows)

-- join removal bug #17769: can't remove if there's a pushed-down reference
EXPLAIN (COSTS OFF)
SELECT q2 FROM
  (SELECT *
   FROM int8_tbl LEFT JOIN innertab ON q2 = id) ss
 WHERE COALESCE(dat1, 0) = q1;
                           QUERY PLAN                           
----------------------------------------------------------------
 Nested Loop Left Join
   Filter: (COALESCE(innertab.dat1, '0'::bigint) = int8_tbl.q1)
   ->  Seq Scan on int8_tbl
   ->  Index Scan using innertab_pkey on innertab
         Index Cond: (id = int8_tbl.q2)
(5 rows)

-- join removal bug #17773: otherwise-removable PHV appears in a qual condition
EXPLAIN (VERBOSE, COSTS OFF)
SELECT q2 FROM
  (SELECT q2, 'constant'::text AS x
   FROM int8_tbl LEFT JOIN innertab ON q2 = id) ss
  RIGHT JOIN int4_tbl ON NULL
 WHERE x >= x;
                      QUERY PLAN                      
------------------------------------------------------
 Nested Loop Left Join
   Output: q2
   Join Filter: NULL::boolean
   Filter: (('constant'::text) >= ('constant'::text))
   ->  Seq Scan on public.int4_tbl
         Output: int4_tbl.f1
   ->  Result
         Output: q2, 'constant'::text
         One-Time Filter: false
(9 rows)

-- join removal bug #17786: check that OR conditions are cleaned up
EXPLAIN (COSTS OFF)
SELECT f1, x
FROM int4_tbl
     JOIN ((SELECT 42 AS x FROM int8_tbl LEFT JOIN innertab ON q1 = id) AS ss1
           RIGHT JOIN tenk1 ON NULL)
        ON tenk1.unique1 = ss1.x OR tenk1.unique2 = ss1.x;
                                QUERY PLAN                                
--------------------------------------------------------------------------
 Nested Loop
   ->  Seq Scan on int4_tbl
   ->  Materialize
         ->  Nested Loop Left Join
               Join Filter: NULL::boolean
               Filter: ((tenk1.unique1 = (42)) OR (tenk1.unique2 = (42)))
               ->  Seq Scan on tenk1
               ->  Result
                     One-Time Filter: false
(9 rows)

rollback;
-- another join removal bug: we must clean up correctly when removing a PHV
begin;
create temp table uniquetbl (f1 text unique);
explain (costs off)
select t1.* from
  uniquetbl as t1
  left join (select *, '***'::text as d1 from uniquetbl) t2
  on t1.f1 = t2.f1
  left join uniquetbl t3
  on t2.d1 = t3.f1;
        QUERY PLAN        
--------------------------
 Seq Scan on uniquetbl t1
(1 row)

explain (costs off)
select t0.*
from
 text_tbl t0
 left join
   (select case t1.ten when 0 then 'doh!'::text else null::text end as case1,
           t1.stringu2
     from tenk1 t1
     join int4_tbl i4 ON i4.f1 = t1.unique2
     left join uniquetbl u1 ON u1.f1 = t1.string4) ss
  on t0.f1 = ss.case1
where ss.stringu2 !~* ss.case1;
                                         QUERY PLAN                                         
--------------------------------------------------------------------------------------------
 Nested Loop
   Join Filter: (t0.f1 = CASE t1.ten WHEN 0 THEN 'doh!'::text ELSE NULL::text END)
   ->  Nested Loop
         ->  Seq Scan on int4_tbl i4
         ->  Index Scan using tenk1_unique2 on tenk1 t1
               Index Cond: (unique2 = i4.f1)
               Filter: (stringu2 !~* CASE ten WHEN 0 THEN 'doh!'::text ELSE NULL::text END)
   ->  Materialize
         ->  Seq Scan on text_tbl t0
(9 rows)

select t0.*
from
 text_tbl t0
 left join
   (select case t1.ten when 0 then 'doh!'::text else null::text end as case1,
           t1.stringu2
     from tenk1 t1
     join int4_tbl i4 ON i4.f1 = t1.unique2
     left join uniquetbl u1 ON u1.f1 = t1.string4) ss
  on t0.f1 = ss.case1
where ss.stringu2 !~* ss.case1;
  f1  
------
 doh!
(1 row)

rollback;
-- another join removal bug: we must clean up EquivalenceClasses too
begin;
create temp table t (a int unique);
insert into t values (1);
explain (costs off)
select 1
from t t1
  left join (select 2 as c
             from t t2 left join t t3 on t2.a = t3.a) s
    on true
where t1.a = s.c;
          QUERY PLAN          
------------------------------
 Nested Loop Left Join
   Filter: (t1.a = (2))
   ->  Seq Scan on t t1
   ->  Materialize
         ->  Seq Scan on t t2
(5 rows)

select 1
from t t1
  left join (select 2 as c
             from t t2 left join t t3 on t2.a = t3.a) s
    on true
where t1.a = s.c;
 ?column? 
----------
(0 rows)

rollback;
-- check handling of semijoins after join removal: we must suppress
-- unique-ification of known-constant values
begin;
create temp table t (a int unique, b int);
insert into t values (12);
explain (verbose, costs off)
select t1.a from t t1
  left join t t2 on t1.a = t2.a
       join t t3 on true
where exists (select 1 from t t4
                join t t5 on t4.b = t5.b
                join t t6 on t5.b = t6.b
              where t1.a = t4.a and t3.a = t5.a and t4.a = 1);
                                     QUERY PLAN                                     
------------------------------------------------------------------------------------
 Nested Loop
   Output: t1.a
   Inner Unique: true
   ->  Nested Loop
         Output: t1.a, t5.a
         ->  Index Only Scan using t_a_key on pg_temp.t t1
               Output: t1.a
               Index Cond: (t1.a = 1)
         ->  HashAggregate
               Output: t5.a
               Group Key: t5.a
               ->  Hash Join
                     Output: t5.a
                     Hash Cond: (t6.b = t4.b)
                     ->  Seq Scan on pg_temp.t t6
                           Output: t6.a, t6.b
                     ->  Hash
                           Output: t4.b, t5.b, t5.a
                           ->  Hash Join
                                 Output: t4.b, t5.b, t5.a
                                 Inner Unique: true
                                 Hash Cond: (t5.b = t4.b)
                                 ->  Seq Scan on pg_temp.t t5
                                       Output: t5.a, t5.b
                                 ->  Hash
                                       Output: t4.b, t4.a
                                       ->  Index Scan using t_a_key on pg_temp.t t4
                                             Output: t4.b, t4.a
                                             Index Cond: (t4.a = 1)
   ->  Index Only Scan using t_a_key on pg_temp.t t3
         Output: t3.a
         Index Cond: (t3.a = t5.a)
(32 rows)

select t1.a from t t1
  left join t t2 on t1.a = t2.a
       join t t3 on true
where exists (select 1 from t t4
                join t t5 on t4.b = t5.b
                join t t6 on t5.b = t6.b
              where t1.a = t4.a and t3.a = t5.a and t4.a = 1);
 a 
---
 1
(1 row)

rollback;
-- check handling of semijoins if all RHS columns are equated to constants: we
-- should suppress unique-ification in this case.
begin;
create temp table t (a int, b int);
insert into t values (12);
explain (costs off)
select * from t t1, t t2 where exists
  (select 1 from t t3 where t1.a = t3.a and t2.b = t3.b and t3.a = 1 and t3.b = 2);
                 QUERY PLAN                  
---------------------------------------------
 Nested Loop Semi Join
   ->  Nested Loop
         ->  Seq Scan on t t1
               Filter: (a = 1)
         ->  Materialize
               ->  Seq Scan on t t2
                     Filter: (b = 2)
   ->  Materialize
         ->  Seq Scan on t t3
               Filter: ((a = 1) AND (b = 2))
(10 rows)

select * from t t1, t t2 where exists
  (select 1 from t t3 where t1.a = t3.a and t2.b = t3.b and t3.a = 1 and t3.b = 2);
 a | b | a | b 
---+---+---+---
 1 | 2 | 1 | 2
(1 row)

rollback;
-- check handling of semijoin unique-ification for child relations if all RHS
-- columns are equated to constants.
begin;
create temp table p (a int, b int) partition by range (a);
create temp table p1 partition of p for values from (0) to (10);
create temp table p2 partition of p for values from (10) to (20);
insert into p values (12);
insert into p values (1020);
set enable_partitionwise_join to on;
explain (costs off)
select * from p t1 where exists
  (select 1 from p t2 where t1.a = t2.a and t1.a = 1);
          QUERY PLAN           
-------------------------------
 Nested Loop Semi Join
   ->  Seq Scan on p1 t1
         Filter: (a = 1)
   ->  Materialize
         ->  Seq Scan on p1 t2
               Filter: (a = 1)
(6 rows)

select * from p t1 where exists
  (select 1 from p t2 where t1.a = t2.a and t1.a = 1);
 a | b 
---+---
 1 | 2
(1 row)

rollback;
-- test cases where we can remove a join, but not a PHV computed at it
begin;
create temp table t (a int unique, b int);
insert into t values (1,1), (2,2);
explain (costs off)
select 1
from t t1
  left join (select t2.a, 1 as c
             from t t2 left join t t3 on t2.a = t3.a) s
  on true
  left join t t4 on true
where s.a < s.c;
             QUERY PLAN              
-------------------------------------
 Nested Loop Left Join
   ->  Nested Loop
         ->  Seq Scan on t t1
         ->  Materialize
               ->  Seq Scan on t t2
                     Filter: (a < 1)
   ->  Materialize
         ->  Seq Scan on t t4
(8 rows)

explain (costs off)
select t1.a, s.*
from t t1
  left join lateral (select t2.a, coalesce(t1.a, 1) as c
                     from t t2 left join t t3 on t2.a = t3.a) s
  on true
  left join t t4 on true
where s.a < s.c;
                  QUERY PLAN                   
-----------------------------------------------
 Nested Loop Left Join
   ->  Nested Loop
         ->  Seq Scan on t t1
         ->  Seq Scan on t t2
               Filter: (a < COALESCE(t1.a, 1))
   ->  Materialize
         ->  Seq Scan on t t4
(7 rows)

select t1.a, s.*
from t t1
  left join lateral (select t2.a, coalesce(t1.a, 1) as c
                     from t t2 left join t t3 on t2.a = t3.a) s
  on true
  left join t t4 on true
where s.a < s.c;
 a | a | c 
---+---+---
 2 | 1 | 2
 2 | 1 | 2
(2 rows)

rollback;
-- test case to expose miscomputation of required relid set for a PHV
explain (verbose, costs off)
select i8.*, ss.v, t.unique2
  from int8_tbl i8
    left join int4_tbl i4 on i4.f1 = 1
    left join lateral (select i4.f1 + 1 as v) as ss on true
    left join tenk1 t on t.unique2 = ss.v
where q2 = 456;
                         QUERY PLAN                          
-------------------------------------------------------------
 Nested Loop Left Join
   Output: i8.q1, i8.q2, ((i4.f1 + 1)), t.unique2
   ->  Nested Loop Left Join
         Output: i8.q1, i8.q2, (i4.f1 + 1)
         ->  Seq Scan on public.int8_tbl i8
               Output: i8.q1, i8.q2
               Filter: (i8.q2 = 456)
         ->  Seq Scan on public.int4_tbl i4
               Output: i4.f1
               Filter: (i4.f1 = 1)
   ->  Index Only Scan using tenk1_unique2 on public.tenk1 t
         Output: t.unique2
         Index Cond: (t.unique2 = ((i4.f1 + 1)))
(13 rows)

select i8.*, ss.v, t.unique2
  from int8_tbl i8
    left join int4_tbl i4 on i4.f1 = 1
    left join lateral (select i4.f1 + 1 as v) as ss on true
    left join tenk1 t on t.unique2 = ss.v
where q2 = 456;
 q1  | q2  | v | unique2 
-----+-----+---+---------
 123 | 456 |   |        
(1 row)

-- and check a related issue where we miscompute required relids for
-- a PHV that's been translated to a child rel
create temp table parttbl (a integer primary key) partition by range (a);
create temp table parttbl1 partition of parttbl for values from (1) to (100);
insert into parttbl values (11), (12);
explain (costs off)
select * from
  (select *, 12 as phv from parttbl) as ss
  right join int4_tbl on true
where ss.a = ss.phv and f1 = 0;
             QUERY PLAN             
------------------------------------
 Nested Loop
   ->  Seq Scan on parttbl1 parttbl
         Filter: (a = 12)
   ->  Seq Scan on int4_tbl
         Filter: (f1 = 0)
(5 rows)

select * from
  (select *, 12 as phv from parttbl) as ss
  right join int4_tbl on true
where ss.a = ss.phv and f1 = 0;
 a  | phv | f1 
----+-----+----
 12 |  12 |  0
(1 row)

-- bug #8444: we've historically allowed duplicate aliases within aliased JOINs
select * from
  int8_tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = f1; -- error
ERROR:  column reference "f1" is ambiguous
LINE 2: ..._tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = f1;
                                                                    ^
select * from
  int8_tbl x join (int4_tbl x cross join int4_tbl y) j on q1 = y.f1; -- error
ERROR:  invalid reference to FROM-clause entry for table "y"
LINE 2: ...bl x join (int4_tbl x cross join int4_tbl y) j on q1 = y.f1;
                                                                  ^
DETAIL:  There is an entry for table "y", but it cannot be referenced from this part of the query.
select * from
  int8_tbl x join (int4_tbl x cross join int4_tbl y(ff)) j on q1 = f1; -- ok
 q1 | q2 | f1 | ff 
----+----+----+----
(0 rows)

--
-- test that semi- or inner self-joins on a unique column are removed
--
-- enable only nestloop to get more predictable plans
set enable_hashjoin to off;
set enable_mergejoin to off;
create table sj (a int unique, b int, c int unique);
insert into sj values (1, null, 2), (null, 2, null), (211);
analyze sj;
-- Trivial self-join case.
explain (costs off)
select p.* from sj p, sj q where q.a = p.a and q.b = q.a - 1;
                  QUERY PLAN                   
-----------------------------------------------
 Seq Scan on sj q
   Filter: ((a IS NOT NULL) AND (b = (a - 1)))
(2 rows)

select p.* from sj p, sj q where q.a = p.a and q.b = q.a - 1;
 a | b | c 
---+---+---
 2 | 1 | 1
(1 row)

-- Self-join removal performs after a subquery pull-up process and could remove
-- such kind of self-join too. Check this option.
explain (costs off)
select * from sj p
where exists (select * from sj q
              where q.a = p.a and q.b < 10);
                QUERY PLAN                
------------------------------------------
 Seq Scan on sj q
   Filter: ((a IS NOT NULL) AND (b < 10))
(2 rows)

select * from sj p
where exists (select * from sj q
              where q.a = p.a and q.b < 10);
 a | b | c 
---+---+---
 2 | 1 | 1
(1 row)

-- Don't remove self-join for the case of equality of two different unique columns.
explain (costs off)
select * from sj t1, sj t2 where t1.a = t2.c and t1.b is not null;
              QUERY PLAN               
---------------------------------------
 Nested Loop
   Join Filter: (t1.a = t2.c)
   ->  Seq Scan on sj t2
   ->  Materialize
         ->  Seq Scan on sj t1
               Filter: (b IS NOT NULL)
(6 rows)

-- Ensure that relations with TABLESAMPLE clauses are not considered as
-- candidates to be removed
explain (costs off)
select * from sj t1
    join lateral
      (select * from sj tablesample system(t1.b)) s
    on t1.a = s.a;
              QUERY PLAN               
---------------------------------------
 Nested Loop
   ->  Seq Scan on sj t1
   ->  Memoize
         Cache Key: t1.a, t1.b
         Cache Mode: binary
         ->  Sample Scan on sj
               Sampling: system (t1.b)
               Filter: (t1.a = a)
(8 rows)

-- Ensure that SJE does not form a self-referential lateral dependency
explain (costs off)
select * from sj t1
    left join lateral
      (select t1.a as t1a, * from sj t2) s
    on true
where t1.a = s.a;
        QUERY PLAN         
---------------------------
 Seq Scan on sj t2
   Filter: (a IS NOT NULL)
(2 rows)

-- Degenerated case.
explain (costs off)
select * from
  (select a as x from sj where false) as q1,
  (select a as y from sj where false) as q2
where q1.x = q2.y;
        QUERY PLAN        
--------------------------
 Result
   One-Time Filter: false
(2 rows)

-- We can't use a cross-EC generated self join qual because of current logic of
-- the generate_join_implied_equalities routine.
explain (costs off)
select * from sj t1, sj t2 where t1.a = t1.b and t1.b = t2.b and t2.b = t2.a;
          QUERY PLAN          
------------------------------
 Nested Loop
   Join Filter: (t1.a = t2.b)
   ->  Seq Scan on sj t1
         Filter: (a = b)
   ->  Seq Scan on sj t2
         Filter: (b = a)
(6 rows)

explain (costs off)
select * from sj t1, sj t2, sj t3
where t1.a = t1.b and t1.b = t2.b and t2.b = t2.a and
      t1.b = t3.b and t3.b = t3.a;
             QUERY PLAN             
------------------------------------
 Nested Loop
   Join Filter: (t1.a = t3.b)
   ->  Nested Loop
         Join Filter: (t1.a = t2.b)
         ->  Seq Scan on sj t1
               Filter: (a = b)
         ->  Seq Scan on sj t2
               Filter: (b = a)
   ->  Seq Scan on sj t3
         Filter: (b = a)
(10 rows)

-- Double self-join removal.
-- Use a condition on "b + 1", not on "b", for the second join, so that
-- the equivalence class is different from the first one, and we can
-- test the non-ec code path.
explain (costs off)
select *
from  sj t1
      join sj t2 on t1.a = t2.a and t1.b = t2.b
   join sj t3 on t2.a = t3.a and t2.b + 1 = t3.b + 1;
                                QUERY PLAN                                 
---------------------------------------------------------------------------
 Seq Scan on sj t3
   Filter: ((a IS NOT NULL) AND (b IS NOT NULL) AND ((b + 1) IS NOT NULL))
(2 rows)

-- subselect that references the removed relation
explain (costs off)
select t1.a, (select a from sj where a = t2.a and a = t1.a)
from sj t1, sj t2
where t1.a = t2.a;
                QUERY PLAN                
------------------------------------------
 Seq Scan on sj t2
   Filter: (a IS NOT NULL)
   SubPlan 1
     ->  Result
           One-Time Filter: (t2.a = t2.a)
           ->  Seq Scan on sj
                 Filter: (a = t2.a)
(7 rows)

-- self-join under outer join
explain (costs off)
select * from sj x join sj y on x.a = y.a
left join int8_tbl z on x.a = z.q1;
             QUERY PLAN             
------------------------------------
 Nested Loop Left Join
   Join Filter: (y.a = z.q1)
   ->  Seq Scan on sj y
         Filter: (a IS NOT NULL)
   ->  Materialize
         ->  Seq Scan on int8_tbl z
(6 rows)

explain (costs off)
select * from sj x join sj y on x.a = y.a
left join int8_tbl z on y.a = z.q1;
             QUERY PLAN             
------------------------------------
 Nested Loop Left Join
   Join Filter: (y.a = z.q1)
   ->  Seq Scan on sj y
         Filter: (a IS NOT NULL)
   ->  Materialize
         ->  Seq Scan on int8_tbl z
(6 rows)

explain (costs off)
select * from (
  select t1.*, t2.a as ax from sj t1 join sj t2
  on (t1.a = t2.a and t1.c * t1.c = t2.c + 2 and t2.b is null)
) as q1
left join
  (select t3.* from sj t3, sj t4 where t3.c = t4.c) as q2
on q1.ax = q2.a;
                                QUERY PLAN                                 
---------------------------------------------------------------------------
 Nested Loop Left Join
   Join Filter: (t2.a = t4.a)
   ->  Seq Scan on sj t2
         Filter: ((b IS NULL) AND (a IS NOT NULL) AND ((c * c) = (c + 2)))
   ->  Seq Scan on sj t4
         Filter: (c IS NOT NULL)
(6 rows)

-- Test that placeholders are updated correctly after join removal
explain (costs off)
select * from (values (1)) x
left join (select coalesce(y.q1, 1) from int8_tbl y
 right join sj j1 inner join sj j2 on j1.a = j2.a
 on true) z
on true;
                QUERY PLAN                
------------------------------------------
 Nested Loop Left Join
   ->  Result
   ->  Nested Loop Left Join
         ->  Seq Scan on sj j2
               Filter: (a IS NOT NULL)
         ->  Materialize
               ->  Seq Scan on int8_tbl y
(7 rows)

-- Test that references to the removed rel in lateral subqueries are replaced
-- correctly after join removal
explain (verbose, costs off)
select t3.a from sj t1
 join sj t2 on t1.a = t2.a
 join lateral (select t1.a offset 0) t3 on true;
             QUERY PLAN             
------------------------------------
 Nested Loop
   Output: (t2.a)
   ->  Seq Scan on public.sj t2
         Output: t2.a, t2.b, t2.c
         Filter: (t2.a IS NOT NULL)
   ->  Result
         Output: t2.a
(7 rows)

explain (verbose, costs off)
select t3.a from sj t1
 join sj t2 on t1.a = t2.a
 join lateral (select * from (select t1.a offset 0) offset 0) t3 on true;
             QUERY PLAN             
------------------------------------
 Nested Loop
   Output: (t2.a)
   ->  Seq Scan on public.sj t2
         Output: t2.a, t2.b, t2.c
         Filter: (t2.a IS NOT NULL)
   ->  Result
         Output: t2.a
(7 rows)

explain (verbose, costs off)
select t4.a from sj t1
 join sj t2 on t1.a = t2.a
 join lateral (select t3.a from sj t3, (select t1.a) offset 0) t4 on true;
             QUERY PLAN             
------------------------------------
 Nested Loop
   Output: t3.a
   ->  Seq Scan on public.sj t2
         Output: t2.a, t2.b, t2.c
         Filter: (t2.a IS NOT NULL)
   ->  Seq Scan on public.sj t3
         Output: t3.a
(7 rows)

-- Check updating of semi_rhs_exprs links from upper-level semi join to
-- the removing relation
explain (verbose, costs off)
select t1.a from sj t1 where t1.b in (
  select t2.b from sj t2 join sj t3 on t2.c=t3.c);
                QUERY PLAN                
------------------------------------------
 Nested Loop Semi Join
   Output: t1.a
   Join Filter: (t1.b = t3.b)
   ->  Seq Scan on public.sj t1
         Output: t1.a, t1.b, t1.c
   ->  Materialize
         Output: t3.c, t3.b
         ->  Seq Scan on public.sj t3
               Output: t3.c, t3.b
               Filter: (t3.c IS NOT NULL)
(10 rows)

--
-- SJE corner case: uniqueness of an inner is [partially] derived from
-- baserestrictinfo clauses.
-- XXX: We really should allow SJE for these corner cases?
--
INSERT INTO sj VALUES (313);
-- Don't remove SJ
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND j1.a = 2 AND j2.a = 3;
          QUERY PLAN          
------------------------------
 Nested Loop
   Join Filter: (j1.b = j2.b)
   ->  Seq Scan on sj j1
         Filter: (a = 2)
   ->  Seq Scan on sj j2
         Filter: (a = 3)
(6 rows)

-- Return one row
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND j1.a = 2 AND j2.a = 3;
 a | b | c | a | b | c 
---+---+---+---+---+---
 2 | 1 | 1 | 3 | 1 | 3
(1 row)

-- Remove SJ, define uniqueness by a constant
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND j1.a = 2 AND j2.a = 2;
               QUERY PLAN                
-----------------------------------------
 Seq Scan on sj j2
   Filter: ((b IS NOT NULL) AND (a = 2))
(2 rows)

-- Return one row
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND j1.a = 2 AND j2.a = 2;
 a | b | c | a | b | c 
---+---+---+---+---+---
 2 | 1 | 1 | 2 | 1 | 1
(1 row)

-- Remove SJ, define uniqueness by a constant expression
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2
WHERE j1.b = j2.b
  AND j1.a = (EXTRACT(DOW FROM current_timestamp(0))/15 + 3)::int
  AND (EXTRACT(DOW FROM current_timestamp(0))/15 + 3)::int = j2.a;
                                                         QUERY PLAN                                                         
----------------------------------------------------------------------------------------------------------------------------
 Seq Scan on sj j2
   Filter: ((b IS NOT NULL) AND (a = (((EXTRACT(dow FROM CURRENT_TIMESTAMP(0)) / '15'::numeric) + '3'::numeric))::integer))
(2 rows)

-- Return one row
SELECT * FROM sj j1, sj j2
WHERE j1.b = j2.b
  AND j1.a = (EXTRACT(DOW FROM current_timestamp(0))/15 + 3)::int
  AND (EXTRACT(DOW FROM current_timestamp(0))/15 + 3)::int = j2.a;
 a | b | c | a | b | c 
---+---+---+---+---+---
 3 | 1 | 3 | 3 | 1 | 3
(1 row)

-- Remove SJ
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND j1.a = 1 AND j2.a = 1;
               QUERY PLAN                
-----------------------------------------
 Seq Scan on sj j2
   Filter: ((b IS NOT NULL) AND (a = 1))
(2 rows)

-- Return no rows
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND j1.a = 1 AND j2.a = 1;
 a | b | c | a | b | c 
---+---+---+---+---+---
(0 rows)

-- Shuffle a clause. Remove SJ
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND 1 = j1.a AND j2.a = 1;
               QUERY PLAN                
-----------------------------------------
 Seq Scan on sj j2
   Filter: ((b IS NOT NULL) AND (a = 1))
(2 rows)

-- Return no rows
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND 1 = j1.a AND j2.a = 1;
 a | b | c | a | b | c 
---+---+---+---+---+---
(0 rows)

-- SJE Corner case: a 'a.x=a.x' clause, have replaced with 'a.x IS NOT NULL'
-- after SJ elimination it shouldn't be a mergejoinable clause.
EXPLAIN (COSTS OFF)
SELECT t4.*
FROM (SELECT t1.*, t2.a AS a1 FROM sj t1, sj t2 WHERE t1.b = t2.b) AS t3
JOIN sj t4 ON (t4.a = t3.a) WHERE t3.a1 = 42;
           QUERY PLAN            
---------------------------------
 Nested Loop
   Join Filter: (t1.b = t2.b)
   ->  Seq Scan on sj t2
         Filter: (a = 42)
   ->  Seq Scan on sj t1
         Filter: (a IS NOT NULL)
(6 rows)

SELECT t4.*
FROM (SELECT t1.*, t2.a AS a1 FROM sj t1, sj t2 WHERE t1.b = t2.b) AS t3
JOIN sj t4 ON (t4.a = t3.a) WHERE t3.a1 = 42;
 a | b | c 
---+---+---
(0 rows)

-- Functional index
CREATE UNIQUE INDEX sj_fn_idx ON sj((a * a));
-- Remove SJ
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2
 WHERE j1.b = j2.b AND j1.a*j1.a = 1 AND j2.a*j2.a = 1;
                  QUERY PLAN                   
-----------------------------------------------
 Seq Scan on sj j2
   Filter: ((b IS NOT NULL) AND ((a * a) = 1))
(2 rows)

-- Don't remove SJ
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2
 WHERE j1.b = j2.b AND j1.a*j1.a = 1 AND j2.a*j2.a = 2;
          QUERY PLAN           
-------------------------------
 Nested Loop
   Join Filter: (j1.b = j2.b)
   ->  Seq Scan on sj j1
         Filter: ((a * a) = 1)
   ->  Seq Scan on sj j2
         Filter: ((a * a) = 2)
(6 rows)

-- Restriction contains expressions in both sides, Remove SJ.
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2
WHERE j1.b = j2.b
  AND (j1.a*j1.a) = (EXTRACT(DOW FROM current_timestamp(0))/15 + 3)::int
  AND (EXTRACT(DOW FROM current_timestamp(0))/15 + 3)::int = (j2.a*j2.a);
                                                            QUERY PLAN                                                            
----------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on sj j2
   Filter: ((b IS NOT NULL) AND ((a * a) = (((EXTRACT(dow FROM CURRENT_TIMESTAMP(0)) / '15'::numeric) + '3'::numeric))::integer))
(2 rows)

-- Empty set of rows should be returned
SELECT * FROM sj j1, sj j2
WHERE j1.b = j2.b
  AND (j1.a*j1.a) = (EXTRACT(DOW FROM current_timestamp(0))/15 + 3)::int
  AND (EXTRACT(DOW FROM current_timestamp(0))/15 + 3)::int = (j2.a*j2.a);
 a | b | c | a | b | c 
---+---+---+---+---+---
(0 rows)

-- Restriction contains volatile function - disable SJE feature.
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2
WHERE j1.b = j2.b
  AND (j1.a*j1.c/3) = (random()/3 + 3)::int
  AND (random()/3 + 3)::int = (j2.a*j2.c/3);
                                                QUERY PLAN                                                 
-----------------------------------------------------------------------------------------------------------
 Nested Loop
   Join Filter: (j1.b = j2.b)
   ->  Seq Scan on sj j1
         Filter: (((a * c) / 3) = (((random() / '3'::double precision) + '3'::double precision))::integer)
   ->  Seq Scan on sj j2
         Filter: ((((random() / '3'::double precision) + '3'::double precision))::integer = ((a * c) 3))
(6 rows)

-- Return one row
SELECT * FROM sj j1, sj j2
WHERE j1.b = j2.b
  AND (j1.a*j1.c/3) = (random()/3 + 3)::int
  AND (random()/3 + 3)::int = (j2.a*j2.c/3);
 a | b | c | a | b | c 
---+---+---+---+---+---
 3 | 1 | 3 | 3 | 1 | 3
(1 row)

-- Multiple filters
CREATE UNIQUE INDEX sj_temp_idx1 ON sj(a,b,c);
-- Remove SJ
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2
 WHERE j1.b = j2.b AND j1.a = 2 AND j1.c = 3 AND j2.a = 2 AND 3 = j2.c;
                     QUERY PLAN                      
-----------------------------------------------------
 Seq Scan on sj j2
   Filter: ((b IS NOT NULL) AND (a = 2) AND (c = 3))
(2 rows)

-- Don't remove SJ
EXPLAIN (COSTS OFF)
 SELECT * FROM sj j1, sj j2
 WHERE j1.b = j2.b AND 2 = j1.a AND j1.c = 3 AND j2.a = 1 AND 3 = j2.c;
              QUERY PLAN               
---------------------------------------
 Nested Loop
   Join Filter: (j1.b = j2.b)
   ->  Seq Scan on sj j1
         Filter: ((2 = a) AND (c = 3))
   ->  Seq Scan on sj j2
         Filter: ((c = 3) AND (a = 1))
(6 rows)

CREATE UNIQUE INDEX sj_temp_idx ON sj(a,b);
-- Don't remove SJ
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND j1.a = 2;
          QUERY PLAN          
------------------------------
 Nested Loop
   Join Filter: (j1.b = j2.b)
   ->  Seq Scan on sj j1
         Filter: (a = 2)
   ->  Seq Scan on sj j2
(5 rows)

-- Don't remove SJ
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND 2 = j2.a;
          QUERY PLAN          
------------------------------
 Nested Loop
   Join Filter: (j1.b = j2.b)
   ->  Seq Scan on sj j2
         Filter: (2 = a)
   ->  Seq Scan on sj j1
(5 rows)

-- Don't remove SJ
EXPLAIN (COSTS OFF)
SELECT * FROM sj j1, sj j2 WHERE j1.b = j2.b AND (j1.a = 1 OR j2.a = 1);
                          QUERY PLAN                           
---------------------------------------------------------------
 Nested Loop
   Join Filter: ((j1.b = j2.b) AND ((j1.a = 1) OR (j2.a = 1)))
   ->  Seq Scan on sj j1
   ->  Materialize
         ->  Seq Scan on sj j2
(5 rows)

DROP INDEX sj_fn_idx, sj_temp_idx1, sj_temp_idx;
-- Test that OR predicated are updated correctly after join removal
CREATE TABLE tab_with_flag ( id INT PRIMARY KEY, is_flag SMALLINT);
CREATE INDEX idx_test_is_flag ON tab_with_flag (is_flag);
EXPLAIN (COSTS OFF)
SELECT COUNT(*) FROM tab_with_flag
WHERE
 (is_flag IS NULL OR is_flag = 0)
 AND id IN (SELECT id FROM tab_with_flag WHERE id IN (23));
                        QUERY PLAN                         
-----------------------------------------------------------
 Aggregate
   ->  Bitmap Heap Scan on tab_with_flag
         Recheck Cond: (id = ANY ('{2,3}'::integer[]))
         Filter: ((is_flag IS NULL) OR (is_flag = 0))
         ->  Bitmap Index Scan on tab_with_flag_pkey
               Index Cond: (id = ANY ('{2,3}'::integer[]))
(6 rows)

DROP TABLE tab_with_flag;
-- HAVING clause
explain (costs off)
select p.b from sj p join sj q on p.a = q.a group by p.b having sum(p.a) = 1;
           QUERY PLAN            
---------------------------------
 HashAggregate
   Group Key: q.b
   Filter: (sum(q.a) = 1)
   ->  Seq Scan on sj q
         Filter: (a IS NOT NULL)
(5 rows)

-- update lateral references and range table entry reference
explain (verbose, costs off)
select 1 from (select x.* from sj x, sj y where x.a = y.a) q,
  lateral generate_series(1, q.a) gs(i);
                      QUERY PLAN                      
------------------------------------------------------
 Nested Loop
   Output: 1
   ->  Seq Scan on public.sj y
         Output: y.a, y.b, y.c
         Filter: (y.a IS NOT NULL)
   ->  Function Scan on pg_catalog.generate_series gs
         Output: gs.i
         Function Call: generate_series(1, y.a)
(8 rows)

explain (verbose, costs off)
select 1 from (select y.* from sj x, sj y where x.a = y.a) q,
  lateral generate_series(1, q.a) gs(i);
                      QUERY PLAN                      
------------------------------------------------------
 Nested Loop
   Output: 1
   ->  Seq Scan on public.sj y
         Output: y.a, y.b, y.c
         Filter: (y.a IS NOT NULL)
   ->  Function Scan on pg_catalog.generate_series gs
         Output: gs.i
         Function Call: generate_series(1, y.a)
(8 rows)

-- Test that a non-EC-derived join clause is processed correctly. Use an
-- outer join so that we can't form an EC.
explain (costs off) select * from sj p join sj q on p.a = q.a
  left join sj r on p.a + q.a = r.a;
             QUERY PLAN             
------------------------------------
 Nested Loop Left Join
   Join Filter: ((q.a + q.a) = r.a)
   ->  Seq Scan on sj q
         Filter: (a IS NOT NULL)
   ->  Materialize
         ->  Seq Scan on sj r
(6 rows)

-- FIXME this constant false filter doesn't look good. Should we merge
-- equivalence classes?
explain (costs off)
select * from sj p, sj q where p.a = q.a and p.b = 1 and q.b = 2;
                     QUERY PLAN                      
-----------------------------------------------------
 Seq Scan on sj q
   Filter: ((a IS NOT NULL) AND (b = 2) AND (b = 1))
(2 rows)

-- Check that attr_needed is updated correctly after self-join removal. In this
-- test, the join of j1 with j2 is removed. k1.b is required at either j1 or j2.
-- If this info is lost, join targetlist for (k1, k2) will not contain k1.b.
-- Use index scan for k1 so that we don't get 'b' from physical tlist used for
-- seqscan. Also disable reordering of joins because this test depends on a
-- particular join tree.
create table sk (a int, b int);
create index on sk(a);
set join_collapse_limit to 1;
set enable_seqscan to off;
explain (costs off) select 1 from
 (sk k1 join sk k2 on k1.a = k2.a)
 join (sj j1 join sj j2 on j1.a = j2.a) on j1.b = k1.b;
                     QUERY PLAN                      
-----------------------------------------------------
 Nested Loop
   Join Filter: (k1.b = j2.b)
   ->  Nested Loop
         ->  Index Scan using sk_a_idx on sk k1
         ->  Index Only Scan using sk_a_idx on sk k2
               Index Cond: (a = k1.a)
   ->  Materialize
         ->  Index Scan using sj_a_key on sj j2
               Index Cond: (a IS NOT NULL)
(9 rows)

explain (costs off) select 1 from
 (sk k1 join sk k2 on k1.a = k2.a)
 join (sj j1 join sj j2 on j1.a = j2.a) on j2.b = k1.b;
                     QUERY PLAN                      
-----------------------------------------------------
 Nested Loop
   Join Filter: (k1.b = j2.b)
   ->  Nested Loop
         ->  Index Scan using sk_a_idx on sk k1
         ->  Index Only Scan using sk_a_idx on sk k2
               Index Cond: (a = k1.a)
   ->  Materialize
         ->  Index Scan using sj_a_key on sj j2
               Index Cond: (a IS NOT NULL)
(9 rows)

reset join_collapse_limit;
reset enable_seqscan;
-- Check that clauses from the join filter list is not lost on the self-join removal
CREATE TABLE emp1 (id SERIAL PRIMARY KEY NOT NULL, code int);
EXPLAIN (VERBOSE, COSTS OFF)
SELECT * FROM emp1 e1, emp1 e2 WHERE e1.id = e2.id AND e2.code <> e1.code;
                QUERY PLAN                
------------------------------------------
 Seq Scan on public.emp1 e2
   Output: e2.id, e2.code, e2.id, e2.code
   Filter: (e2.code <> e2.code)
(3 rows)

-- Shuffle self-joined relations. Only in the case of iterative deletion
-- attempts explains of these queries will be identical.
CREATE UNIQUE INDEX ON emp1((id*id));
EXPLAIN (COSTS OFF)
SELECT count(*) FROM emp1 c1, emp1 c2, emp1 c3
WHERE c1.id=c2.id AND c1.id*c2.id=c3.id*c3.id;
               QUERY PLAN                
-----------------------------------------
 Aggregate
   ->  Seq Scan on emp1 c3
         Filter: ((id * id) IS NOT NULL)
(3 rows)

EXPLAIN (COSTS OFF)
SELECT count(*) FROM emp1 c1, emp1 c2, emp1 c3
WHERE c1.id=c3.id AND c1.id*c3.id=c2.id*c2.id;
               QUERY PLAN                
-----------------------------------------
 Aggregate
   ->  Seq Scan on emp1 c3
         Filter: ((id * id) IS NOT NULL)
(3 rows)

EXPLAIN (COSTS OFF)
SELECT count(*) FROM emp1 c1, emp1 c2, emp1 c3
WHERE c3.id=c2.id AND c3.id*c2.id=c1.id*c1.id;
               QUERY PLAN                
-----------------------------------------
 Aggregate
   ->  Seq Scan on emp1 c3
         Filter: ((id * id) IS NOT NULL)
(3 rows)

-- Check the usage of a parse tree by the set operations (bug #18170)
EXPLAIN (COSTS OFF)
SELECT c1.code FROM emp1 c1 LEFT JOIN emp1 c2 ON c1.id = c2.id
WHERE c2.id IS NOT NULL
EXCEPT ALL
SELECT c3.code FROM emp1 c3;
        QUERY PLAN         
---------------------------
 HashSetOp Except All
   ->  Seq Scan on emp1 c2
   ->  Seq Scan on emp1 c3
(3 rows)

-- Check that SJE removes references from PHVs correctly
explain (costs off)
select * from emp1 t1 left join
    (select coalesce(t3.code, 1) from emp1 t2
        left join (emp1 t3 join emp1 t4 on t3.id = t4.id)
        on true)
on true;
                 QUERY PLAN                  
---------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on emp1 t1
   ->  Materialize
         ->  Nested Loop Left Join
               ->  Seq Scan on emp1 t2
               ->  Materialize
                     ->  Seq Scan on emp1 t4
(7 rows)

-- Try PHV, which could potentially be removed completely by SJE, but that's
-- not implemented yet.
explain (verbose, costs off)
select 1 from emp1 t1 left join
    ((select 1 as x, * from emp1 t2) s1 inner join
        (select * from emp1 t3) s2 on s1.id = s2.id)
    on true
where s1.x = 1;
               QUERY PLAN               
----------------------------------------
 Nested Loop
   Output: 1
   ->  Seq Scan on public.emp1 t1
         Output: t1.id, t1.code
   ->  Materialize
         Output: t3.id
         ->  Seq Scan on public.emp1 t3
               Output: t3.id
               Filter: (1 = 1)
(9 rows)

-- Check that PHVs do not impose any constraints on removing self joins
explain (verbose, costs off)
select * from emp1 t1 join emp1 t2 on t1.id = t2.id left join
    lateral (select t1.id as t1id, * from generate_series(1,1) t3) s on true;
                        QUERY PLAN                        
----------------------------------------------------------
 Nested Loop Left Join
   Output: t2.id, t2.code, t2.id, t2.code, (t2.id), t3.t3
   ->  Seq Scan on public.emp1 t2
         Output: t2.id, t2.code
   ->  Function Scan on pg_catalog.generate_series t3
         Output: t3.t3, t2.id
         Function Call: generate_series(11)
(7 rows)

explain (verbose, costs off)
select * from generate_series(1,10) t1(id) left join
    lateral (select t1.id as t1id, t2.id from emp1 t2 join emp1 t3 on t2.id = t3.id)
on true;
                      QUERY PLAN                      
------------------------------------------------------
 Nested Loop Left Join
   Output: t1.id, (t1.id), t3.id
   ->  Function Scan on pg_catalog.generate_series t1
         Output: t1.id
         Function Call: generate_series(110)
   ->  Seq Scan on public.emp1 t3
         Output: t3.id, t1.id
(7 rows)

-- This is a degenerate case of PHV usage: it is evaluated and needed inside
-- a baserel scan operation that the SJE removes.  The PHV in this test should
-- be in the filter of parameterized Index Scan: the replace_nestloop_params()
-- code will detect if the placeholder list doesn't have a reference to this
-- parameter.
--
-- NOTE:  enable_hashjoin and enable_mergejoin must be disabled.
CREATE TABLE tbl_phv(x int, y int PRIMARY KEY);
CREATE INDEX tbl_phv_idx ON tbl_phv(x);
INSERT INTO tbl_phv (x, y)
  SELECT gs, gs FROM generate_series(1,100) AS gs;
VACUUM ANALYZE tbl_phv;
EXPLAIN (COSTS OFF, VERBOSE)
SELECT 1 FROM tbl_phv t1 LEFT JOIN
  (SELECT 1 extra, x, y FROM tbl_phv tl) t3 JOIN
    (SELECT y FROM tbl_phv tr) t4
  ON t4.y = t3.y
ON true WHERE t3.extra IS NOT NULL AND t3.x = t1.x % 2;
                       QUERY PLAN                        
---------------------------------------------------------
 Nested Loop
   Output: 1
   ->  Seq Scan on public.tbl_phv t1
         Output: t1.x, t1.y
   ->  Index Scan using tbl_phv_idx on public.tbl_phv tr
         Output: tr.x, tr.y
         Index Cond: (tr.x = (t1.x % 2))
         Filter: (1 IS NOT NULL)
(8 rows)

DROP TABLE IF EXISTS tbl_phv;
-- Check that SJE replaces join clauses involving the removed rel correctly
explain (costs off)
select * from emp1 t1
   inner join emp1 t2 on t1.id = t2.id
    left join emp1 t3 on t1.id > 1 and t1.id < 2;
                  QUERY PLAN                  
----------------------------------------------
 Nested Loop Left Join
   Join Filter: ((t2.id > 1) AND (t2.id < 2))
   ->  Seq Scan on emp1 t2
   ->  Materialize
         ->  Seq Scan on emp1 t3
(5 rows)

-- Check that SJE doesn't replace the target relation
EXPLAIN (COSTS OFF)
WITH t1 AS (SELECT * FROM emp1)
UPDATE emp1 SET code = t1.code + 1 FROM t1
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
                      QUERY PLAN                       
-------------------------------------------------------
 Update on emp1
   ->  Nested Loop
         ->  Seq Scan on emp1
         ->  Index Scan using emp1_pkey on emp1 emp1_1
               Index Cond: (id = emp1.id)
(5 rows)

-- Check that SJE correctly replaces relations in OR-clauses
EXPLAIN (COSTS OFF)
SELECT * FROM emp1 t1
   INNER JOIN emp1 t2 ON t1.id = t2.id
    LEFT JOIN emp1 t3 ON t1.code = 1 AND (t2.code = t3.code OR t2.code = 1);
                                QUERY PLAN                                 
---------------------------------------------------------------------------
 Nested Loop Left Join
   Join Filter: ((t2.code = 1) AND ((t2.code = t3.code) OR (t2.code = 1)))
   ->  Seq Scan on emp1 t2
   ->  Materialize
         ->  Seq Scan on emp1 t3
(5 rows)

    INSERT INTO emp1 VALUES (11), (21);
WITH t1 AS (SELECT * FROM emp1)
UPDATE emp1 SET code = t1.code + 1 FROM t1
WHERE t1.id = emp1.id RETURNING emp1.id, emp1.code, t1.code;
 id | code | code 
----+------+------
  1 |    2 |    1
  2 |    2 |    1
(2 rows)

TRUNCATE emp1;
EXPLAIN (COSTS OFF)
UPDATE sj sq SET b = 1 FROM sj as sz WHERE sq.a = sz.a;
             QUERY PLAN              
-------------------------------------
 Update on sj sq
   ->  Nested Loop
         Join Filter: (sq.a = sz.a)
         ->  Seq Scan on sj sq
         ->  Materialize
               ->  Seq Scan on sj sz
(6 rows)

CREATE RULE sj_del_rule AS ON DELETE TO sj
  DO INSTEAD
    UPDATE sj SET a = 1 WHERE a = old.a;
EXPLAIN (COSTS OFF) DELETE FROM sj;
              QUERY PLAN              
--------------------------------------
 Update on sj sj_1
   ->  Nested Loop
         Join Filter: (sj.a = sj_1.a)
         ->  Seq Scan on sj sj_1
         ->  Materialize
               ->  Seq Scan on sj
(6 rows)

DROP RULE sj_del_rule ON sj CASCADE;
-- Check that SJE does not mistakenly omit qual clauses (bug #18187)
insert into emp1 values (11);
explain (costs off)
select 1 from emp1 full join
    (select * from emp1 t1 join
        emp1 t2 join emp1 t3 on t2.id = t3.id
        on true
    where false) s on true
where false;
        QUERY PLAN        
--------------------------
 Result
   One-Time Filter: false
(2 rows)

select 1 from emp1 full join
    (select * from emp1 t1 join
        emp1 t2 join emp1 t3 on t2.id = t3.id
        on true
    where false) s on true
where false;
 ?column? 
----------
(0 rows)

-- Check that SJE does not mistakenly re-use knowledge of relation uniqueness
-- made with different set of quals
insert into emp1 values (21);
explain (costs off)
select * from emp1 t1 where exists (select * from emp1 t2
                                    where t2.id = t1.code and t2.code > 0);
                 QUERY PLAN                  
---------------------------------------------
 Nested Loop
   ->  Seq Scan on emp1 t1
   ->  Index Scan using emp1_pkey on emp1 t2
         Index Cond: (id = t1.code)
         Filter: (code > 0)
(5 rows)

select * from emp1 t1 where exists (select * from emp1 t2
                                    where t2.id = t1.code and t2.code > 0);
 id | code 
----+------
  1 |    1
  2 |    1
(2 rows)

-- We can remove the join even if we find the join can't duplicate rows and
-- the base quals of each side are different.  In the following case we end up
-- moving quals over to s1 to make it so it can't match any rows.
create table sl(a int, b int, c int);
create unique index on sl(a, b);
vacuum analyze sl;
-- Both sides are unique, but base quals are different
explain (costs off)
select * from sl t1, sl t2 where t1.a = t2.a and t1.b = 1 and t2.b = 2;
          QUERY PLAN          
------------------------------
 Nested Loop
   Join Filter: (t1.a = t2.a)
   ->  Seq Scan on sl t1
         Filter: (b = 1)
   ->  Seq Scan on sl t2
         Filter: (b = 2)
(6 rows)

-- Check NullTest in baserestrictinfo list
explain (costs off)
select * from sl t1, sl t2
where t1.a = t2.a and t1.b = 1 and t2.b = 2
  and t1.c IS NOT NULL and t2.c IS NOT NULL
  and t2.b IS NOT NULL and t1.b IS NOT NULL
  and t1.a IS NOT NULL and t2.a IS NOT NULL;
                                      QUERY PLAN                                       
---------------------------------------------------------------------------------------
 Nested Loop
   Join Filter: (t1.a = t2.a)
   ->  Seq Scan on sl t1
         Filter: ((c IS NOT NULL) AND (b IS NOT NULL) AND (a IS NOT NULL) AND (b = 1))
   ->  Seq Scan on sl t2
         Filter: ((c IS NOT NULL) AND (b IS NOT NULL) AND (a IS NOT NULL) AND (b = 2))
(6 rows)

explain (verbose, costs off)
select * from sl t1, sl t2
where t1.b = t2.b and t2.a = 3 and t1.a = 3
  and t1.c IS NOT NULL and t2.c IS NOT NULL
  and t2.b IS NOT NULL and t1.b IS NOT NULL
  and t1.a IS NOT NULL and t2.a IS NOT NULL;
                                         QUERY PLAN                                          
---------------------------------------------------------------------------------------------
 Seq Scan on public.sl t2
   Output: t2.a, t2.b, t2.c, t2.a, t2.b, t2.c
   Filter: ((t2.c IS NOT NULL) AND (t2.b IS NOT NULL) AND (t2.a IS NOT NULL) AND (t2.a = 3))
(3 rows)

-- Join qual isn't mergejoinable, but inner is unique.
EXPLAIN (COSTS OFF)
SELECT n2.a FROM sj n1, sj n2 WHERE n1.a <> n2.a AND n2.a = 1;
          QUERY PLAN           
-------------------------------
 Nested Loop
   Join Filter: (n1.a <> n2.a)
   ->  Seq Scan on sj n2
         Filter: (a = 1)
   ->  Seq Scan on sj n1
(5 rows)

EXPLAIN (COSTS OFF)
SELECT * FROM
(SELECT n2.a FROM sj n1, sj n2 WHERE n1.a <> n2.a) q0, sl
WHERE q0.a = 1;
          QUERY PLAN           
-------------------------------
 Nested Loop
   Join Filter: (n1.a <> n2.a)
   ->  Nested Loop
         ->  Seq Scan on sl
         ->  Seq Scan on sj n2
               Filter: (a = 1)
   ->  Seq Scan on sj n1
(7 rows)

-- Do not forget to replace relid in bare Var join clause (bug #19435)
ALTER TABLE sl ADD COLUMN bool_col boolean;
EXPLAIN (COSTS OFF)
SELECT 1 AS c1 FROM sl sl1 LEFT JOIN (sl AS sl2 NATURAL JOIN sl AS sl3)
  ON sl2.bool_col LEFT JOIN sl AS sl4 ON sl2.bool_col;
                                                       QUERY PLAN                                                        
-------------------------------------------------------------------------------------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on sl sl1
   ->  Nested Loop Left Join
         Join Filter: sl3.bool_col
         ->  Seq Scan on sl sl3
               Filter: (bool_col AND (a IS NOT NULL) AND (b IS NOT NULL) AND (c IS NOT NULL) AND (bool_col IS NOT NULL))
         ->  Seq Scan on sl sl4
(7 rows)

-- Check optimization disabling if it will violate special join conditions.
-- Two identical joined relations satisfies self join removal conditions but
-- stay in different special join infos.
CREATE TABLE sj_t1 (id serial, a int);
CREATE TABLE sj_t2 (id serial, a int);
CREATE TABLE sj_t3 (id serial, a int);
CREATE TABLE sj_t4 (id serial, a int);
CREATE UNIQUE INDEX ON sj_t3 USING btree (a,id);
CREATE UNIQUE INDEX ON sj_t2 USING btree (id);
EXPLAIN (COSTS OFF)
SELECT * FROM sj_t1
JOIN (
 SELECT sj_t2.id AS id FROM sj_t2
 WHERE EXISTS
  (
  SELECT TRUE FROM sj_t3,sj_t4 WHERE sj_t3.a = 1 AND sj_t3.id = sj_t2.id
  )
 ) t2t3t4
ON sj_t1.id = t2t3t4.id
JOIN (
 SELECT sj_t2.id AS id FROM sj_t2
 WHERE EXISTS
  (
  SELECT TRUE FROM sj_t3,sj_t4 WHERE sj_t3.a = 1 AND sj_t3.id = sj_t2.id
  )
 ) _t2t3t4
ON sj_t1.id = _t2t3t4.id;
                                     QUERY PLAN                                      
-------------------------------------------------------------------------------------
 Nested Loop
   Join Filter: (sj_t3.id = sj_t1.id)
   ->  Nested Loop
         Join Filter: (sj_t2.id = sj_t3.id)
         ->  Nested Loop Semi Join
               ->  Nested Loop
                     ->  HashAggregate
                           Group Key: sj_t3.id
                           ->  Nested Loop
                                 ->  Seq Scan on sj_t4
                                 ->  Materialize
                                       ->  Bitmap Heap Scan on sj_t3
                                             Recheck Cond: (a = 1)
                                             ->  Bitmap Index Scan on sj_t3_a_id_idx
                                                   Index Cond: (a = 1)
                     ->  Index Only Scan using sj_t2_id_idx on sj_t2 sj_t2_1
                           Index Cond: (id = sj_t3.id)
               ->  Nested Loop
                     ->  Index Only Scan using sj_t3_a_id_idx on sj_t3 sj_t3_1
                           Index Cond: ((a = 1) AND (id = sj_t3.id))
                     ->  Seq Scan on sj_t4 sj_t4_1
         ->  Index Only Scan using sj_t2_id_idx on sj_t2
               Index Cond: (id = sj_t2_1.id)
   ->  Seq Scan on sj_t1
(24 rows)

--
-- Test RowMarks-related code
--
-- Both sides have explicit LockRows marks
EXPLAIN (COSTS OFF)
SELECT a1.a FROM sj a1,sj a2 WHERE (a1.a=a2.a) FOR UPDATE;
           QUERY PLAN            
---------------------------------
 LockRows
   ->  Seq Scan on sj a2
         Filter: (a IS NOT NULL)
(3 rows)

reset enable_hashjoin;
reset enable_mergejoin;
--
-- Test hints given on incorrect column references are useful
--
select t1.uunique1 from
  tenk1 t1 join tenk2 t2 on t1.two = t2.two; -- error, prefer "t1" suggestion
ERROR:  column t1.uunique1 does not exist
LINE 1: select t1.uunique1 from
               ^
HINT:  Perhaps you meant to reference the column "t1.unique1".
select t2.uunique1 from
  tenk1 t1 join tenk2 t2 on t1.two = t2.two; -- error, prefer "t2" suggestion
ERROR:  column t2.uunique1 does not exist
LINE 1: select t2.uunique1 from
               ^
HINT:  Perhaps you meant to reference the column "t2.unique1".
select uunique1 from
  tenk1 t1 join tenk2 t2 on t1.two = t2.two; -- error, suggest both at once
ERROR:  column "uunique1" does not exist
LINE 1: select uunique1 from
               ^
HINT:  Perhaps you meant to reference the column "t1.unique1" or the column "t2.unique1".
select ctid from
  tenk1 t1 join tenk2 t2 on t1.two = t2.two; -- error, need qualification
ERROR:  column "ctid" does not exist
LINE 1: select ctid from
               ^
DETAIL:  There are columns named "ctid", but they are in tables that cannot be referenced from this part of the query.
HINT:  Try using a table-qualified name.
--
-- Take care to reference the correct RTE
--
select atts.relid::regclass, s.* from pg_stats s join
    pg_attribute a on s.attname = a.attname and s.tablename =
    a.attrelid::regclass::text join (select unnest(indkey) attnum,
    indexrelid from pg_index i) atts on atts.attnum = a.attnum where
    schemaname != 'pg_catalog';
ERROR:  column atts.relid does not exist
LINE 1: select atts.relid::regclass, s.* from pg_stats s join
               ^
-- Test bug in rangetable flattening
explain (verbose, costs off)
select 1 from
  (select * from int8_tbl where q1 <> (select 42) offset 0) ss
where false;
        QUERY PLAN        
--------------------------
 Result
   Output: 1
   One-Time Filter: false
(3 rows)

--
-- Test LATERAL
--
select unique2, x.*
from tenk1 a, lateral (select * from int4_tbl b where f1 = a.unique1) x;
 unique2 | f1 
---------+----
    9998 |  0
(1 row)

explain (costs off)
  select unique2, x.*
  from tenk1 a, lateral (select * from int4_tbl b where f1 = a.unique1) x;
                   QUERY PLAN                    
-------------------------------------------------
 Nested Loop
   ->  Seq Scan on int4_tbl b
   ->  Index Scan using tenk1_unique1 on tenk1 a
         Index Cond: (unique1 = b.f1)
(4 rows)

select unique2, x.*
from int4_tbl x, lateral (select unique2 from tenk1 where f1 = unique1) ss;
 unique2 | f1 
---------+----
    9998 |  0
(1 row)

explain (costs off)
  select unique2, x.*
  from int4_tbl x, lateral (select unique2 from tenk1 where f1 = unique1) ss;
                  QUERY PLAN                   
-----------------------------------------------
 Nested Loop
   ->  Seq Scan on int4_tbl x
   ->  Index Scan using tenk1_unique1 on tenk1
         Index Cond: (unique1 = x.f1)
(4 rows)

explain (costs off)
  select unique2, x.*
  from int4_tbl x cross join lateral (select unique2 from tenk1 where f1 = unique1) ss;
                  QUERY PLAN                   
-----------------------------------------------
 Nested Loop
   ->  Seq Scan on int4_tbl x
   ->  Index Scan using tenk1_unique1 on tenk1
         Index Cond: (unique1 = x.f1)
(4 rows)

select unique2, x.*
from int4_tbl x left join lateral (select unique1, unique2 from tenk1 where f1 = unique1) ss on true;
 unique2 |     f1      
---------+-------------
    9998 |           0
         |      123456
         |     -123456
         |  2147483647
         | -2147483647
(5 rows)

explain (costs off)
  select unique2, x.*
  from int4_tbl x left join lateral (select unique1, unique2 from tenk1 where f1 = unique1) ss on true;
                  QUERY PLAN                   
-----------------------------------------------
 Nested Loop Left Join
   ->  Seq Scan on int4_tbl x
   ->  Index Scan using tenk1_unique1 on tenk1
         Index Cond: (unique1 = x.f1)
(4 rows)

-- check scoping of lateral versus parent references
-- the first of these should return int8_tbl.q2, the second int8_tbl.q1
select *, (select r from (select q1 as q2) x, (select q2 as r) y) from int8_tbl;
        q1        |        q2         |         r         
------------------+-------------------+-------------------
              123 |               456 |               456
              123 |  4567890123456789 |  4567890123456789
 4567890123456789 |               123 |               123
 4567890123456789 |  4567890123456789 |  4567890123456789
 4567890123456789 | -4567890123456789 | -4567890123456789
(5 rows)

select *, (select r from (select q1 as q2) x, lateral (select q2 as r) y) from int8_tbl;
        q1        |        q2         |        r         
------------------+-------------------+------------------
              123 |               456 |              123
              123 |  4567890123456789 |              123
 4567890123456789 |               123 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 | 4567890123456789
(5 rows)

-- lateral with function in FROM
select count(*) from tenk1 a, lateral generate_series(1,two) g;
 count 
-------
  5000
(1 row)

explain (costs off)
  select count(*) from tenk1 a, lateral generate_series(1,two) g;
                      QUERY PLAN                      
------------------------------------------------------
 Aggregate
   ->  Nested Loop
         ->  Seq Scan on tenk1 a
         ->  Memoize
               Cache Key: a.two
               Cache Mode: binary
               ->  Function Scan on generate_series g
(7 rows)

explain (costs off)
  select count(*) from tenk1 a cross join lateral generate_series(1,two) g;
                      QUERY PLAN                      
------------------------------------------------------
 Aggregate
   ->  Nested Loop
         ->  Seq Scan on tenk1 a
         ->  Memoize
               Cache Key: a.two
               Cache Mode: binary
               ->  Function Scan on generate_series g
(7 rows)

-- don't need the explicit LATERAL keyword for functions
explain (costs off)
  select count(*) from tenk1 a, generate_series(1,two) g;
                      QUERY PLAN                      
------------------------------------------------------
 Aggregate
   ->  Nested Loop
         ->  Seq Scan on tenk1 a
         ->  Memoize
               Cache Key: a.two
               Cache Mode: binary
               ->  Function Scan on generate_series g
(7 rows)

-- lateral with UNION ALL subselect
explain (costs off)
  select * from generate_series(100,200) g,
    lateral (select * from int8_tbl a where g = q1 union all
             select * from int8_tbl b where g = q2) ss;
                QUERY PLAN                
------------------------------------------
 Nested Loop
   ->  Function Scan on generate_series g
   ->  Append
         ->  Seq Scan on int8_tbl a
               Filter: (g.g = q1)
         ->  Seq Scan on int8_tbl b
               Filter: (g.g = q2)
(7 rows)

select * from generate_series(100,200) g,
  lateral (select * from int8_tbl a where g = q1 union all
           select * from int8_tbl b where g = q2) ss;
  g  |        q1        |        q2        
-----+------------------+------------------
 123 |              123 |              456
 123 |              123 | 4567890123456789
 123 | 4567890123456789 |              123
(3 rows)

-- lateral with VALUES
explain (costs off)
  select count(*) from tenk1 a,
    tenk1 b join lateral (values(a.unique1)) ss(x) on b.unique2 = ss.x;
                         QUERY PLAN                         
------------------------------------------------------------
 Aggregate
   ->  Merge Join
         Merge Cond: (a.unique1 = b.unique2)
         ->  Index Only Scan using tenk1_unique1 on tenk1 a
         ->  Index Only Scan using tenk1_unique2 on tenk1 b
(5 rows)

select count(*) from tenk1 a,
  tenk1 b join lateral (values(a.unique1)) ss(x) on b.unique2 = ss.x;
 count 
-------
 10000
(1 row)

-- lateral with VALUES, no flattening possible
explain (costs off)
  select count(*) from tenk1 a,
    tenk1 b join lateral (values(a.unique1),(-1)) ss(x) on b.unique2 = ss.x;
                            QUERY PLAN                            
------------------------------------------------------------------
 Aggregate
   ->  Nested Loop
         ->  Nested Loop
               ->  Index Only Scan using tenk1_unique1 on tenk1 a
               ->  Values Scan on "*VALUES*"
         ->  Memoize
               Cache Key: "*VALUES*".column1
               Cache Mode: logical
               ->  Index Only Scan using tenk1_unique2 on tenk1 b
                     Index Cond: (unique2 = "*VALUES*".column1)
(10 rows)

select count(*) from tenk1 a,
  tenk1 b join lateral (values(a.unique1),(-1)) ss(x) on b.unique2 = ss.x;
 count 
-------
 10000
(1 row)

-- lateral injecting a strange outer join condition
explain (costs off)
  select * from int8_tbl a,
    int8_tbl x left join lateral (select a.q1 from int4_tbl y) ss(z)
      on x.q2 = ss.z
  order by a.q1, a.q2, x.q1, x.q2, ss.z;
                   QUERY PLAN                   
------------------------------------------------
 Sort
   Sort Key: a.q1, a.q2, x.q1, x.q2, (a.q1)
   ->  Nested Loop
         ->  Seq Scan on int8_tbl a
         ->  Hash Left Join
               Hash Cond: (x.q2 = (a.q1))
               ->  Seq Scan on int8_tbl x
               ->  Hash
                     ->  Seq Scan on int4_tbl y
(9 rows)

select * from int8_tbl a,
  int8_tbl x left join lateral (select a.q1 from int4_tbl y) ss(z)
    on x.q2 = ss.z
  order by a.q1, a.q2, x.q1, x.q2, ss.z;
        q1        |        q2         |        q1        |        q2         |        z         
------------------+-------------------+------------------+-------------------+------------------
              123 |               456 |              123 |               456 |                 
              123 |               456 |              123 |  4567890123456789 |                 
              123 |               456 | 4567890123456789 | -4567890123456789 |                 
              123 |               456 | 4567890123456789 |               123 |              123
              123 |               456 | 4567890123456789 |               123 |              123
              123 |               456 | 4567890123456789 |               123 |              123
              123 |               456 | 4567890123456789 |               123 |              123
              123 |               456 | 4567890123456789 |               123 |              123
              123 |               456 | 4567890123456789 |  4567890123456789 |                 
              123 |  4567890123456789 |              123 |               456 |                 
              123 |  4567890123456789 |              123 |  4567890123456789 |                 
              123 |  4567890123456789 | 4567890123456789 | -4567890123456789 |                 
              123 |  4567890123456789 | 4567890123456789 |               123 |              123
              123 |  4567890123456789 | 4567890123456789 |               123 |              123
              123 |  4567890123456789 | 4567890123456789 |               123 |              123
              123 |  4567890123456789 | 4567890123456789 |               123 |              123
              123 |  4567890123456789 | 4567890123456789 |               123 |              123
              123 |  4567890123456789 | 4567890123456789 |  4567890123456789 |                 
 4567890123456789 | -4567890123456789 |              123 |               456 |                 
 4567890123456789 | -4567890123456789 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 | 4567890123456789 | -4567890123456789 |                 
 4567890123456789 | -4567890123456789 | 4567890123456789 |               123 |                 
 4567890123456789 | -4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |               123 |              123 |               456 |                 
 4567890123456789 |               123 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 |               123 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 |               123 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 |               123 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 |               123 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 |               123 | 4567890123456789 | -4567890123456789 |                 
 4567890123456789 |               123 | 4567890123456789 |               123 |                 
 4567890123456789 |               123 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |               123 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |               123 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |               123 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |               123 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 |              123 |               456 |                 
 4567890123456789 |  4567890123456789 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 |              123 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 | -4567890123456789 |                 
 4567890123456789 |  4567890123456789 | 4567890123456789 |               123 |                 
 4567890123456789 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
(57 rows)

-- lateral reference to a join alias variable
select * from (select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1,
  lateral (select x) ss2(y);
 x | f1 | y 
---+----+---
 0 |  0 | 0
(1 row)

select * from (select f1 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1,
  lateral (values(x)) ss2(y);
      x      |     f1      |      y      
-------------+-------------+-------------
           0 |           0 |           0
      123456 |      123456 |      123456
     -123456 |     -123456 |     -123456
  2147483647 |  2147483647 |  2147483647
 -2147483647 | -2147483647 | -2147483647
(5 rows)

select * from ((select f1/2 as x from int4_tbl) ss1 join int4_tbl i4 on x = f1) j,
  lateral (select x) ss2(y);
 x | f1 | y 
---+----+---
 0 |  0 | 0
(1 row)

-- lateral references requiring pullup
select * from (values(1)) x(lb),
  lateral generate_series(lb,4) x4;
 lb | x4 
----+----
  1 |  1
  1 |  2
  1 |  3
  1 |  4
(4 rows)

select * from (select f1/1000000000 from int4_tbl) x(lb),
  lateral generate_series(lb,4) x4;
 lb | x4 
----+----
  0 |  0
  0 |  1
  0 |  2
  0 |  3
  0 |  4
  0 |  0
  0 |  1
  0 |  2
  0 |  3
  0 |  4
  0 |  0
  0 |  1
  0 |  2
  0 |  3
  0 |  4
  2 |  2
  2 |  3
  2 |  4
 -2 | -2
 -2 | -1
 -2 |  0
 -2 |  1
 -2 |  2
 -2 |  3
 -2 |  4
(25 rows)

select * from (values(1)) x(lb),
  lateral (values(lb)) y(lbcopy);
 lb | lbcopy 
----+--------
  1 |      1
(1 row)

select * from (values(1)) x(lb),
  lateral (select lb from int4_tbl) y(lbcopy);
 lb | lbcopy 
----+--------
  1 |      1
  1 |      1
  1 |      1
  1 |      1
  1 |      1
(5 rows)

select * from
  int8_tbl x left join (select q1,coalesce(q2,0) q2 from int8_tbl) y on x.q2 = y.q1,
  lateral (values(x.q1,y.q1,y.q2)) v(xq1,yq1,yq2);
        q1        |        q2         |        q1        |        q2         |       xq1        |       yq1        |        yq2        
------------------+-------------------+------------------+-------------------+------------------+------------------+-------------------
              123 |               456 |                  |                   |              123 |                  |                  
              123 |  4567890123456789 | 4567890123456789 | -4567890123456789 |              123 | 4567890123456789 | -4567890123456789
              123 |  4567890123456789 | 4567890123456789 |  4567890123456789 |              123 | 4567890123456789 |  4567890123456789
              123 |  4567890123456789 | 4567890123456789 |               123 |              123 | 4567890123456789 |               123
 4567890123456789 |               123 |              123 |  4567890123456789 | 4567890123456789 |              123 |  4567890123456789
 4567890123456789 |               123 |              123 |               456 | 4567890123456789 |              123 |               456
 4567890123456789 |  4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 |  4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |               123 | 4567890123456789 | 4567890123456789 |               123
 4567890123456789 | -4567890123456789 |                  |                   | 4567890123456789 |                  |                  
(10 rows)

select * from
  int8_tbl x left join (select q1,coalesce(q2,0) q2 from int8_tbl) y on x.q2 = y.q1,
  lateral (select x.q1,y.q1,y.q2) v(xq1,yq1,yq2);
        q1        |        q2         |        q1        |        q2         |       xq1        |       yq1        |        yq2        
------------------+-------------------+------------------+-------------------+------------------+------------------+-------------------
              123 |               456 |                  |                   |              123 |                  |                  
              123 |  4567890123456789 | 4567890123456789 | -4567890123456789 |              123 | 4567890123456789 | -4567890123456789
              123 |  4567890123456789 | 4567890123456789 |  4567890123456789 |              123 | 4567890123456789 |  4567890123456789
              123 |  4567890123456789 | 4567890123456789 |               123 |              123 | 4567890123456789 |               123
 4567890123456789 |               123 |              123 |  4567890123456789 | 4567890123456789 |              123 |  4567890123456789
 4567890123456789 |               123 |              123 |               456 | 4567890123456789 |              123 |               456
 4567890123456789 |  4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789 | 4567890123456789 | -4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 |  4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |               123 | 4567890123456789 | 4567890123456789 |               123
 4567890123456789 | -4567890123456789 |                  |                   | 4567890123456789 |                  |                  
(10 rows)

select x.* from
  int8_tbl x left join (select q1,coalesce(q2,0) q2 from int8_tbl) y on x.q2 = y.q1,
  lateral (select x.q1,y.q1,y.q2) v(xq1,yq1,yq2);
        q1        |        q2         
------------------+-------------------
              123 |               456
              123 |  4567890123456789
              123 |  4567890123456789
              123 |  4567890123456789
 4567890123456789 |               123
 4567890123456789 |               123
 4567890123456789 |  4567890123456789
 4567890123456789 |  4567890123456789
 4567890123456789 |  4567890123456789
 4567890123456789 | -4567890123456789
(10 rows)

select v.* from
  (int8_tbl x left join (select q1,coalesce(q2,0) q2 from int8_tbl) y on x.q2 = y.q1)
  left join int4_tbl z on z.f1 = x.q2,
  lateral (select x.q1,y.q1 union all select x.q2,y.q2) v(vx,vy);
        vx         |        vy         
-------------------+-------------------
               123 |                  
               456 |                  
               123 |  4567890123456789
  4567890123456789 | -4567890123456789
               123 |  4567890123456789
  4567890123456789 |  4567890123456789
               123 |  4567890123456789
  4567890123456789 |               123
  4567890123456789 |               123
               123 |  4567890123456789
  4567890123456789 |               123
               123 |               456
  4567890123456789 |  4567890123456789
  4567890123456789 | -4567890123456789
  4567890123456789 |  4567890123456789
  4567890123456789 |  4567890123456789
  4567890123456789 |  4567890123456789
  4567890123456789 |               123
  4567890123456789 |                  
 -4567890123456789 |                  
(20 rows)

select v.* from
  (int8_tbl x left join (select q1,(select coalesce(q2,0)) q2 from int8_tbl) y on x.q2 = y.q1)
  left join int4_tbl z on z.f1 = x.q2,
  lateral (select x.q1,y.q1 union all select x.q2,y.q2) v(vx,vy);
        vx         |        vy         
-------------------+-------------------
  4567890123456789 |               123
               123 |               456
  4567890123456789 |               123
               123 |  4567890123456789
  4567890123456789 |  4567890123456789
  4567890123456789 |               123
               123 |  4567890123456789
  4567890123456789 |               123
  4567890123456789 |  4567890123456789
  4567890123456789 |  4567890123456789
               123 |  4567890123456789
  4567890123456789 |  4567890123456789
  4567890123456789 |  4567890123456789
  4567890123456789 | -4567890123456789
               123 |  4567890123456789
  4567890123456789 | -4567890123456789
               123 |                  
               456 |                  
  4567890123456789 |                  
 -4567890123456789 |                  
(20 rows)

select v.* from
  (int8_tbl x left join (select q1,(select coalesce(q2,0)) q2 from int8_tbl) y on x.q2 = y.q1)
  left join int4_tbl z on z.f1 = x.q2,
  lateral (select x.q1,y.q1 from onerow union all select x.q2,y.q2 from onerow) v(vx,vy);
        vx         |        vy         
-------------------+-------------------
  4567890123456789 |               123
               123 |               456
  4567890123456789 |               123
               123 |  4567890123456789
  4567890123456789 |  4567890123456789
  4567890123456789 |               123
               123 |  4567890123456789
  4567890123456789 |               123
  4567890123456789 |  4567890123456789
  4567890123456789 |  4567890123456789
               123 |  4567890123456789
  4567890123456789 |  4567890123456789
  4567890123456789 |  4567890123456789
  4567890123456789 | -4567890123456789
               123 |  4567890123456789
  4567890123456789 | -4567890123456789
               123 |                  
               456 |                  
  4567890123456789 |                  
 -4567890123456789 |                  
(20 rows)

explain (verbose, costs off)
select * from
  int8_tbl a left join
  lateral (select *, a.q2 as x from int8_tbl b) ss on a.q2 = ss.q1;
                QUERY PLAN                
------------------------------------------
 Nested Loop Left Join
   Output: a.q1, a.q2, b.q1, b.q2, (a.q2)
   ->  Seq Scan on public.int8_tbl a
         Output: a.q1, a.q2
   ->  Seq Scan on public.int8_tbl b
         Output: b.q1, b.q2, a.q2
         Filter: (a.q2 = b.q1)
(7 rows)

select * from
  int8_tbl a left join
  lateral (select *, a.q2 as x from int8_tbl b) ss on a.q2 = ss.q1;
        q1        |        q2         |        q1        |        q2         |        x         
------------------+-------------------+------------------+-------------------+------------------
              123 |               456 |                  |                   |                 
              123 |  4567890123456789 | 4567890123456789 |               123 | 4567890123456789
              123 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
              123 |  4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789
 4567890123456789 |               123 |              123 |               456 |              123
 4567890123456789 |               123 |              123 |  4567890123456789 |              123
 4567890123456789 |  4567890123456789 | 4567890123456789 |               123 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 |                  |                   |                 
(10 rows)

explain (verbose, costs off)
select * from
  int8_tbl a left join
  lateral (select *, coalesce(a.q2, 42) as x from int8_tbl b) ss on a.q2 = ss.q1;
                            QUERY PLAN                            
------------------------------------------------------------------
 Nested Loop Left Join
   Output: a.q1, a.q2, b.q1, b.q2, (COALESCE(a.q2, '42'::bigint))
   ->  Seq Scan on public.int8_tbl a
         Output: a.q1, a.q2
   ->  Seq Scan on public.int8_tbl b
         Output: b.q1, b.q2, COALESCE(a.q2, '42'::bigint)
         Filter: (a.q2 = b.q1)
(7 rows)

select * from
  int8_tbl a left join
  lateral (select *, coalesce(a.q2, 42) as x from int8_tbl b) ss on a.q2 = ss.q1;
        q1        |        q2         |        q1        |        q2         |        x         
------------------+-------------------+------------------+-------------------+------------------
              123 |               456 |                  |                   |                 
              123 |  4567890123456789 | 4567890123456789 |               123 | 4567890123456789
              123 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
              123 |  4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789
 4567890123456789 |               123 |              123 |               456 |              123
 4567890123456789 |               123 |              123 |  4567890123456789 |              123
 4567890123456789 |  4567890123456789 | 4567890123456789 |               123 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |  4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 | -4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 |                  |                   |                 
(10 rows)

-- lateral can result in join conditions appearing below their
-- real semantic level
explain (verbose, costs off)
select * from int4_tbl i left join
  lateral (select * from int2_tbl j where i.f1 = j.f1) k on true;
                QUERY PLAN                 
-------------------------------------------
 Hash Left Join
   Output: i.f1, j.f1
   Hash Cond: (i.f1 = j.f1)
   ->  Seq Scan on public.int4_tbl i
         Output: i.f1
   ->  Hash
         Output: j.f1
         ->  Seq Scan on public.int2_tbl j
               Output: j.f1
(9 rows)

select * from int4_tbl i left join
  lateral (select * from int2_tbl j where i.f1 = j.f1) k on true;
     f1      | f1 
-------------+----
           0 |  0
      123456 |   
     -123456 |   
  2147483647 |   
 -2147483647 |   
(5 rows)

explain (verbose, costs off)
select * from int4_tbl i left join
  lateral (select coalesce(i) from int2_tbl j where i.f1 = j.f1) k on true;
             QUERY PLAN              
-------------------------------------
 Nested Loop Left Join
   Output: i.f1, (COALESCE(i.*))
   ->  Seq Scan on public.int4_tbl i
         Output: i.f1, i.*
   ->  Seq Scan on public.int2_tbl j
         Output: j.f1, COALESCE(i.*)
         Filter: (i.f1 = j.f1)
(7 rows)

select * from int4_tbl i left join
  lateral (select coalesce(i) from int2_tbl j where i.f1 = j.f1) k on true;
     f1      | coalesce 
-------------+----------
           0 | (0)
      123456 | 
     -123456 | 
  2147483647 | 
 -2147483647 | 
(5 rows)

explain (verbose, costs off)
select * from int4_tbl a,
  lateral (
    select * from int4_tbl b left join int8_tbl c on (b.f1 = q1 and a.f1 = q2)
  ) ss;
                   QUERY PLAN                    
-------------------------------------------------
 Nested Loop
   Output: a.f1, b.f1, c.q1, c.q2
   ->  Seq Scan on public.int4_tbl a
         Output: a.f1
   ->  Hash Left Join
         Output: b.f1, c.q1, c.q2
         Hash Cond: (b.f1 = c.q1)
         ->  Seq Scan on public.int4_tbl b
               Output: b.f1
         ->  Hash
               Output: c.q1, c.q2
               ->  Seq Scan on public.int8_tbl c
                     Output: c.q1, c.q2
                     Filter: (a.f1 = c.q2)
(14 rows)

select * from int4_tbl a,
  lateral (
    select * from int4_tbl b left join int8_tbl c on (b.f1 = q1 and a.f1 = q2)
  ) ss;
     f1      |     f1      | q1 | q2 
-------------+-------------+----+----
           0 |           0 |    |   
           0 |      123456 |    |   
           0 |     -123456 |    |   
           0 |  2147483647 |    |   
           0 | -2147483647 |    |   
      123456 |           0 |    |   
      123456 |      123456 |    |   
      123456 |     -123456 |    |   
      123456 |  2147483647 |    |   
      123456 | -2147483647 |    |   
     -123456 |           0 |    |   
     -123456 |      123456 |    |   
     -123456 |     -123456 |    |   
     -123456 |  2147483647 |    |   
     -123456 | -2147483647 |    |   
  2147483647 |           0 |    |   
  2147483647 |      123456 |    |   
  2147483647 |     -123456 |    |   
  2147483647 |  2147483647 |    |   
  2147483647 | -2147483647 |    |   
 -2147483647 |           0 |    |   
 -2147483647 |      123456 |    |   
 -2147483647 |     -123456 |    |   
 -2147483647 |  2147483647 |    |   
 -2147483647 | -2147483647 |    |   
(25 rows)

-- lateral reference in a PlaceHolderVar evaluated at join level
explain (verbose, costs off)
select * from
  int8_tbl a left join lateral
  (select b.q1 as bq1, c.q1 as cq1, least(a.q1,b.q1,c.q1) from
   int8_tbl b cross join int8_tbl c) ss
  on a.q2 = ss.bq1;
                         QUERY PLAN                          
-------------------------------------------------------------
 Nested Loop Left Join
   Output: a.q1, a.q2, b.q1, c.q1, (LEAST(a.q1, b.q1, c.q1))
   ->  Seq Scan on public.int8_tbl a
         Output: a.q1, a.q2
   ->  Nested Loop
         Output: b.q1, c.q1, LEAST(a.q1, b.q1, c.q1)
         ->  Seq Scan on public.int8_tbl b
               Output: b.q1, b.q2
               Filter: (a.q2 = b.q1)
         ->  Seq Scan on public.int8_tbl c
               Output: c.q1, c.q2
(11 rows)

select * from
  int8_tbl a left join lateral
  (select b.q1 as bq1, c.q1 as cq1, least(a.q1,b.q1,c.q1) from
   int8_tbl b cross join int8_tbl c) ss
  on a.q2 = ss.bq1;
        q1        |        q2         |       bq1        |       cq1        |      least       
------------------+-------------------+------------------+------------------+------------------
              123 |               456 |                  |                  |                 
              123 |  4567890123456789 | 4567890123456789 |              123 |              123
              123 |  4567890123456789 | 4567890123456789 |              123 |              123
              123 |  4567890123456789 | 4567890123456789 | 4567890123456789 |              123
              123 |  4567890123456789 | 4567890123456789 | 4567890123456789 |              123
              123 |  4567890123456789 | 4567890123456789 | 4567890123456789 |              123
              123 |  4567890123456789 | 4567890123456789 |              123 |              123
              123 |  4567890123456789 | 4567890123456789 |              123 |              123
              123 |  4567890123456789 | 4567890123456789 | 4567890123456789 |              123
              123 |  4567890123456789 | 4567890123456789 | 4567890123456789 |              123
              123 |  4567890123456789 | 4567890123456789 | 4567890123456789 |              123
              123 |  4567890123456789 | 4567890123456789 |              123 |              123
              123 |  4567890123456789 | 4567890123456789 |              123 |              123
              123 |  4567890123456789 | 4567890123456789 | 4567890123456789 |              123
              123 |  4567890123456789 | 4567890123456789 | 4567890123456789 |              123
              123 |  4567890123456789 | 4567890123456789 | 4567890123456789 |              123
 4567890123456789 |               123 |              123 |              123 |              123
 4567890123456789 |               123 |              123 |              123 |              123
 4567890123456789 |               123 |              123 | 4567890123456789 |              123
 4567890123456789 |               123 |              123 | 4567890123456789 |              123
 4567890123456789 |               123 |              123 | 4567890123456789 |              123
 4567890123456789 |               123 |              123 |              123 |              123
 4567890123456789 |               123 |              123 |              123 |              123
 4567890123456789 |               123 |              123 | 4567890123456789 |              123
 4567890123456789 |               123 |              123 | 4567890123456789 |              123
 4567890123456789 |               123 |              123 | 4567890123456789 |              123
 4567890123456789 |  4567890123456789 | 4567890123456789 |              123 |              123
 4567890123456789 |  4567890123456789 | 4567890123456789 |              123 |              123
 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |              123 |              123
 4567890123456789 |  4567890123456789 | 4567890123456789 |              123 |              123
 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 |              123 |              123
 4567890123456789 |  4567890123456789 | 4567890123456789 |              123 |              123
 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789
 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789 | 4567890123456789
 4567890123456789 | -4567890123456789 |                  |                  |                 
(42 rows)

-- case requiring nested PlaceHolderVars
explain (verbose, costs off)
select * from
  int8_tbl c left join (
    int8_tbl a left join (select q1, coalesce(q2,42) as x from int8_tbl b) ss1
      on a.q2 = ss1.q1
    cross join
    lateral (select q1, coalesce(ss1.x,q2) as y from int8_tbl d) ss2
  ) on c.q2 = ss2.q1,
  lateral (select ss2.y offset 0) ss3;
                                                                                     QUERY PLAN                                                                                     
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop
   Output: c.q1, c.q2, a.q1, a.q2, b.q1, (COALESCE(b.q2, '42'::bigint)), d.q1, (COALESCE((COALESCE(b.q2, '42'::bigint)), d.q2)), ((COALESCE((COALESCE(b.q2, '42'::bigint)), d.q2)))
   ->  Hash Right Join
         Output: c.q1, c.q2, a.q1, a.q2, b.q1, (COALESCE(b.q2, '42'::bigint)), d.q1, (COALESCE((COALESCE(b.q2, '42'::bigint)), d.q2))
         Hash Cond: (d.q1 = c.q2)
         ->  Nested Loop
               Output: a.q1, a.q2, b.q1, (COALESCE(b.q2, '42'::bigint)), d.q1, (COALESCE((COALESCE(b.q2, '42'::bigint)), d.q2))
               ->  Hash Left Join
                     Output: a.q1, a.q2, b.q1, (COALESCE(b.q2, '42'::bigint))
                     Hash Cond: (a.q2 = b.q1)
                     ->  Seq Scan on public.int8_tbl a
                           Output: a.q1, a.q2
                     ->  Hash
                           Output: b.q1, (COALESCE(b.q2, '42'::bigint))
                           ->  Seq Scan on public.int8_tbl b
                                 Output: b.q1, COALESCE(b.q2, '42'::bigint)
               ->  Seq Scan on public.int8_tbl d
                     Output: d.q1, COALESCE((COALESCE(b.q2, '42'::bigint)), d.q2)
         ->  Hash
               Output: c.q1, c.q2
               ->  Seq Scan on public.int8_tbl c
                     Output: c.q1, c.q2
   ->  Result
         Output: (COALESCE((COALESCE(b.q2, '42'::bigint)), d.q2))
(24 rows)

-- another case requiring nested PlaceHolderVars
explain (verbose, costs off)
select * from
  (select 0 as val0) as ss0
  left join (select 1 as val) as ss1 on true
  left join lateral (select ss1.val as val_filtered where false) as ss2 on true;
           QUERY PLAN           
--------------------------------
 Nested Loop Left Join
   Output: 0, (1), ((1))
   Join Filter: false
   ->  Result
         Output: 1
   ->  Result
         Output: (1)
         One-Time Filter: false
(8 rows)

select * from
  (select 0 as val0) as ss0
  left join (select 1 as val) as ss1 on true
  left join lateral (select ss1.val as val_filtered where false) as ss2 on true;
 val0 | val | val_filtered 
------+-----+--------------
    0 |   1 |             
(1 row)

-- case that breaks the old ph_may_need optimization
explain (verbose, costs off)
select c.*,a.*,ss1.q1,ss2.q1,ss3.* from
  int8_tbl c left join (
    int8_tbl a left join
      (select q1, coalesce(q2,f1) as x from int8_tbl b, int4_tbl b2
       where q1 < f1) ss1
      on a.q2 = ss1.q1
    cross join
    lateral (select q1, coalesce(ss1.x,q2) as y from int8_tbl d) ss2
  ) on c.q2 = ss2.q1,
  lateral (select * from int4_tbl i where ss2.y > f1) ss3;
                                               QUERY PLAN                                                
---------------------------------------------------------------------------------------------------------
 Nested Loop
   Output: c.q1, c.q2, a.q1, a.q2, b.q1, d.q1, i.f1
   Join Filter: ((COALESCE((COALESCE(b.q2, (b2.f1)::bigint)), d.q2)) > i.f1)
   ->  Hash Right Join
         Output: c.q1, c.q2, a.q1, a.q2, b.q1, d.q1, (COALESCE((COALESCE(b.q2, (b2.f1)::bigint)), d.q2))
         Hash Cond: (d.q1 = c.q2)
         ->  Nested Loop
               Output: a.q1, a.q2, b.q1, d.q1, (COALESCE((COALESCE(b.q2, (b2.f1)::bigint)), d.q2))
               ->  Hash Right Join
                     Output: a.q1, a.q2, b.q1, (COALESCE(b.q2, (b2.f1)::bigint))
                     Hash Cond: (b.q1 = a.q2)
                     ->  Nested Loop
                           Output: b.q1, COALESCE(b.q2, (b2.f1)::bigint)
                           Join Filter: (b.q1 < b2.f1)
                           ->  Seq Scan on public.int8_tbl b
                                 Output: b.q1, b.q2
                           ->  Materialize
                                 Output: b2.f1
                                 ->  Seq Scan on public.int4_tbl b2
                                       Output: b2.f1
                     ->  Hash
                           Output: a.q1, a.q2
                           ->  Seq Scan on public.int8_tbl a
                                 Output: a.q1, a.q2
               ->  Seq Scan on public.int8_tbl d
                     Output: d.q1, COALESCE((COALESCE(b.q2, (b2.f1)::bigint)), d.q2)
         ->  Hash
               Output: c.q1, c.q2
               ->  Seq Scan on public.int8_tbl c
                     Output: c.q1, c.q2
   ->  Materialize
         Output: i.f1
         ->  Seq Scan on public.int4_tbl i
               Output: i.f1
(34 rows)

-- check processing of postponed quals (bug #9041)
explain (verbose, costs off)
select * from
  (select 1 as x offset 0) x cross join (select 2 as y offset 0) y
  left join lateral (
    select * from (select 3 as z offset 0) z where z.z = x.x
  ) zz on zz.z = y.y;
                  QUERY PLAN                  
----------------------------------------------
 Nested Loop Left Join
   Output: (1), (2), (3)
   Join Filter: (((3) = (1)) AND ((3) = (2)))
   ->  Nested Loop
         Output: (1), (2)
         ->  Result
               Output: 1
         ->  Result
               Output: 2
   ->  Result
         Output: 3
(11 rows)

-- a new postponed-quals issue (bug #17768)
explain (costs off)
select * from int4_tbl t1,
  lateral (select * from int4_tbl t2 inner join int4_tbl t3 on t1.f1 = 1
           inner join (int4_tbl t4 left join int4_tbl t5 on true) on true) ss;
                   QUERY PLAN                    
-------------------------------------------------
 Nested Loop Left Join
   ->  Nested Loop
         ->  Nested Loop
               ->  Nested Loop
                     ->  Seq Scan on int4_tbl t1
                           Filter: (f1 = 1)
                     ->  Seq Scan on int4_tbl t2
               ->  Materialize
                     ->  Seq Scan on int4_tbl t3
         ->  Materialize
               ->  Seq Scan on int4_tbl t4
   ->  Materialize
         ->  Seq Scan on int4_tbl t5
(13 rows)

-- check dummy rels with lateral references (bug #15694)
explain (verbose, costs off)
select * from int8_tbl i8 left join lateral
  (select *, i8.q2 from int4_tbl where false) ss on true;
              QUERY PLAN              
--------------------------------------
 Nested Loop Left Join
   Output: i8.q1, i8.q2, f1, (i8.q2)
   Join Filter: false
   ->  Seq Scan on public.int8_tbl i8
         Output: i8.q1, i8.q2
   ->  Result
         Output: f1, i8.q2
         One-Time Filter: false
(8 rows)

explain (verbose, costs off)
select * from int8_tbl i8 left join lateral
  (select *, i8.q2 from int4_tbl i1, int4_tbl i2 where false) ss on true;
               QUERY PLAN                
-----------------------------------------
 Nested Loop Left Join
   Output: i8.q1, i8.q2, f1, f1, (i8.q2)
   ->  Seq Scan on public.int8_tbl i8
         Output: i8.q1, i8.q2
   ->  Result
         Output: f1, f1, i8.q2
         One-Time Filter: false
(7 rows)

-- check handling of nested appendrels inside LATERAL
select * from
  ((select 2 as v) union all (select 3 as v)) as q1
  cross join lateral
  ((select * from
      ((select 4 as v) union all (select 5 as v)) as q3)
   union all
   (select q1.v)
  ) as q2;
 v | v 
---+---
 2 | 4
 2 | 5
 2 | 2
 3 | 4
 3 | 5
 3 | 3
(6 rows)

-- check the number of columns specified
SELECT * FROM (int8_tbl i cross join int4_tbl j) ss(a,b,c,d);
ERROR:  join expression "ss" has 3 columns available but 4 columns specified
-- check we don't try to do a unique-ified semijoin with LATERAL
explain (verbose, costs off)
select * from
  (values (0,9998), (1,1000)) v(id,x),
  lateral (select f1 from int4_tbl
           where f1 = any (select unique1 from tenk1
                           where unique2 = v.x offset 0)) ss;
                              QUERY PLAN                              
----------------------------------------------------------------------
 Nested Loop
   Output: "*VALUES*".column1, "*VALUES*".column2, int4_tbl.f1
   ->  Values Scan on "*VALUES*"
         Output: "*VALUES*".column1, "*VALUES*".column2
   ->  Nested Loop Semi Join
         Output: int4_tbl.f1
         Join Filter: (int4_tbl.f1 = tenk1.unique1)
         ->  Seq Scan on public.int4_tbl
               Output: int4_tbl.f1
         ->  Materialize
               Output: tenk1.unique1
               ->  Index Scan using tenk1_unique2 on public.tenk1
                     Output: tenk1.unique1
                     Index Cond: (tenk1.unique2 = "*VALUES*".column2)
(14 rows)

select * from
  (values (0,9998), (1,1000)) v(id,x),
  lateral (select f1 from int4_tbl
           where f1 = any (select unique1 from tenk1
                           where unique2 = v.x offset 0)) ss;
 id |  x   | f1 
----+------+----
  0 | 9998 |  0
(1 row)

-- check proper extParam/allParam handling (this isn't exactly a LATERAL issue,
-- but we can make the test case much more compact with LATERAL)
explain (verbose, costs off)
select * from (values (0), (1)) v(id),
lateral (select * from int8_tbl t1,
         lateral (select * from
                    (select * from int8_tbl t2
                     where (q1, random() > 0) = any (select q2, random() > 0 from int8_tbl t3
                                     where q2 = (select greatest(t1.q1,t2.q2))
                                       and (select v.id=0)) offset 0) ss2) ss
         where t1.q1 = ss.q2) ss0;
                                                         QUERY PLAN                                                         
----------------------------------------------------------------------------------------------------------------------------
 Nested Loop
   Output: "*VALUES*".column1, t1.q1, t1.q2, ss2.q1, ss2.q2
   ->  Seq Scan on public.int8_tbl t1
         Output: t1.q1, t1.q2
   ->  Nested Loop
         Output: "*VALUES*".column1, ss2.q1, ss2.q2
         ->  Values Scan on "*VALUES*"
               Output: "*VALUES*".column1
         ->  Subquery Scan on ss2
               Output: ss2.q1, ss2.q2
               Filter: (t1.q1 = ss2.q2)
               ->  Seq Scan on public.int8_tbl t2
                     Output: t2.q1, t2.q2
                     Filter: (ANY ((t2.q1 = (SubPlan 3).col1) AND ((random() > '0'::double precision) = (SubPlan 3).col2)))
                     SubPlan 3
                       ->  Result
                             Output: t3.q2, (random() > '0'::double precision)
                             One-Time Filter: (InitPlan 2).col1
                             InitPlan 1
                               ->  Result
                                     Output: GREATEST(t1.q1, t2.q2)
                             InitPlan 2
                               ->  Result
                                     Output: ("*VALUES*".column1 = 0)
                             ->  Seq Scan on public.int8_tbl t3
                                   Output: t3.q1, t3.q2
                                   Filter: (t3.q2 = (InitPlan 1).col1)
(27 rows)

select * from (values (0), (1)) v(id),
lateral (select * from int8_tbl t1,
         lateral (select * from
                    (select * from int8_tbl t2
                     where (q1, random() > 0) = any (select q2, random() > 0 from int8_tbl t3
                                     where q2 = (select greatest(t1.q1,t2.q2))
                                       and (select v.id=0)) offset 0) ss2) ss
         where t1.q1 = ss.q2) ss0;
 id |        q1        |        q2         |        q1        |        q2        
----+------------------+-------------------+------------------+------------------
  0 | 4567890123456789 |               123 | 4567890123456789 | 4567890123456789
  0 | 4567890123456789 |  4567890123456789 | 4567890123456789 | 4567890123456789
  0 | 4567890123456789 | -4567890123456789 | 4567890123456789 | 4567890123456789
(3 rows)

-- test some error cases where LATERAL should have been used but wasn't
select f1,g from int4_tbl a, (select f1 as g) ss;
ERROR:  column "f1" does not exist
LINE 1: select f1,g from int4_tbl a, (select f1 as g) ss;
                                             ^
DETAIL:  There is a column named "f1" in table "a", but it cannot be referenced from this part of the query.
HINT:  To reference that column, you must mark this subquery with LATERAL.
select f1,g from int4_tbl a, (select a.f1 as g) ss;
ERROR:  invalid reference to FROM-clause entry for table "a"
LINE 1: select f1,g from int4_tbl a, (select a.f1 as g) ss;
                                             ^
DETAIL:  There is an entry for table "a", but it cannot be referenced from this part of the query.
HINT:  To reference that table, you must mark this subquery with LATERAL.
select f1,g from int4_tbl a cross join (select f1 as g) ss;
ERROR:  column "f1" does not exist
LINE 1: select f1,g from int4_tbl a cross join (select f1 as g) ss;
                                                       ^
DETAIL:  There is a column named "f1" in table "a", but it cannot be referenced from this part of the query.
HINT:  To reference that column, you must mark this subquery with LATERAL.
select f1,g from int4_tbl a cross join (select a.f1 as g) ss;
ERROR:  invalid reference to FROM-clause entry for table "a"
LINE 1: select f1,g from int4_tbl a cross join (select a.f1 as g) ss...
                                                       ^
DETAIL:  There is an entry for table "a", but it cannot be referenced from this part of the query.
HINT:  To reference that table, you must mark this subquery with LATERAL.
-- SQL:2008 says the left table is in scope but illegal to access here
select f1,g from int4_tbl a right join lateral generate_series(0, a.f1) g on true;
ERROR:  invalid reference to FROM-clause entry for table "a"
LINE 1: ... int4_tbl a right join lateral generate_series(0, a.f1) g on...
                                                             ^
DETAIL:  The combining JOIN type must be INNER or LEFT for a LATERAL reference.
select f1,g from int4_tbl a full join lateral generate_series(0, a.f1) g on true;
ERROR:  invalid reference to FROM-clause entry for table "a"
LINE 1: ...m int4_tbl a full join lateral generate_series(0, a.f1) g on...
                                                             ^
DETAIL:  The combining JOIN type must be INNER or LEFT for a LATERAL reference.
-- check we complain about ambiguous table references
select * from
  int8_tbl x cross join (int4_tbl x cross join lateral (select x.f1) ss);
ERROR:  table reference "x" is ambiguous
LINE 2: ...cross join (int4_tbl x cross join lateral (select x.f1) ss);
                                                             ^
-- LATERAL can be used to put an aggregate into the FROM clause of its query
select 1 from tenk1 a, lateral (select max(a.unique1) from int4_tbl b) ss;
ERROR:  aggregate functions are not allowed in FROM clause of their own query level
LINE 1: select 1 from tenk1 a, lateral (select max(a.unique1) from i...
                                               ^
-- check behavior of LATERAL in UPDATE/DELETE
create temp table xx1 as select f1 as x1, -f1 as x2 from int4_tbl;
-- error, can't do this:
update xx1 set x2 = f1 from (select * from int4_tbl where f1 = x1) ss;
ERROR:  column "x1" does not exist
LINE 1: ... set x2 = f1 from (select * from int4_tbl where f1 = x1) ss;
                                                                ^
DETAIL:  There is a column named "x1" in table "xx1", but it cannot be referenced from this part of the query.
update xx1 set x2 = f1 from (select * from int4_tbl where f1 = xx1.x1) ss;
ERROR:  invalid reference to FROM-clause entry for table "xx1"
LINE 1: ...t x2 = f1 from (select * from int4_tbl where f1 = xx1.x1) ss...
                                                             ^
DETAIL:  There is an entry for table "xx1", but it cannot be referenced from this part of the query.
-- can't do it even with LATERAL:
update xx1 set x2 = f1 from lateral (select * from int4_tbl where f1 = x1) ss;
ERROR:  invalid reference to FROM-clause entry for table "xx1"
LINE 1: ...= f1 from lateral (select * from int4_tbl where f1 = x1) ss;
                                                                ^
HINT:  There is an entry for table "xx1", but it cannot be referenced from this part of the query.
-- we might in future allow something like this, but for now it's an error:
update xx1 set x2 = f1 from xx1, lateral (select * from int4_tbl where f1 = x1) ss;
ERROR:  table name "xx1" specified more than once
-- also errors:
delete from xx1 using (select * from int4_tbl where f1 = x1) ss;
ERROR:  column "x1" does not exist
LINE 1: ...te from xx1 using (select * from int4_tbl where f1 = x1) ss;
                                                                ^
DETAIL:  There is a column named "x1" in table "xx1", but it cannot be referenced from this part of the query.
delete from xx1 using (select * from int4_tbl where f1 = xx1.x1) ss;
ERROR:  invalid reference to FROM-clause entry for table "xx1"
LINE 1: ...from xx1 using (select * from int4_tbl where f1 = xx1.x1) ss...
                                                             ^
DETAIL:  There is an entry for table "xx1", but it cannot be referenced from this part of the query.
delete from xx1 using lateral (select * from int4_tbl where f1 = x1) ss;
ERROR:  invalid reference to FROM-clause entry for table "xx1"
LINE 1: ...xx1 using lateral (select * from int4_tbl where f1 = x1) ss;
                                                                ^
HINT:  There is an entry for table "xx1", but it cannot be referenced from this part of the query.
--
-- test LATERAL reference propagation down a multi-level inheritance hierarchy
-- produced for a multi-level partitioned table hierarchy.
--
create table join_pt1 (a int, b int, c varchar) partition by range(a);
create table join_pt1p1 partition of join_pt1 for values from (0) to (100) partition by range(b);
create table join_pt1p2 partition of join_pt1 for values from (100) to (200);
create table join_pt1p1p1 partition of join_pt1p1 for values from (0) to (100);
insert into join_pt1 values (11, 'x'), (101101, 'y');
create table join_ut1 (a int, b int, c varchar);
insert into join_ut1 values (101101, 'y'), (22, 'z');
explain (verbose, costs off)
select t1.b, ss.phv from join_ut1 t1 left join lateral
              (select t2.a as t2a, t3.a t3a, least(t1.a, t2.a, t3.a) phv
       from join_pt1 t2 join join_ut1 t3 on t2.a = t3.b) ss
              on t1.a = ss.t2a order by t1.a;
                             QUERY PLAN                             
--------------------------------------------------------------------
 Sort
   Output: t1.b, (LEAST(t1.a, t2.a, t3.a)), t1.a
   Sort Key: t1.a
   ->  Nested Loop Left Join
         Output: t1.b, (LEAST(t1.a, t2.a, t3.a)), t1.a
         ->  Seq Scan on public.join_ut1 t1
               Output: t1.a, t1.b, t1.c
         ->  Hash Join
               Output: t2.a, LEAST(t1.a, t2.a, t3.a)
               Hash Cond: (t3.b = t2.a)
               ->  Seq Scan on public.join_ut1 t3
                     Output: t3.a, t3.b, t3.c
               ->  Hash
                     Output: t2.a
                     ->  Append
                           ->  Seq Scan on public.join_pt1p1p1 t2_1
                                 Output: t2_1.a
                                 Filter: (t1.a = t2_1.a)
                           ->  Seq Scan on public.join_pt1p2 t2_2
                                 Output: t2_2.a
                                 Filter: (t1.a = t2_2.a)
(21 rows)

select t1.b, ss.phv from join_ut1 t1 left join lateral
              (select t2.a as t2a, t3.a t3a, least(t1.a, t2.a, t3.a) phv
       from join_pt1 t2 join join_ut1 t3 on t2.a = t3.b) ss
              on t1.a = ss.t2a order by t1.a;
  b  | phv 
-----+-----
   2 |    
 101 | 101
(2 rows)

drop table join_pt1;
drop table join_ut1;
--
-- test estimation behavior with multi-column foreign key and constant qual
--
begin;
create table fkest (x integer, x10 integer, x10b integer, x100 integer);
insert into fkest select x, x/10, x/10, x/100 from generate_series(1,1000) x;
create unique index on fkest(x, x10, x100);
analyze fkest;
explain (costs off)
select * from fkest f1
  join fkest f2 on (f1.x = f2.x and f1.x10 = f2.x10b and f1.x100 = f2.x100)
  join fkest f3 on f1.x = f3.x
  where f1.x100 = 2;
                        QUERY PLAN                         
-----------------------------------------------------------
 Nested Loop
   ->  Hash Join
         Hash Cond: ((f2.x = f1.x) AND (f2.x10b = f1.x10))
         ->  Seq Scan on fkest f2
               Filter: (x100 = 2)
         ->  Hash
               ->  Seq Scan on fkest f1
                     Filter: (x100 = 2)
   ->  Index Scan using fkest_x_x10_x100_idx on fkest f3
         Index Cond: (x = f1.x)
(10 rows)

alter table fkest add constraint fk
  foreign key (x, x10b, x100) references fkest (x, x10, x100);
explain (costs off)
select * from fkest f1
  join fkest f2 on (f1.x = f2.x and f1.x10 = f2.x10b and f1.x100 = f2.x100)
  join fkest f3 on f1.x = f3.x
  where f1.x100 = 2;
                     QUERY PLAN                      
-----------------------------------------------------
 Hash Join
   Hash Cond: ((f2.x = f1.x) AND (f2.x10b = f1.x10))
   ->  Hash Join
         Hash Cond: (f3.x = f2.x)
         ->  Seq Scan on fkest f3
         ->  Hash
               ->  Seq Scan on fkest f2
                     Filter: (x100 = 2)
   ->  Hash
         ->  Seq Scan on fkest f1
               Filter: (x100 = 2)
(11 rows)

rollback;
--
-- test that foreign key join estimation performs sanely for outer joins
--
begin;
create table fkest (a int, b int, c int unique, primary key(a,b));
create table fkest1 (a int, b int, primary key(a,b));
insert into fkest select x/10, x%10, x from generate_series(1,1000) x;
insert into fkest1 select x/10, x%10 from generate_series(1,1000) x;
alter table fkest1
  add constraint fkest1_a_b_fkey foreign key (a,b) references fkest;
analyze fkest;
analyze fkest1;
explain (costs off)
select *
from fkest f
  left join fkest1 f1 on f.a = f1.a and f.b = f1.b
  left join fkest1 f2 on f.a = f2.a and f.b = f2.b
  left join fkest1 f3 on f.a = f3.a and f.b = f3.b
where f.c = 1;
                            QUERY PLAN                            
------------------------------------------------------------------
 Nested Loop Left Join
   ->  Nested Loop Left Join
         ->  Nested Loop Left Join
               ->  Index Scan using fkest_c_key on fkest f
                     Index Cond: (c = 1)
               ->  Index Only Scan using fkest1_pkey on fkest1 f1
                     Index Cond: ((a = f.a) AND (b = f.b))
         ->  Index Only Scan using fkest1_pkey on fkest1 f2
               Index Cond: ((a = f.a) AND (b = f.b))
   ->  Index Only Scan using fkest1_pkey on fkest1 f3
         Index Cond: ((a = f.a) AND (b = f.b))
(11 rows)

rollback;
--
-- test planner's ability to mark joins as unique
--
create table j1 (id int primary key);
create table j2 (id int primary key);
create table j3 (id int);
insert into j1 values(1),(2),(3);
insert into j2 values(1),(2),(3);
insert into j3 values(1),(1);
analyze j1;
analyze j2;
analyze j3;
-- ensure join is properly marked as unique
explain (verbose, costs off)
select * from j1 inner join j2 on j1.id = j2.id;
            QUERY PLAN             
-----------------------------------
 Hash Join
   Output: j1.id, j2.id
   Inner Unique: true
   Hash Cond: (j1.id = j2.id)
   ->  Seq Scan on public.j1
         Output: j1.id
   ->  Hash
         Output: j2.id
         ->  Seq Scan on public.j2
               Output: j2.id
(10 rows)

-- ensure join is not unique when not an equi-join
explain (verbose, costs off)
select * from j1 inner join j2 on j1.id > j2.id;
            QUERY PLAN             
-----------------------------------
 Nested Loop
   Output: j1.id, j2.id
   Join Filter: (j1.id > j2.id)
   ->  Seq Scan on public.j1
         Output: j1.id
   ->  Materialize
         Output: j2.id
         ->  Seq Scan on public.j2
               Output: j2.id
(9 rows)

-- ensure non-unique rel is not chosen as inner
explain (verbose, costs off)
select * from j1 inner join j3 on j1.id = j3.id;
            QUERY PLAN             
-----------------------------------
 Hash Join
   Output: j1.id, j3.id
   Inner Unique: true
   Hash Cond: (j3.id = j1.id)
   ->  Seq Scan on public.j3
         Output: j3.id
   ->  Hash
         Output: j1.id
         ->  Seq Scan on public.j1
               Output: j1.id
(10 rows)

-- ensure left join is marked as unique
explain (verbose, costs off)
select * from j1 left join j2 on j1.id = j2.id;
            QUERY PLAN             
-----------------------------------
 Hash Left Join
   Output: j1.id, j2.id
   Inner Unique: true
   Hash Cond: (j1.id = j2.id)
   ->  Seq Scan on public.j1
         Output: j1.id
   ->  Hash
         Output: j2.id
         ->  Seq Scan on public.j2
               Output: j2.id
(10 rows)

-- ensure right join is marked as unique
explain (verbose, costs off)
select * from j1 right join j2 on j1.id = j2.id;
            QUERY PLAN             
-----------------------------------
 Hash Left Join
   Output: j1.id, j2.id
   Inner Unique: true
   Hash Cond: (j2.id = j1.id)
   ->  Seq Scan on public.j2
         Output: j2.id
   ->  Hash
         Output: j1.id
         ->  Seq Scan on public.j1
               Output: j1.id
(10 rows)

-- ensure full join is marked as unique
explain (verbose, costs off)
select * from j1 full join j2 on j1.id = j2.id;
            QUERY PLAN             
-----------------------------------
 Hash Full Join
   Output: j1.id, j2.id
   Inner Unique: true
   Hash Cond: (j1.id = j2.id)
   ->  Seq Scan on public.j1
         Output: j1.id
   ->  Hash
         Output: j2.id
         ->  Seq Scan on public.j2
               Output: j2.id
(10 rows)

-- a clauseless (cross) join can't be unique
explain (verbose, costs off)
select * from j1 cross join j2;
            QUERY PLAN             
-----------------------------------
 Nested Loop
   Output: j1.id, j2.id
   ->  Seq Scan on public.j1
         Output: j1.id
   ->  Materialize
         Output: j2.id
         ->  Seq Scan on public.j2
               Output: j2.id
(8 rows)

-- ensure a natural join is marked as unique
explain (verbose, costs off)
select * from j1 natural join j2;
            QUERY PLAN             
-----------------------------------
 Hash Join
   Output: j1.id
   Inner Unique: true
   Hash Cond: (j1.id = j2.id)
   ->  Seq Scan on public.j1
         Output: j1.id
   ->  Hash
         Output: j2.id
         ->  Seq Scan on public.j2
               Output: j2.id
(10 rows)

-- ensure a distinct clause allows the inner to become unique
explain (verbose, costs off)
select * from j1
inner join (select distinct id from j3) j3 on j1.id = j3.id;
               QUERY PLAN                
-----------------------------------------
 Nested Loop
   Output: j1.id, j3.id
   Inner Unique: true
   Join Filter: (j1.id = j3.id)
   ->  Unique
         Output: j3.id
         ->  Sort
               Output: j3.id
               Sort Key: j3.id
               ->  Seq Scan on public.j3
                     Output: j3.id
   ->  Seq Scan on public.j1
         Output: j1.id
(13 rows)

-- ensure group by clause allows the inner to become unique
explain (verbose, costs off)
select * from j1
inner join (select id from j3 group by id) j3 on j1.id = j3.id;
               QUERY PLAN                
-----------------------------------------
 Nested Loop
   Output: j1.id, j3.id
   Inner Unique: true
   Join Filter: (j1.id = j3.id)
   ->  Group
         Output: j3.id
         Group Key: j3.id
         ->  Sort
               Output: j3.id
               Sort Key: j3.id
               ->  Seq Scan on public.j3
                     Output: j3.id
   ->  Seq Scan on public.j1
         Output: j1.id
(14 rows)

drop table j1;
drop table j2;
drop table j3;
-- test more complex permutations of unique joins
create table j1 (id1 int, id2 int, primary key(id1,id2));
create table j2 (id1 int, id2 int, primary key(id1,id2));
create table j3 (id1 int, id2 int, primary key(id1,id2));
insert into j1 values(1,1),(1,2);
insert into j2 values(1,1);
insert into j3 values(1,1);
analyze j1;
analyze j2;
analyze j3;
-- ensure there's no unique join when not all columns which are part of the
-- unique index are seen in the join clause
explain (verbose, costs off)
select * from j1
inner join j2 on j1.id1 = j2.id1;
                QUERY PLAN                
------------------------------------------
 Nested Loop
   Output: j1.id1, j1.id2, j2.id1, j2.id2
   Join Filter: (j1.id1 = j2.id1)
   ->  Seq Scan on public.j2
         Output: j2.id1, j2.id2
   ->  Seq Scan on public.j1
         Output: j1.id1, j1.id2
(7 rows)

-- ensure proper unique detection with multiple join quals
explain (verbose, costs off)
select * from j1
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2;
                        QUERY PLAN                        
----------------------------------------------------------
 Nested Loop
   Output: j1.id1, j1.id2, j2.id1, j2.id2
   Inner Unique: true
   Join Filter: ((j1.id1 = j2.id1) AND (j1.id2 = j2.id2))
   ->  Seq Scan on public.j2
         Output: j2.id1, j2.id2
   ->  Seq Scan on public.j1
         Output: j1.id1, j1.id2
(8 rows)

-- ensure we don't detect the join to be unique when quals are not part of the
-- join condition
explain (verbose, costs off)
select * from j1
inner join j2 on j1.id1 = j2.id1 where j1.id2 = 1;
                QUERY PLAN                
------------------------------------------
 Nested Loop
   Output: j1.id1, j1.id2, j2.id1, j2.id2
   Join Filter: (j1.id1 = j2.id1)
   ->  Seq Scan on public.j1
         Output: j1.id1, j1.id2
         Filter: (j1.id2 = 1)
   ->  Seq Scan on public.j2
         Output: j2.id1, j2.id2
(8 rows)

-- as above, but for left joins.
explain (verbose, costs off)
select * from j1
left join j2 on j1.id1 = j2.id1 where j1.id2 = 1;
                QUERY PLAN                
------------------------------------------
 Nested Loop Left Join
   Output: j1.id1, j1.id2, j2.id1, j2.id2
   Join Filter: (j1.id1 = j2.id1)
   ->  Seq Scan on public.j1
         Output: j1.id1, j1.id2
         Filter: (j1.id2 = 1)
   ->  Seq Scan on public.j2
         Output: j2.id1, j2.id2
(8 rows)

create unique index j1_id2_idx on j1(id2) where id2 is not null;
-- ensure we don't use a partial unique index as unique proofs
explain (verbose, costs off)
select * from j1
inner join j2 on j1.id2 = j2.id2;
                QUERY PLAN                
------------------------------------------
 Nested Loop
   Output: j1.id1, j1.id2, j2.id1, j2.id2
   Join Filter: (j2.id2 = j1.id2)
   ->  Seq Scan on public.j2
         Output: j2.id1, j2.id2
   ->  Seq Scan on public.j1
         Output: j1.id1, j1.id2
(7 rows)

drop index j1_id2_idx;
-- validate logic in merge joins which skips mark and restore.
-- it should only do this if all quals which were used to detect the unique
-- are present as join quals, and not plain quals.
set enable_nestloop to 0;
set enable_hashjoin to 0;
set enable_sort to 0;
-- create indexes that will be preferred over the PKs to perform the join
create index j1_id1_idx on j1 (id1) where id1 % 1000 = 1;
create index j2_id1_idx on j2 (id1) where id1 % 1000 = 1;
-- need an additional row in j2, if we want j2_id1_idx to be preferred
insert into j2 values(1,2);
analyze j2;
explain (costs off) select * from j1
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1;
               QUERY PLAN                
-----------------------------------------
 Merge Join
   Merge Cond: (j1.id1 = j2.id1)
   Join Filter: (j2.id2 = j1.id2)
   ->  Index Scan using j1_id1_idx on j1
   ->  Index Scan using j2_id1_idx on j2
(5 rows)

select * from j1
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1;
 id1 | id2 | id1 | id2 
-----+-----+-----+-----
   1 |   1 |   1 |   1
   1 |   2 |   1 |   2
(2 rows)

-- Exercise array keys mark/restore B-Tree code
explain (costs off) select * from j1
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1 and j2.id1 = any (array[1]);
                     QUERY PLAN                     
----------------------------------------------------
 Merge Join
   Merge Cond: (j1.id1 = j2.id1)
   Join Filter: (j2.id2 = j1.id2)
   ->  Index Scan using j1_id1_idx on j1
   ->  Index Scan using j2_id1_idx on j2
         Index Cond: (id1 = ANY ('{1}'::integer[]))
(6 rows)

select * from j1
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1 and j2.id1 = any (array[1]);
 id1 | id2 | id1 | id2 
-----+-----+-----+-----
   1 |   1 |   1 |   1
   1 |   2 |   1 |   2
(2 rows)

-- Exercise array keys "find extreme element" B-Tree code
explain (costs off) select * from j1
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1 and j2.id1 >= any (array[1,5]);
                      QUERY PLAN                       
-------------------------------------------------------
 Merge Join
   Merge Cond: (j1.id1 = j2.id1)
   Join Filter: (j2.id2 = j1.id2)
   ->  Index Scan using j1_id1_idx on j1
   ->  Index Scan using j2_id1_idx on j2
         Index Cond: (id1 >= ANY ('{1,5}'::integer[]))
(6 rows)

select * from j1
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1 and j2.id1 >= any (array[1,5]);
 id1 | id2 | id1 | id2 
-----+-----+-----+-----
   1 |   1 |   1 |   1
   1 |   2 |   1 |   2
(2 rows)

reset enable_nestloop;
reset enable_hashjoin;
reset enable_sort;
drop table j1;
drop table j2;
drop table j3;
-- check that semijoin inner is not seen as unique for a portion of the outerrel
explain (verbose, costs off)
select t1.unique1, t2.hundred
from onek t1, tenk1 t2
where exists (select 1 from tenk1 t3
              where t3.thousand = t1.unique1 and t3.tenthous = t2.hundred)
      and t1.unique1 < 1;
                                   QUERY PLAN                                    
---------------------------------------------------------------------------------
 Nested Loop
   Output: t1.unique1, t2.hundred
   ->  Hash Join
         Output: t1.unique1, t3.tenthous
         Hash Cond: (t3.thousand = t1.unique1)
         ->  HashAggregate
               Output: t3.thousand, t3.tenthous
               Group Key: t3.thousand, t3.tenthous
               ->  Index Only Scan using tenk1_thous_tenthous on public.tenk1 t3
                     Output: t3.thousand, t3.tenthous
         ->  Hash
               Output: t1.unique1
               ->  Index Only Scan using onek_unique1 on public.onek t1
                     Output: t1.unique1
                     Index Cond: (t1.unique1 < 1)
   ->  Index Only Scan using tenk1_hundred on public.tenk1 t2
         Output: t2.hundred
         Index Cond: (t2.hundred = t3.tenthous)
(18 rows)

-- ... unless it actually is unique
create table j3 as select unique1, tenthous from onek;
vacuum analyze j3;
create unique index on j3(unique1, tenthous);
explain (verbose, costs off)
select t1.unique1, t2.hundred
from onek t1, tenk1 t2
where exists (select 1 from j3
              where j3.unique1 = t1.unique1 and j3.tenthous = t2.hundred)
      and t1.unique1 < 1;
                               QUERY PLAN                               
------------------------------------------------------------------------
 Nested Loop
   Output: t1.unique1, t2.hundred
   ->  Nested Loop
         Output: t1.unique1, j3.tenthous
         ->  Index Only Scan using onek_unique1 on public.onek t1
               Output: t1.unique1
               Index Cond: (t1.unique1 < 1)
         ->  Index Only Scan using j3_unique1_tenthous_idx on public.j3
               Output: j3.unique1, j3.tenthous
               Index Cond: (j3.unique1 = t1.unique1)
   ->  Index Only Scan using tenk1_hundred on public.tenk1 t2
         Output: t2.hundred
         Index Cond: (t2.hundred = j3.tenthous)
(13 rows)

drop table j3;
-- Exercise the "skip fetch" Bitmap Heap Scan optimization when candidate
-- tuples are discarded. This may occur when:
--   1. A join doesn't require all inner tuples to be scanned for each outer
--      tuple, and
--   2. The inner side is scanned using a bitmap heap scan, and
--   3. The bitmap heap scan is eligible for the "skip fetch" optimization.
--      This optimization is usable when no data from the underlying table is
--      needed. Use a temp table so it is only visible to this backend and
--      vacuum may reliably mark all blocks in the table all visible in the
--      visibility map.
CREATE TEMP TABLE skip_fetch (a INT, b INT) WITH (fillfactor=10);
INSERT INTO skip_fetch SELECT i % 3, i FROM generate_series(0,30) i;
CREATE INDEX ON skip_fetch(a);
VACUUM (ANALYZE) skip_fetch;
SET enable_indexonlyscan = off;
SET enable_seqscan = off;
EXPLAIN (COSTS OFF)
SELECT t1.a FROM skip_fetch t1 LEFT JOIN skip_fetch t2 ON t2.a = 1 WHERE t2.a IS NULL;
                       QUERY PLAN                        
---------------------------------------------------------
 Nested Loop Anti Join
   ->  Seq Scan on skip_fetch t1
         Disabled: true
   ->  Materialize
         ->  Bitmap Heap Scan on skip_fetch t2
               Recheck Cond: (a = 1)
               ->  Bitmap Index Scan on skip_fetch_a_idx
                     Index Cond: (a = 1)
(8 rows)

SELECT t1.a FROM skip_fetch t1 LEFT JOIN skip_fetch t2 ON t2.a = 1 WHERE t2.a IS NULL;
 a 
---
(0 rows)

RESET enable_indexonlyscan;
RESET enable_seqscan;
-- Test BitmapHeapScan with a rescan releases resources correctly
SET enable_seqscan = off;
SET enable_indexscan = off;
CREATE TEMP TABLE rescan_bhs (a INT);
INSERT INTO rescan_bhs VALUES (1), (2);
CREATE INDEX ON rescan_bhs (a);
EXPLAIN (COSTS OFF)
SELECT * FROM rescan_bhs t1 LEFT JOIN rescan_bhs t2 ON t1.a IN
  (SELECT a FROM rescan_bhs t3 WHERE t2.a > 1);
                        QUERY PLAN                         
-----------------------------------------------------------
 Nested Loop Left Join
   Join Filter: (ANY (t1.a = (SubPlan 1).col1))
   ->  Bitmap Heap Scan on rescan_bhs t1
         ->  Bitmap Index Scan on rescan_bhs_a_idx
   ->  Materialize
         ->  Bitmap Heap Scan on rescan_bhs t2
               ->  Bitmap Index Scan on rescan_bhs_a_idx
   SubPlan 1
     ->  Result
           One-Time Filter: (t2.a > 1)
           ->  Bitmap Heap Scan on rescan_bhs t3
                 ->  Bitmap Index Scan on rescan_bhs_a_idx
(12 rows)

SELECT * FROM rescan_bhs t1 LEFT JOIN rescan_bhs t2 ON t1.a IN
  (SELECT a FROM rescan_bhs t3 WHERE t2.a > 1);
 a | a 
---+---
 1 | 2
 2 | 2
(2 rows)

RESET enable_seqscan;
RESET enable_indexscan;
-- Test that we do not account for nullingrels when looking up statistics
CREATE TABLE group_tbl (a INT, b INT);
INSERT INTO group_tbl SELECT 11;
CREATE STATISTICS group_tbl_stat (ndistinct) ON a, b FROM group_tbl;
ANALYZE group_tbl;
EXPLAIN (COSTS OFF)
SELECT 1 FROM group_tbl t1
    LEFT JOIN (SELECT a c1, COALESCE(a) c2 FROM group_tbl t2) s ON TRUE
GROUP BY s.c1, s.c2;
                 QUERY PLAN                 
--------------------------------------------
 Group
   Group Key: t2.a, (COALESCE(t2.a))
   ->  Sort
         Sort Key: t2.a, (COALESCE(t2.a))
         ->  Nested Loop Left Join
               ->  Seq Scan on group_tbl t1
               ->  Seq Scan on group_tbl t2
(7 rows)

DROP TABLE group_tbl;
-- Test that we ignore PlaceHolderVars when looking up statistics
EXPLAIN (COSTS OFF)
SELECT t1.unique1 FROM tenk1 t1 LEFT JOIN
  (SELECT *, 42 AS phv FROM tenk1 t2) ss ON t1.unique2 = ss.unique2
WHERE ss.unique1 = ss.phv AND t1.unique1 < 100;
                    QUERY PLAN                    
--------------------------------------------------
 Nested Loop
   ->  Seq Scan on tenk1 t2
         Filter: (unique1 = 42)
   ->  Index Scan using tenk1_unique2 on tenk1 t1
         Index Cond: (unique2 = t2.unique2)
         Filter: (unique1 < 100)
(6 rows)

SELECT t1.unique1 FROM tenk1 t1 LEFT JOIN
  (SELECT *, 42 AS phv FROM tenk1 t2) ss ON t1.unique2 = ss.unique2
WHERE ss.unique1 = ss.phv AND t1.unique1 < 100;
 unique1 
---------
      42
(1 row)

--
-- Test for a nested loop join involving index scan, transforming OR-clauses
-- to SAOP.
--
EXPLAIN (COSTS OFF)
SELECT COUNT(*) FROM tenk1 t1, tenk1 t2
WHERE t2.thousand = t1.tenthous OR t2.thousand = t1.unique1 OR t2.thousand = t1.unique2;
                                       QUERY PLAN                                        
-----------------------------------------------------------------------------------------
 Aggregate
   ->  Nested Loop
         ->  Seq Scan on tenk1 t1
         ->  Index Only Scan using tenk1_thous_tenthous on tenk1 t2
               Index Cond: (thousand = ANY (ARRAY[t1.tenthous, t1.unique1, t1.unique2]))
(5 rows)

SELECT COUNT(*) FROM tenk1 t1, tenk1 t2
WHERE t2.thousand = t1.tenthous OR t2.thousand = t1.unique1 OR t2.thousand = t1.unique2;
 count 
-------
 20000
(1 row)

EXPLAIN (COSTS OFF)
SELECT COUNT(*) FROM onek t1 LEFT JOIN tenk1 t2
    ON (t2.thousand = t1.tenthous OR t2.thousand = t1.thousand);
                                  QUERY PLAN                                  
------------------------------------------------------------------------------
 Aggregate
   ->  Nested Loop Left Join
         ->  Seq Scan on onek t1
         ->  Index Only Scan using tenk1_thous_tenthous on tenk1 t2
               Index Cond: (thousand = ANY (ARRAY[t1.tenthous, t1.thousand]))
(5 rows)

SELECT COUNT(*) FROM onek t1 LEFT JOIN tenk1 t2
    ON (t2.thousand = t1.tenthous OR t2.thousand = t1.thousand);
 count 
-------
 19000
(1 row)


[Seitenstruktur0.586Druckenetwas mehr zur Ethik2026-08-08]