SET search_path TO arbitrary_configs_router;
SET client_min_messages TO WARNING;
-- test simple select for a single row
SELECT * FROM articles_hash WHERE author_id = 10 AND id = 50;
 id | author_id |   title   | word_count
---------------------------------------------------------------------
 50 |        10 | anjanette |      19519
(1 row)

-- get all titles by a single author
SELECT title FROM articles_hash WHERE author_id = 10;
   title
---------------------------------------------------------------------
 aggrandize
 absentness
 andelee
 attemper
 anjanette
(5 rows)

-- try ordering them by word count
SELECT title, word_count FROM articles_hash
	WHERE author_id = 10
	ORDER BY word_count DESC NULLS LAST;
   title    | word_count
---------------------------------------------------------------------
 anjanette  |      19519
 aggrandize |      17277
 attemper   |      14976
 andelee    |       6363
 absentness |       1820
(5 rows)

-- look at last two articles by an author
SELECT title, id FROM articles_hash
	WHERE author_id = 5
	ORDER BY id
	LIMIT 2;
  title  | id
---------------------------------------------------------------------
 aruru   |  5
 adversa | 15
(2 rows)

-- find all articles by two authors in same shard
-- but plan is not fast path router plannable due to
-- two distribution columns in the query
SELECT title, author_id FROM articles_hash
	WHERE author_id = 7 OR author_id = 8
	ORDER BY author_id ASC, id;
    title    | author_id
---------------------------------------------------------------------
 aseptic     |         7
 auriga      |         7
 arsenous    |         7
 archduchies |         7
 abeyance    |         7
 agatized    |         8
 assembly    |         8
 aerophyte   |         8
 anatine     |         8
 alkylic     |         8
(10 rows)

-- having clause is supported if it goes to a single shard
-- and single dist. key on the query
SELECT author_id, sum(word_count) AS corpus_size FROM articles_hash
	WHERE author_id = 1
	GROUP BY author_id
	HAVING sum(word_count) > 1000
	ORDER BY sum(word_count) DESC;
 author_id | corpus_size
---------------------------------------------------------------------
         1 |       35894
(1 row)

-- fast path planner only support = operator
SELECT * FROM articles_hash WHERE author_id <= 1;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

SELECT * FROM articles_hash WHERE author_id IN (1, 3) ORDER BY 1,2,3,4;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
  3 |         3 | asternal     |      10480
 11 |         1 | alamo        |       1347
 13 |         3 | aseyev       |       2255
 21 |         1 | arcading     |       5890
 23 |         3 | abhorring    |       6799
 31 |         1 | athwartships |       7271
 33 |         3 | autochrome   |       8180
 41 |         1 | aznavour     |      11814
 43 |         3 | affixal      |      12723
(10 rows)

-- queries with CTEs cannot go through fast-path planning
WITH first_author AS ( SELECT id FROM articles_hash WHERE author_id = 1)
SELECT * FROM first_author;
 id
---------------------------------------------------------------------
  1
 11
 21
 31
 41
(5 rows)

-- two CTE joins also cannot go through fast-path planning
WITH id_author AS ( SELECT id, author_id FROM articles_hash WHERE author_id = 1),
id_title AS (SELECT id, title from articles_hash WHERE author_id = 1)
SELECT * FROM id_author, id_title WHERE id_author.id = id_title.id;
 id | author_id | id |    title
---------------------------------------------------------------------
  1 |         1 |  1 | arsenous
 11 |         1 | 11 | alamo
 21 |         1 | 21 | arcading
 31 |         1 | 31 | athwartships
 41 |         1 | 41 | aznavour
(5 rows)

-- this is a different case where each CTE is recursively planned and those goes
-- through the fast-path router planner, but the top level join is not
WITH id_author AS ( SELECT id, author_id FROM articles_hash WHERE author_id = 1),
id_title AS (SELECT id, title from articles_hash WHERE author_id = 2)
SELECT * FROM id_author, id_title WHERE id_author.id = id_title.id;
 id | author_id | id | title
---------------------------------------------------------------------
(0 rows)

-- recursive CTEs are also cannot go through fast
-- path planning
WITH RECURSIVE hierarchy as (
	SELECT *, 1 AS level
		FROM company_employees
		WHERE company_id = 1 and manager_id = 0
	UNION
	SELECT ce.*, (h.level+1)
		FROM hierarchy h JOIN company_employees ce
			ON (h.employee_id = ce.manager_id AND
				h.company_id = ce.company_id AND
				ce.company_id = 1))
SELECT * FROM hierarchy WHERE LEVEL <= 2;
 company_id | employee_id | manager_id | level
---------------------------------------------------------------------
          1 |           1 |          0 |     1
          1 |           2 |          1 |     2
          1 |           3 |          1 |     2
(3 rows)

WITH update_article AS (
    UPDATE articles_hash SET word_count = 10 WHERE id = 1 AND word_count = 9 RETURNING *
)
SELECT * FROM update_article;
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

WITH delete_article AS (
    DELETE FROM articles_hash WHERE id = 1 AND word_count = 10 RETURNING *
)
SELECT * FROM delete_article;
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

-- grouping sets are supported via fast-path
SELECT
	id, substring(title, 2, 1) AS subtitle, count(*)
	FROM articles_hash
	WHERE author_id = 1
	GROUP BY GROUPING SETS ((id),(subtitle))
	ORDER BY id, subtitle;
 id | subtitle | count
---------------------------------------------------------------------
  1 |          |     1
 11 |          |     1
 21 |          |     1
 31 |          |     1
 41 |          |     1
    | l        |     1
    | r        |     2
    | t        |     1
    | z        |     1
(9 rows)

-- queries which involve functions in FROM clause are not supported via fast path planning
SELECT * FROM articles_hash, position('om' in 'Thomas') WHERE author_id = 1;
 id | author_id |    title     | word_count | position
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572 |        3
 11 |         1 | alamo        |       1347 |        3
 21 |         1 | arcading     |       5890 |        3
 31 |         1 | athwartships |       7271 |        3
 41 |         1 | aznavour     |      11814 |        3
(5 rows)

-- sublinks are not supported via fast path planning
SELECT * FROM articles_hash
WHERE author_id IN (SELECT author_id FROM articles_hash WHERE author_id = 2)
ORDER BY articles_hash.id;
 id | author_id |   title    | word_count
---------------------------------------------------------------------
  2 |         2 | abducing   |      13642
 12 |         2 | archiblast |      18185
 22 |         2 | antipope   |       2728
 32 |         2 | amazon     |      11342
 42 |         2 | ausable    |      15885
(5 rows)

-- subqueries are not supported via fast path planning
SELECT articles_hash.id,test.word_count
FROM articles_hash, (SELECT id, word_count FROM articles_hash) AS test WHERE test.id = articles_hash.id
ORDER BY test.word_count DESC, articles_hash.id LIMIT 5;
 id | word_count
---------------------------------------------------------------------
 50 |      19519
 14 |      19094
 48 |      18610
 12 |      18185
 46 |      17702
(5 rows)

SELECT articles_hash.id,test.word_count
FROM articles_hash, (SELECT id, word_count FROM articles_hash) AS test
WHERE test.id = articles_hash.id and articles_hash.author_id = 1
ORDER BY articles_hash.id;
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

-- simple lookup query just works
SELECT *
	FROM articles_hash
	WHERE author_id = 1;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- below query hits a single shard but with multiple filters
-- so cannot go via fast-path
SELECT *
	FROM articles_hash
	WHERE author_id = 1 OR author_id = 17;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- rename the output columns
SELECT id as article_id, word_count * id as random_value
	FROM articles_hash
	WHERE author_id = 1;
 article_id | random_value
---------------------------------------------------------------------
          1 |         9572
         11 |        14817
         21 |       123690
         31 |       225401
         41 |       484374
(5 rows)

-- joins do not go through fast-path planning
SELECT a.author_id as first_author, b.word_count as second_word_count
	FROM articles_hash a, articles_hash b
	WHERE a.author_id = 10 and a.author_id = b.author_id
	LIMIT 3;
 first_author | second_word_count
---------------------------------------------------------------------
           10 |             17277
           10 |              1820
           10 |              6363
(3 rows)

-- single shard select with limit goes through fast-path planning
SELECT *
	FROM articles_hash
	WHERE author_id = 1
	LIMIT 3;
 id | author_id |  title   | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous |       9572
 11 |         1 | alamo    |       1347
 21 |         1 | arcading |       5890
(3 rows)

-- single shard select with limit + offset goes through fast-path planning
SELECT *
	FROM articles_hash
	WHERE author_id = 1
	LIMIT 2
	OFFSET 1;
 id | author_id |  title   | word_count
---------------------------------------------------------------------
 11 |         1 | alamo    |       1347
 21 |         1 | arcading |       5890
(2 rows)

-- single shard select with limit + offset + order by goes through fast-path planning
SELECT *
	FROM articles_hash
	WHERE author_id = 1
	ORDER BY id desc
	LIMIT 2
	OFFSET 1;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
 31 |         1 | athwartships |       7271
 21 |         1 | arcading     |       5890
(2 rows)

-- single shard select with group by on non-partition column goes through fast-path planning
SELECT id
	FROM articles_hash
	WHERE author_id = 1
	GROUP BY id
	ORDER BY id;
 id
---------------------------------------------------------------------
  1
 11
 21
 31
 41
(5 rows)

-- single shard select with distinct goes through fast-path planning
SELECT DISTINCT id
	FROM articles_hash
	WHERE author_id = 1
	ORDER BY id;
 id
---------------------------------------------------------------------
  1
 11
 21
 31
 41
(5 rows)

-- single shard aggregate goes through fast-path planning
SELECT avg(word_count)
	FROM articles_hash
	WHERE author_id = 2;
        avg
---------------------------------------------------------------------
 12356.400000000000
(1 row)

-- max, min, sum, count goes through fast-path planning
SELECT max(word_count) as max, min(word_count) as min,
	   sum(word_count) as sum, count(word_count) as cnt
	FROM articles_hash
	WHERE author_id = 2;
  max  | min  |  sum  | cnt
---------------------------------------------------------------------
 18185 | 2728 | 61782 |   5
(1 row)

-- queries with aggregates and group by goes through fast-path planning
SELECT max(word_count)
	FROM articles_hash
	WHERE author_id = 1
	GROUP BY author_id;
  max
---------------------------------------------------------------------
 11814
(1 row)

-- set operations are not supported via fast-path planning
SELECT * FROM (
	SELECT * FROM articles_hash WHERE author_id = 1
	UNION
	SELECT * FROM articles_hash WHERE author_id = 3
) AS combination
ORDER BY id;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
  3 |         3 | asternal     |      10480
 11 |         1 | alamo        |       1347
 13 |         3 | aseyev       |       2255
 21 |         1 | arcading     |       5890
 23 |         3 | abhorring    |       6799
 31 |         1 | athwartships |       7271
 33 |         3 | autochrome   |       8180
 41 |         1 | aznavour     |      11814
 43 |         3 | affixal      |      12723
(10 rows)

-- function calls in the target list is supported via fast path
SELECT LEFT(title, 1) FROM articles_hash WHERE author_id = 1;
 left
---------------------------------------------------------------------
 a
 a
 a
 a
 a
(5 rows)

-- top-level union queries are supported through recursive planning
-- unions in subqueries are not supported via fast-path planning
SELECT * FROM (
	(SELECT * FROM articles_hash WHERE author_id = 1)
	UNION
	(SELECT * FROM articles_hash WHERE author_id = 1)) uu
ORDER BY 1, 2
LIMIT 5;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- Test various filtering options for router plannable check
-- cannot go through fast-path if there is
-- explicit coercion
SELECT *
	FROM articles_hash
	WHERE author_id = 1::bigint;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- can go through fast-path if there is
-- implicit coercion
-- This doesn't work see the related issue
-- reported https://github.com/citusdata/citus/issues/2605
-- SELECT *
--	FROM articles_hash
--	WHERE author_id = 1.0;
SELECT *
	FROM articles_hash
	WHERE author_id = 68719476736; -- this is bigint
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

-- cannot go through fast-path due to
-- multiple filters on the dist. key
SELECT *
	FROM articles_hash
	WHERE author_id = 1 and author_id >= 1;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- cannot go through fast-path due to
-- multiple filters on the dist. key
SELECT *
	FROM articles_hash
	WHERE author_id = 1 or id = 1;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- goes through fast-path planning because
-- the dist. key is ANDed with the rest of the
-- filters
SELECT *
	FROM articles_hash
	WHERE author_id = 1 and (id = 1 or id = 41);
 id | author_id |  title   | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous |       9572
 41 |         1 | aznavour |      11814
(2 rows)

-- this time there is an OR clause which prevents
-- router planning at all
SELECT *
	FROM articles_hash
	WHERE author_id = 1 and id = 1 or id = 41;
 id | author_id |  title   | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous |       9572
 41 |         1 | aznavour |      11814
(2 rows)

-- goes through fast-path planning because
-- the dist. key is ANDed with the rest of the
-- filters
SELECT *
	FROM articles_hash
	WHERE author_id = 1 and (id = random()::int  * 0);
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

-- not router plannable due to function call on the right side
SELECT *
	FROM articles_hash
	WHERE author_id = (random()::int  * 0 + 1);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- Citus does not qualify this as a fast-path because
-- dist_key = func()
SELECT *
	FROM articles_hash
	WHERE author_id = abs(-1);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- Citus does not qualify this as a fast-path because
-- dist_key = func()
SELECT *
	FROM articles_hash
	WHERE 1 = abs(author_id);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- Citus does not qualify this as a fast-path because
-- dist_key = func()
SELECT *
	FROM articles_hash
	WHERE author_id = abs(author_id - 2);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- the function is not on the dist. key, so qualify as
-- fast-path
SELECT *
	FROM articles_hash
	WHERE author_id = 1 and (id = abs(id - 2));
 id | author_id |  title   | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous |       9572
(1 row)

-- not router plannable due to is true
SELECT *
	FROM articles_hash
	WHERE (author_id = 1) is true;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- router plannable, (boolean expression) = true is collapsed to (boolean expression)
SELECT *
	FROM articles_hash
	WHERE (author_id = 1) = true;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- some more complex quals
SELECT count(*) FROM articles_hash WHERE (author_id = 15) AND (id = 1 OR word_count > 5);
 count
---------------------------------------------------------------------
     0
(1 row)

SELECT count(*) FROM articles_hash WHERE (author_id = 15) OR (id = 1 AND word_count > 5);
 count
---------------------------------------------------------------------
     1
(1 row)

SELECT count(*) FROM articles_hash WHERE (id = 15) OR (author_id = 1 AND word_count > 5);
 count
---------------------------------------------------------------------
     6
(1 row)

SELECT count(*) FROM articles_hash WHERE (id = 15) AND (author_id = 1 OR word_count > 5);
 count
---------------------------------------------------------------------
     1
(1 row)

SELECT count(*) FROM articles_hash WHERE (id = 15) AND (author_id = 1 AND (word_count > 5 OR id  = 2));
 count
---------------------------------------------------------------------
     0
(1 row)

SELECT count(*) FROM articles_hash WHERE (id = 15) AND (title ilike 'a%' AND (word_count > 5 OR author_id  = 2));
 count
---------------------------------------------------------------------
     1
(1 row)

SELECT count(*) FROM articles_hash WHERE (id = 15) AND (title ilike 'a%' AND (word_count > 5 AND author_id  = 2));
 count
---------------------------------------------------------------------
     0
(1 row)

SELECT count(*) FROM articles_hash WHERE (id = 15) AND (title ilike 'a%' AND ((word_count > 5 OR title ilike 'b%' ) AND (author_id  = 2 AND word_count > 50)));
 count
---------------------------------------------------------------------
     0
(1 row)

-- fast-path router plannable, between operator is on another column
SELECT *
	FROM articles_hash
	WHERE (author_id = 1) and id between 0 and 20;
 id | author_id |  title   | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous |       9572
 11 |         1 | alamo    |       1347
(2 rows)

-- fast-path router plannable, partition column expression is and'ed to rest
SELECT *
	FROM articles_hash
	WHERE (author_id = 1) and (id = 1 or id = 31) and title like '%s';
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 31 |         1 | athwartships |       7271
(2 rows)

-- fast-path router plannable, order is changed
SELECT *
	FROM articles_hash
	WHERE (id = 1 or id = 31) and title like '%s' and (author_id = 1);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 31 |         1 | athwartships |       7271
(2 rows)

-- fast-path router plannable
SELECT *
	FROM articles_hash
	WHERE (title like '%s' or title like 'a%') and (author_id = 1);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- fast-path router plannable
SELECT *
	FROM articles_hash
	WHERE (title like '%s' or title like 'a%') and (author_id = 1) and (word_count < 3000 or word_count > 8000);
 id | author_id |  title   | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous |       9572
 11 |         1 | alamo    |       1347
 41 |         1 | aznavour |      11814
(3 rows)

-- window functions are supported with fast-path router plannable
SELECT LAG(title, 1) over (ORDER BY word_count) prev, title, word_count
	FROM articles_hash
	WHERE author_id = 5;
   prev   |  title   | word_count
---------------------------------------------------------------------
          | afrasia  |        864
 afrasia  | adversa  |       3164
 adversa  | antehall |       7707
 antehall | aminate  |       9089
 aminate  | aruru    |      11389
(5 rows)

SELECT LAG(title, 1) over (ORDER BY word_count) prev, title, word_count
	FROM articles_hash
	WHERE author_id = 5
	ORDER BY word_count DESC;
   prev   |  title   | word_count
---------------------------------------------------------------------
 aminate  | aruru    |      11389
 antehall | aminate  |       9089
 adversa  | antehall |       7707
 afrasia  | adversa  |       3164
          | afrasia  |        864
(5 rows)

SELECT id, MIN(id) over (order by word_count)
	FROM articles_hash
	WHERE author_id = 1;
 id | min
---------------------------------------------------------------------
 11 |  11
 21 |  11
 31 |  11
  1 |   1
 41 |   1
(5 rows)

SELECT id, word_count, AVG(word_count) over (order by word_count)
	FROM articles_hash
	WHERE author_id = 1;
 id | word_count |          avg
---------------------------------------------------------------------
 11 |       1347 | 1347.0000000000000000
 21 |       5890 | 3618.5000000000000000
 31 |       7271 | 4836.0000000000000000
  1 |       9572 | 6020.0000000000000000
 41 |      11814 | 7178.8000000000000000
(5 rows)

SELECT word_count, rank() OVER (PARTITION BY author_id ORDER BY word_count)
	FROM articles_hash
	WHERE author_id = 1;
 word_count | rank
---------------------------------------------------------------------
       1347 |    1
       5890 |    2
       7271 |    3
       9572 |    4
      11814 |    5
(5 rows)

-- some more tests on complex target lists
SELECT DISTINCT ON (author_id, id) author_id, id,
	MIN(id) over (order by avg(word_count)) * AVG(id * 5.2 + (1.0/max(word_count))) over (order by max(word_count)) as t1,
	count(*) FILTER (WHERE title LIKE 'al%') as cnt_with_filter,
	count(*) FILTER (WHERE '0300030' LIKE '%3%') as cnt_with_filter_2,
	avg(case when id > 2 then char_length(word_count::text) * (id * strpos(word_count::text, '1')) end) as case_cnt,
	COALESCE(strpos(avg(word_count)::text, '1'), 20)
	FROM articles_hash as aliased_table
	WHERE author_id = 1
	GROUP BY author_id, id
	HAVING count(DISTINCT title) > 0
	ORDER BY author_id, id, sum(word_count) - avg(char_length(title)) DESC, COALESCE(array_upper(ARRAY[max(id)],1) * 5,0) DESC;
 author_id | id |              t1              | cnt_with_filter | cnt_with_filter_2 |        case_cnt        | coalesce
---------------------------------------------------------------------
         1 |  1 |      83.20028854345579490574 |               0 |                 1 |                        |        0
         1 | 11 |     629.20816629547141796586 |               1 |                 1 |    44.0000000000000000 |        1
         1 | 21 |     915.20501693381380745499 |               0 |                 1 | 0.00000000000000000000 |        0
         1 | 31 |    1201.20384890897723321000 |               0 |                 1 |   496.0000000000000000 |        4
         1 | 41 | 109.200247763831844321405335 |               0 |                 1 |   205.0000000000000000 |        1
(5 rows)

-- where false queries are router plannable but not fast-path
SELECT *
	FROM articles_hash
	WHERE false;
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

-- fast-path with false
SELECT *
	FROM articles_hash
	WHERE author_id = 1 and false;
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

-- fast-path with false
SELECT *
	FROM articles_hash
	WHERE author_id = 1 and 1=0;
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

SELECT *
	FROM articles_hash
	WHERE null and author_id = 1;
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

-- we cannot qualify dist_key = X operator Y via
-- fast-path planning
SELECT *
	FROM articles_hash
	WHERE author_id = 1 + 1;
 id | author_id |   title    | word_count
---------------------------------------------------------------------
  2 |         2 | abducing   |      13642
 12 |         2 | archiblast |      18185
 22 |         2 | antipope   |       2728
 32 |         2 | amazon     |      11342
 42 |         2 | ausable    |      15885
(5 rows)

-- where false with immutable function returning false
-- goes through fast-path
SELECT *
	FROM articles_hash a
	WHERE a.author_id = 10 and int4eq(1, 2);
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

-- partition_column is null clause does not prune out any shards,
-- all shards remain after shard pruning, not router plannable
-- not fast-path router either
SELECT *
	FROM articles_hash a
	WHERE a.author_id is null;
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

-- partition_column equals to null clause prunes out all shards
-- no shards after shard pruning, router plannable
-- not fast-path router either
SELECT *
	FROM articles_hash a
	WHERE a.author_id = null;
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

-- union/difference /intersection with where false
-- this query was not originally router plannable, addition of 1=0
-- makes it router plannable but not fast-path
SELECT * FROM (
	SELECT * FROM articles_hash WHERE author_id = 1
	UNION
	SELECT * FROM articles_hash WHERE author_id = 2 and 1=0
) AS combination
ORDER BY id;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- same with the above, but with WHERE false
SELECT * FROM (
	SELECT * FROM articles_hash WHERE author_id = 1
	UNION
	SELECT * FROM articles_hash WHERE author_id = 2 and 1=0
) AS combination WHERE false
ORDER BY id;
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

-- window functions with where false
SELECT word_count, rank() OVER (PARTITION BY author_id ORDER BY word_count)
	FROM articles_hash
	WHERE author_id = 1 and 1=0;
 word_count | rank
---------------------------------------------------------------------
(0 rows)

-- complex query hitting a single shard and a fast-path
SELECT
	count(DISTINCT CASE
			WHEN
				word_count > 100
			THEN
				id
			ELSE
				NULL
			END) as c
	FROM
		articles_hash
	WHERE
		author_id = 5;
 c
---------------------------------------------------------------------
 5
(1 row)

-- queries inside transactions can be fast-path router plannable
BEGIN;
SELECT *
	FROM articles_hash
	WHERE author_id = 1
	ORDER BY id;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

END;
-- queries inside read-only transactions can be fast-path router plannable
SET TRANSACTION READ ONLY;
WARNING:  SET TRANSACTION can only be used in transaction blocks
SELECT *
	FROM articles_hash
	WHERE author_id = 1
	ORDER BY id;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

END;
WARNING:  there is no transaction in progress
-- cursor queries are fast-path router plannable
BEGIN;
DECLARE test_cursor CURSOR FOR
	SELECT *
		FROM articles_hash
		WHERE author_id = 1
		ORDER BY id;
FETCH test_cursor;
 id | author_id |  title   | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous |       9572
(1 row)

FETCH ALL test_cursor;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(4 rows)

FETCH test_cursor; -- fetch one row after the last
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

FETCH BACKWARD test_cursor;
 id | author_id |  title   | word_count
---------------------------------------------------------------------
 41 |         1 | aznavour |      11814
(1 row)

END;
-- queries inside copy can be router plannable
COPY (
	SELECT *
	FROM articles_hash
	WHERE author_id = 1
	ORDER BY id) TO STDOUT;
1	1	arsenous	9572
11	1	alamo	1347
21	1	arcading	5890
31	1	athwartships	7271
41	1	aznavour	11814
-- table creation queries inside can be fast-path router plannable
CREATE TEMP TABLE temp_articles_hash as
	SELECT *
	FROM articles_hash
	WHERE author_id = 1
	ORDER BY id;
-- fast-path router plannable queries may include filter for aggregates
SELECT count(*), count(*) FILTER (WHERE id < 3)
	FROM articles_hash
	WHERE author_id = 1;
 count | count
---------------------------------------------------------------------
     5 |     1
(1 row)

-- prepare queries can be router plannable
PREPARE author_1_articles as
	SELECT *
	FROM articles_hash
	WHERE author_id = 1;
EXECUTE author_1_articles;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_1_articles;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_1_articles;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_1_articles;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_1_articles;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_1_articles;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- parametric prepare queries can be router plannable
PREPARE author_articles(int) as
	SELECT *
	FROM articles_hash
	WHERE author_id = $1;
EXECUTE author_articles(1);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_articles(1);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_articles(1);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_articles(1);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_articles(1);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_articles(1);
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

EXECUTE author_articles(NULL);
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

EXECUTE author_articles(NULL);
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

EXECUTE author_articles(NULL);
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

EXECUTE author_articles(NULL);
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

EXECUTE author_articles(NULL);
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

EXECUTE author_articles(NULL);
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

EXECUTE author_articles(NULL);
 id | author_id | title | word_count
---------------------------------------------------------------------
(0 rows)

PREPARE author_articles_update(int) AS
	UPDATE articles_hash SET title = 'test' WHERE author_id = $1;
EXECUTE author_articles_update(NULL);
EXECUTE author_articles_update(NULL);
EXECUTE author_articles_update(NULL);
EXECUTE author_articles_update(NULL);
EXECUTE author_articles_update(NULL);
EXECUTE author_articles_update(NULL);
EXECUTE author_articles_update(NULL);
-- we don't want too many details. though we're omitting
-- "DETAIL:  distribution column value:", we see it acceptable
-- since the query results verifies the correctness
\set VERBOSITY terse
SELECT author_articles_max_id();
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id();
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id();
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id();
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id();
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id();
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id(1);
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id(1);
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id(1);
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id(1);
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id(1);
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT author_articles_max_id(1);
 author_articles_max_id
---------------------------------------------------------------------
                     41
(1 row)

SELECT * FROM author_articles_id_word_count();
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count();
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count();
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count();
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count();
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count();
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count(1);
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count(1);
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count(1);
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count(1);
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count(1);
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

SELECT * FROM author_articles_id_word_count(1);
 id | word_count
---------------------------------------------------------------------
  1 |       9572
 11 |       1347
 21 |       5890
 31 |       7271
 41 |      11814
(5 rows)

\set VERBOSITY default
-- insert .. select via coordinator could also
-- use fast-path queries
PREPARE insert_sel(int, int) AS
INSERT INTO articles_hash
	SELECT * FROM articles_hash WHERE author_id = $2 AND word_count = $1 OFFSET 0;
EXECUTE insert_sel(1,1);
EXECUTE insert_sel(1,1);
EXECUTE insert_sel(1,1);
EXECUTE insert_sel(1,1);
EXECUTE insert_sel(1,1);
EXECUTE insert_sel(1,1);
-- one final interesting preperad statement
-- where one of the filters is on the target list
PREPARE fast_path_agg_filter(int, int) AS
	SELECT
		count(*) FILTER (WHERE word_count=$1)
	FROM
		articles_hash
	WHERE author_id = $2;
EXECUTE fast_path_agg_filter(1,1);
 count
---------------------------------------------------------------------
     0
(1 row)

EXECUTE fast_path_agg_filter(2,2);
 count
---------------------------------------------------------------------
     0
(1 row)

EXECUTE fast_path_agg_filter(3,3);
 count
---------------------------------------------------------------------
     0
(1 row)

EXECUTE fast_path_agg_filter(4,4);
 count
---------------------------------------------------------------------
     0
(1 row)

EXECUTE fast_path_agg_filter(5,5);
 count
---------------------------------------------------------------------
     0
(1 row)

EXECUTE fast_path_agg_filter(6,6);
 count
---------------------------------------------------------------------
     0
(1 row)

-- views internally become subqueries, so not fast-path router query
SELECT * FROM test_view;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

-- materialized views can be created for fast-path router plannable queries
CREATE MATERIALIZED VIEW mv_articles_hash_empty AS
	SELECT * FROM articles_hash WHERE author_id = 1;
SELECT * FROM mv_articles_hash_empty;
 id | author_id |    title     | word_count
---------------------------------------------------------------------
  1 |         1 | arsenous     |       9572
 11 |         1 | alamo        |       1347
 21 |         1 | arcading     |       5890
 31 |         1 | athwartships |       7271
 41 |         1 | aznavour     |      11814
(5 rows)

SELECT id
	FROM articles_hash
	WHERE author_id = 1;
 id
---------------------------------------------------------------------
  1
 11
 21
 31
 41
(5 rows)

INSERT INTO articles_hash VALUES (51, 1, 'amateus', 1814), (52, 1, 'second amateus', 2824);
-- verify insert is successfull (not router plannable and executable)
SELECT id
	FROM articles_hash
	WHERE author_id = 1;
 id
---------------------------------------------------------------------
  1
 11
 21
 31
 41
 51
 52
(7 rows)

SELECT count(*) FROM collections_list WHERE key = 4;
 count
---------------------------------------------------------------------
     5
(1 row)

SELECT count(*) FROM collections_list_1 WHERE key = 4;
 count
---------------------------------------------------------------------
     5
(1 row)

SELECT count(*) FROM collections_list_2 WHERE key = 4;
 count
---------------------------------------------------------------------
     0
(1 row)

UPDATE collections_list SET value = 15 WHERE key = 4;
SELECT count(*) FILTER (where value = 15) FROM collections_list WHERE key = 4;
 count
---------------------------------------------------------------------
     5
(1 row)

SELECT count(*) FILTER (where value = 15) FROM collections_list_1 WHERE key = 4;
 count
---------------------------------------------------------------------
     5
(1 row)

SELECT count(*) FILTER (where value = 15) FROM collections_list_2 WHERE key = 4;
 count
---------------------------------------------------------------------
     0
(1 row)

-- test INSERT using values from generate_series() and repeat() functions
INSERT INTO authors_reference (id, name) VALUES (generate_series(1, 10), repeat('Migjeni', 3));
SELECT * FROM authors_reference ORDER BY 1, 2;
 id |         name
---------------------------------------------------------------------
  1 | MigjeniMigjeniMigjeni
  2 | MigjeniMigjeniMigjeni
  3 | MigjeniMigjeniMigjeni
  4 | MigjeniMigjeniMigjeni
  5 | MigjeniMigjeniMigjeni
  6 | MigjeniMigjeniMigjeni
  7 | MigjeniMigjeniMigjeni
  8 | MigjeniMigjeniMigjeni
  9 | MigjeniMigjeniMigjeni
 10 | MigjeniMigjeniMigjeni
(10 rows)

