--
-- queries to test the subquery pushdown on reference tables

-- subqueries in WHERE with IN operator
SELECT
  user_id
FROM
  users_table
WHERE
  value_2 IN
          (SELECT
              value_2
           FROM
              events_reference_table
           WHERE
              users_table.user_id = events_reference_table.user_id
          )
GROUP BY user_id
ORDER BY user_id
LIMIT 3;

-- subqueries in WHERE with NOT EXISTS operator, should work since
-- reference table in the inner part of the join
SELECT
  user_id
FROM
  users_table
WHERE
  NOT EXISTS
      (SELECT
          value_2
       FROM
          events_reference_table
       WHERE
          users_table.user_id = events_reference_table.user_id
      )
GROUP BY user_id
ORDER BY user_id
LIMIT 3;

-- subqueries in WHERE with NOT EXISTS operator, should not work since
-- there is a correlated subquery in WHERE clause
SELECT
  user_id
FROM
  users_reference_table
WHERE
  NOT EXISTS
      (SELECT
          value_2
       FROM
          events_table
       WHERE
          users_reference_table.user_id = events_table.user_id
      )
LIMIT 3;

-- immutable functions are also treated as reference tables, query should not
-- work since there is a correlated subquery in the WHERE clause
SELECT
  user_id
FROM
  (SELECT user_id FROM generate_series(1,10) AS series(user_id)) users_reference_table
WHERE
  NOT EXISTS
      (SELECT
          value_2
       FROM
          events_table
       WHERE
          users_reference_table.user_id = events_table.user_id
      )
LIMIT 3;

-- subqueries without FROM are also treated as reference tables, query should not
-- work since there is a correlated subquery in the WHERE clause
SELECT
  user_id
FROM
  (SELECT  5 AS user_id UNION ALL SELECT 6) users_reference_table
WHERE
  NOT EXISTS
      (SELECT
          value_2
       FROM
          events_table
       WHERE
          users_reference_table.user_id = events_table.user_id
      )
LIMIT 3;

-- join with distributed table prevents FROM from recurring
SELECT
  DISTINCT user_id
FROM
  (SELECT s FROM generate_series(1,10) s) series,
  (SELECT DISTINCT user_id FROM users_table) users_table,
  (SELECT 1 AS one) one
WHERE
  s = user_id AND user_id > one AND
  user_id IN
      (SELECT
          value_2
       FROM
          events_table
       WHERE
          users_table.user_id = events_table.user_id
      )
ORDER BY user_id
LIMIT 3;

-- inner join between distributed prevents FROM from recurring
SELECT
  DISTINCT user_id
FROM
  users_table JOIN users_reference_table USING (user_id)
WHERE
  users_table.value_2 IN
      (SELECT
          value_2
       FROM
          events_table
       WHERE
          users_table.user_id = events_table.user_id
      )
ORDER BY user_id
LIMIT 3;

-- outer join could still recur
SELECT
  DISTINCT user_id
FROM
  users_table RIGHT JOIN users_reference_table USING (user_id)
WHERE
  users_reference_table.value_2 IN
      (SELECT
          value_2
       FROM
          events_table
       WHERE
          users_table.user_id = events_table.user_id
      )
ORDER BY user_id
LIMIT 3;

-- subqueries in WHERE with IN operator without equality
SELECT
  users_table.user_id, count(*)
FROM
  users_table
WHERE
  value_2 IN
          (SELECT
              value_2
           FROM
              events_reference_table
           WHERE
              users_table.user_id > events_reference_table.user_id
          )
GROUP BY users_table.user_id
ORDER BY 2 DESC, 1 DESC
LIMIT 3;

-- immutable functions are also treated as reference tables
SELECT
  users_table.user_id, count(*)
FROM
  users_table
WHERE
  value_2 IN
          (SELECT
              value_2
           FROM
              generate_series(1,10) AS events_reference_table(user_id)
           WHERE
              users_table.user_id > events_reference_table.user_id
          )
GROUP BY users_table.user_id
ORDER BY 2 DESC, 1 DESC
LIMIT 3;

-- immutable functions are also treated as reference tables
SELECT
  users_table.user_id, count(*)
FROM
  users_table
WHERE
  value_2 IN
          (SELECT
              value_2
           FROM
              (SELECT 5 AS user_id) AS events_reference_table
           WHERE
              users_table.user_id > events_reference_table.user_id
          )
GROUP BY users_table.user_id
ORDER BY 2 DESC, 1 DESC
LIMIT 3;


-- reference tables in a subquery in the WHERE clause are ok
SELECT user_id, value_2 FROM users_table WHERE
  value_1 > 1 AND value_1 < 3
  AND value_2 >= 5
  AND user_id IN
  (
		SELECT
		  e1.user_id
		FROM (
		  -- Get the first time each user viewed the homepage.
		  SELECT
		    user_id,
		    1 AS view_homepage,
		    min(time) AS view_homepage_time
		  FROM events_reference_table
		     WHERE
		     event_type IN (1, 2)
		  GROUP BY user_id
		) e1 LEFT JOIN LATERAL (
		  SELECT
		    user_id,
		    1 AS use_demo,
		    time AS use_demo_time
		  FROM events_reference_table
		  WHERE
		    user_id = e1.user_id AND
		       event_type IN (2, 3)
		  ORDER BY time
		) e2 ON true LEFT JOIN LATERAL (
		  SELECT
		    user_id,
		    1 AS enter_credit_card,
		    time AS enter_credit_card_time
		  FROM  events_reference_table
		  WHERE
		    user_id = e2.user_id AND
		    event_type IN (3, 4)
		  ORDER BY time
		) e3 ON true LEFT JOIN LATERAL (
		  SELECT
		    1 AS submit_card_info,
		    user_id,
		    time AS enter_credit_card_time
		  FROM  events_reference_table
		  WHERE
		    user_id = e3.user_id AND
		    event_type IN (4, 5)
		  ORDER BY time
		) e4 ON true LEFT JOIN LATERAL (
		  SELECT
		    1 AS see_bought_screen
		  FROM  events_reference_table
		  WHERE
		    user_id = e4.user_id AND
		    event_type IN (5, 6)
		  ORDER BY time
		) e5 ON true
		group by e1.user_id
		HAVING sum(submit_card_info) > 0
)
ORDER BY 1, 2;

-- reference table LEFT JOIN distributed table in WHERE is still not ok
SELECT user_id, value_2 FROM users_table WHERE
  value_1 > 1 AND value_1 < 3
  AND value_2 >= 5
  AND user_id IN
  (
		SELECT
		  e1.user_id
		FROM (
		  -- Get the first time each user viewed the homepage.
		  SELECT
		    user_id,
		    1 AS view_homepage,
		    min(time) AS view_homepage_time
		  FROM events_reference_table
		     WHERE
		     event_type IN (1, 2)
		  GROUP BY user_id
		) e1 LEFT JOIN LATERAL (
		  SELECT
		    user_id,
		    1 AS use_demo,
		    time AS use_demo_time
		  FROM events_table
		  WHERE
		    user_id = e1.user_id AND
		       event_type IN (2, 3)
		  ORDER BY time
		) e2 ON true LEFT JOIN LATERAL (
		  SELECT
		    user_id,
		    1 AS enter_credit_card,
		    time AS enter_credit_card_time
		  FROM  events_reference_table
		  WHERE
		    user_id = e2.user_id AND
		    event_type IN (3, 4)
		  ORDER BY time
		) e3 ON true LEFT JOIN LATERAL (
		  SELECT
		    1 AS submit_card_info,
		    user_id,
		    time AS enter_credit_card_time
		  FROM  events_reference_table
		  WHERE
		    user_id = e3.user_id AND
		    event_type IN (4, 5)
		  ORDER BY time
		) e4 ON true LEFT JOIN LATERAL (
		  SELECT
		    1 AS see_bought_screen
		  FROM  events_reference_table
		  WHERE
		    user_id = e4.user_id AND
		    event_type IN (5, 6)
		  ORDER BY time
		) e5 ON true

		group by e1.user_id
		HAVING sum(submit_card_info) > 0
)
ORDER BY 1, 2;

-- non-partition key equality with reference table
 SELECT
  user_id, count(*)
FROM
  users_table
WHERE
  value_3 =ANY(SELECT value_2 FROM users_reference_table WHERE value_1 >= 1 AND value_1 <= 2)
 GROUP BY 1 ORDER BY 2 DESC, 1 DESC LIMIT 5;


-- non-partition key comparison with reference table
SELECT
  user_id, count(*)
FROM
  events_table as e1
WHERE
  event_type IN
            (SELECT
                event_type
             FROM
              events_reference_table as e2
             WHERE
              value_2 = 2 AND
              value_3 > 3 AND
              e1.value_2 > e2.value_2
            )
GROUP BY 1
ORDER BY 2 DESC, 1 DESC
LIMIT 5;

-- subqueries in both WHERE and FROM clauses
-- should work since reference table is on the
-- inner part of the join
SELECT user_id, value_2 FROM users_table WHERE
  value_1 > 1 AND value_1 < 3
  AND value_2 >= 5
  AND user_id IN
  (
    SELECT
      e1.user_id
    FROM (
      -- Get the first time each user viewed the homepage.
      SELECT
        user_id,
        1 AS view_homepage,
        min(time) AS view_homepage_time
      FROM events_table
         WHERE
         event_type IN (1, 2)
      GROUP BY user_id
    ) e1 LEFT JOIN LATERAL (
      SELECT
        user_id,
        1 AS use_demo,
        time AS use_demo_time
      FROM events_table
      WHERE
        user_id = e1.user_id AND
           event_type IN (2, 3)
      ORDER BY time
    ) e2 ON true LEFT JOIN LATERAL (
      SELECT
        user_id,
        1 AS enter_credit_card,
        time AS enter_credit_card_time
      FROM  events_table
      WHERE
        user_id = e2.user_id AND
        event_type IN (3, 4)
      ORDER BY time
    ) e3 ON true LEFT JOIN LATERAL (
      SELECT
        1 AS submit_card_info,
        user_id,
        time AS enter_credit_card_time
      FROM  events_table
      WHERE
        user_id = e3.user_id AND
        event_type IN (4, 5)
      ORDER BY time
    ) e4 ON true LEFT JOIN LATERAL (
      SELECT
        1 AS see_bought_screen
      FROM  events_reference_table
      WHERE
        user_id = e4.user_id AND
        event_type IN (5, 6)
      ORDER BY time
    ) e5 ON true
    group by e1.user_id
    HAVING sum(submit_card_info) > 0
)
ORDER BY 1, 2;

-- change debug level to check recursive planning output
SET client_min_messages TO DEBUG1;

-- recursively planning subqueries in WHERE clause due to recurring table in FROM
SELECT
  count(*)
FROM
  users_reference_table
WHERE user_id
  NOT IN
(SELECT users_table.value_2 FROM users_table JOIN users_reference_table as u2 ON users_table.value_2 = u2.value_2);

-- recursively planning subqueries in WHERE clause due to recurring table in FROM
SELECT count(*)
FROM
  (SELECT
      user_id, random() FROM users_reference_table) AS vals
    WHERE vals.user_id NOT IN
    (SELECT users_table.value_2
     FROM users_table
     JOIN users_reference_table AS u2 ON users_table.value_2 = u2.value_2);

-- query should not work since there is a correlated subquery in the WHERE clause
SELECT user_id,
       count(*)
FROM users_reference_table
WHERE value_2 > ALL
    (SELECT min(value_2)
     FROM events_table
     WHERE event_type > 2 AND users_reference_table.user_id = events_table.user_id
     GROUP BY user_id)
GROUP BY user_id
HAVING count(*) > 3
ORDER BY 2 DESC,
         1 DESC
LIMIT 5;

-- query will be planned as a SEMI JOIN
SELECT *
FROM users_table
WHERE user_id IN
    (SELECT users_table.user_id
     FROM users_table,
          users_reference_table
     WHERE users_reference_table.user_id NOT IN
         (SELECT value_2
          FROM users_reference_table AS u2))
ORDER BY 1,2,3
LIMIT 5;

SET client_min_messages TO DEFAULT;

SELECT
  user_id
FROM
  users_table
WHERE
  value_2 >
          (SELECT
              max(value_2)
           FROM
              events_reference_table
           WHERE
              users_table.user_id = events_reference_table.user_id AND event_type = 2
           GROUP BY
              users_table.user_id
          )
GROUP BY user_id
HAVING count(*) > 3
ORDER BY user_id
LIMIT 5;

-- similar query with slightly more complex group by
SELECT
  user_id
FROM
  users_table
WHERE
  value_2 >
          (SELECT
              max(value_2)
           FROM
              events_reference_table
           WHERE
              users_table.user_id = events_reference_table.user_id AND event_type = 2
           GROUP BY
              (users_table.user_id * 2)
          )
GROUP BY user_id
HAVING count(*) > 3
ORDER BY user_id
LIMIT 5;
