--
-- MULTI_UTILITY_STATEMENTS
--
-- Check that we can run utility statements with embedded SELECT statements on
-- distributed tables. Currently we only support CREATE TABLE AS (SELECT..),
-- DECLARE CURSOR, and COPY ... TO statements.
SET citus.next_shard_id TO 1000000;
CREATE TEMP TABLE lineitem_pricing_summary AS
(
     SELECT
	l_returnflag,
	l_linestatus,
	sum(l_quantity) as sum_qty,
	sum(l_extendedprice) as sum_base_price,
	sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
	sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
	avg(l_quantity) as avg_qty,
	avg(l_extendedprice) as avg_price,
	avg(l_discount) as avg_disc,
	count(*) as count_order
    FROM
	lineitem
    WHERE
	l_shipdate <= date '1998-12-01' - interval '90 days'
    GROUP BY
	l_returnflag,
	l_linestatus
    ORDER BY
	l_returnflag,
	l_linestatus
);
SELECT * FROM lineitem_pricing_summary ORDER BY l_returnflag, l_linestatus;
 l_returnflag | l_linestatus |  sum_qty  | sum_base_price | sum_disc_price |    sum_charge    |       avg_qty       |     avg_price      |        avg_disc        | count_order
---------------------------------------------------------------------
 A            | F            |  75465.00 |   113619873.63 | 107841287.0728 | 112171153.245923 | 25.6334918478260870 | 38593.707075407609 | 0.05055027173913043478 |        2944
 N            | F            |   2022.00 |     3102551.45 |   2952540.7118 |   3072642.770652 | 26.6052631578947368 | 40823.045394736842 | 0.05263157894736842105 |          76
 N            | O            | 149778.00 |   224706948.16 | 213634857.6854 | 222134071.929801 | 25.4594594594594595 | 38195.979629440762 | 0.04939486656467788543 |        5883
 R            | F            |  73156.00 |   108937979.73 | 103516623.6698 | 107743533.784328 | 25.2175112030334367 | 37551.871675284385 | 0.04983798690106859704 |        2901
(4 rows)

-- Test we can handle joins
CREATE TABLE shipping_priority AS
(
    SELECT
	l_orderkey,
	sum(l_extendedprice * (1 - l_discount)) as revenue,
	o_orderdate,
	o_shippriority
    FROM
	customer,
	orders,
	lineitem
    WHERE
	c_mktsegment = 'BUILDING'
	AND c_custkey = o_custkey
	AND l_orderkey = o_orderkey
	AND o_orderdate < date '1995-03-15'
	AND l_shipdate > date '1995-03-15'
    GROUP BY
	l_orderkey,
	o_orderdate,
	o_shippriority
    ORDER BY
	revenue DESC,
	o_orderdate
);
SELECT * FROM shipping_priority;
 l_orderkey |   revenue   | o_orderdate | o_shippriority
---------------------------------------------------------------------
       1637 | 268170.6408 | 02-08-1995  |              0
       9696 | 252014.5497 | 02-20-1995  |              0
      10916 | 242749.1996 | 03-11-1995  |              0
        450 | 221012.3165 | 03-05-1995  |              0
       5347 | 198353.7942 | 02-22-1995  |              0
      10691 | 112800.1020 | 03-14-1995  |              0
        386 | 104975.2484 | 01-25-1995  |              0
       5765 |  88222.7556 | 12-15-1994  |              0
       4707 |  88143.7774 | 02-27-1995  |              0
       5312 |  83750.7028 | 02-24-1995  |              0
       5728 |  70101.6400 | 12-11-1994  |              0
        577 |  57986.6224 | 12-19-1994  |              0
      12706 |  16636.6368 | 11-21-1994  |              0
       3844 |   8851.3200 | 12-29-1994  |              0
      11073 |   7433.6295 | 12-02-1994  |              0
      13924 |   3111.4970 | 12-20-1994  |              0
(16 rows)

DROP TABLE shipping_priority;
-- Check COPY against distributed tables works both when specifying a
-- query as the source, and when directly naming a table.
COPY (
    SELECT
	l_orderkey,
	sum(l_extendedprice * (1 - l_discount)) as revenue,
	o_orderdate,
	o_shippriority
    FROM
	customer,
	orders,
	lineitem
    WHERE
	c_mktsegment = 'BUILDING'
	AND c_custkey = o_custkey
	AND l_orderkey = o_orderkey
	AND o_orderdate < date '1995-03-15'
	AND l_shipdate > date '1995-03-15'
    GROUP BY
	l_orderkey,
	o_orderdate,
	o_shippriority
    ORDER BY
	revenue DESC,
	o_orderdate
) TO stdout;
1637	268170.6408	02-08-1995	0
9696	252014.5497	02-20-1995	0
10916	242749.1996	03-11-1995	0
450	221012.3165	03-05-1995	0
5347	198353.7942	02-22-1995	0
10691	112800.1020	03-14-1995	0
386	104975.2484	01-25-1995	0
5765	88222.7556	12-15-1994	0
4707	88143.7774	02-27-1995	0
5312	83750.7028	02-24-1995	0
5728	70101.6400	12-11-1994	0
577	57986.6224	12-19-1994	0
12706	16636.6368	11-21-1994	0
3844	8851.3200	12-29-1994	0
11073	7433.6295	12-02-1994	0
13924	3111.4970	12-20-1994	0
-- check copying to file
-- (quiet off to force number of copied records to be displayed)
\set QUIET off
COPY nation TO :'dev_null';
COPY 25
\set QUIET on
-- stdout
COPY nation TO STDOUT;
0	ALGERIA                  	0	 haggle. carefully final deposits detect slyly agai
1	ARGENTINA                	1	al foxes promise slyly according to the regular accounts. bold requests alon
2	BRAZIL                   	1	y alongside of the pending deposits. carefully special packages are about the ironic forges. slyly special
3	CANADA                   	1	eas hang ironic, silent packages. slyly regular packages are furiously over the tithes. fluffily bold
4	EGYPT                    	4	y above the carefully unusual theodolites. final dugouts are quickly across the furiously regular d
5	ETHIOPIA                 	0	ven packages wake quickly. regu
6	FRANCE                   	3	refully final requests. regular, ironi
7	GERMANY                  	3	l platelets. regular accounts x-ray: unusual, regular acco
8	INDIA                    	2	ss excuses cajole slyly across the packages. deposits print aroun
9	INDONESIA                	2	 slyly express asymptotes. regular deposits haggle slyly. carefully ironic hockey players sleep blithely. carefull
10	IRAN                     	4	efully alongside of the slyly final dependencies.
11	IRAQ                     	4	nic deposits boost atop the quickly final requests? quickly regula
12	JAPAN                    	2	ously. final, express gifts cajole a
13	JORDAN                   	4	ic deposits are blithely about the carefully regular pa
14	KENYA                    	0	 pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t
15	MOROCCO                  	0	rns. blithely bold courts among the closely regular packages use furiously bold platelets?
16	MOZAMBIQUE               	0	s. ironic, unusual asymptotes wake blithely r
17	PERU                     	1	platelets. blithely pending dependencies use fluffily across the even pinto beans. carefully silent accoun
18	CHINA                    	2	c dependencies. furiously express notornis sleep slyly regular accounts. ideas sleep. depos
19	ROMANIA                  	3	ular asymptotes are about the furious multipliers. express dependencies nag above the ironically ironic account
20	SAUDI ARABIA             	4	ts. silent requests haggle. closely express packages sleep across the blithely
21	VIETNAM                  	2	hely enticingly express accounts. even, final
22	RUSSIA                   	3	 requests against the platelets use never according to the quickly regular pint
23	UNITED KINGDOM           	3	eans boost carefully special requests. accounts are. carefull
24	UNITED STATES            	1	y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be
-- ensure individual cols can be copied out, too
COPY nation(n_name) TO STDOUT;
ALGERIA
ARGENTINA
BRAZIL
CANADA
EGYPT
ETHIOPIA
FRANCE
GERMANY
INDIA
INDONESIA
IRAN
IRAQ
JAPAN
JORDAN
KENYA
MOROCCO
MOZAMBIQUE
PERU
CHINA
ROMANIA
SAUDI ARABIA
VIETNAM
RUSSIA
UNITED KINGDOM
UNITED STATES
-- Test that we can create on-commit drop tables, along with changing column names
BEGIN;
CREATE TEMP TABLE customer_few (customer_key) ON COMMIT DROP AS
    (SELECT * FROM customer WHERE c_nationkey = 1 ORDER BY c_custkey LIMIT 10);
SELECT customer_key, c_name, c_address
       FROM customer_few ORDER BY customer_key LIMIT 5;
 customer_key |       c_name       |                c_address
---------------------------------------------------------------------
            3 | Customer#000000003 | MG9kdTD2WBHm
           14 | Customer#000000014 | KXkletMlL2JQEA
           30 | Customer#000000030 | nJDsELGAavU63Jl0c5NKsKfL8rIJQQkQnYL2QJY
           59 | Customer#000000059 | zLOCP0wh92OtBihgspOGl4
          106 | Customer#000000106 | xGCOEAUjUNG
(5 rows)

COMMIT;
SELECT customer_key, c_name, c_address
       FROM customer_few ORDER BY customer_key LIMIT 5;
ERROR:  relation "customer_few" does not exist
-- Test DECLARE CURSOR .. WITH HOLD without parameters that calls ReScan on the top-level CustomScan
CREATE TABLE cursor_me (x int, y int);
SELECT create_distributed_table('cursor_me', 'x');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

INSERT INTO cursor_me SELECT s/10, s FROM generate_series(1, 100) s;
DECLARE holdCursor CURSOR WITH HOLD FOR
		SELECT * FROM cursor_me WHERE x = 1 ORDER BY y;
FETCH NEXT FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 10
(1 row)

FETCH FORWARD 3 FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 11
 1 | 12
 1 | 13
(3 rows)

FETCH LAST FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 19
(1 row)

FETCH BACKWARD 3 FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 18
 1 | 17
 1 | 16
(3 rows)

FETCH FORWARD 3 FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 17
 1 | 18
 1 | 19
(3 rows)

CLOSE holdCursor;
-- Test DECLARE CURSOR .. WITH HOLD inside transaction block
BEGIN;
DECLARE holdCursor CURSOR WITH HOLD FOR
		SELECT * FROM cursor_me WHERE x = 1 ORDER BY y;
FETCH 3 FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 10
 1 | 11
 1 | 12
(3 rows)

FETCH BACKWARD 3 FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 11
 1 | 10
(2 rows)

FETCH FORWARD 3 FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 10
 1 | 11
 1 | 12
(3 rows)

COMMIT;
FETCH 3 FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 13
 1 | 14
 1 | 15
(3 rows)

CLOSE holdCursor;
-- Test DECLARE NO SCROLL CURSOR .. WITH HOLD inside transaction block
BEGIN;
DECLARE holdCursor NO SCROLL CURSOR WITH HOLD FOR
		SELECT * FROM cursor_me WHERE x = 1 ORDER BY y;
FETCH 3 FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 10
 1 | 11
 1 | 12
(3 rows)

FETCH FORWARD 3 FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 13
 1 | 14
 1 | 15
(3 rows)

COMMIT;
FETCH 3 FROM holdCursor;
 x | y
---------------------------------------------------------------------
 1 | 16
 1 | 17
 1 | 18
(3 rows)

FETCH BACKWARD 3 FROM holdCursor;
ERROR:  cursor can only scan forward
HINT:  Declare it with SCROLL option to enable backward scan.
CLOSE holdCursor;
-- Test DECLARE CURSOR .. WITH HOLD with parameter
CREATE OR REPLACE FUNCTION declares_cursor(p int)
RETURNS void AS $$
	DECLARE c CURSOR WITH HOLD FOR SELECT * FROM cursor_me WHERE x = $1;
$$ LANGUAGE SQL;
SELECT declares_cursor(5);
 declares_cursor
---------------------------------------------------------------------

(1 row)

FETCH NEXT FROM c;
 x | y
---------------------------------------------------------------------
 5 | 50
(1 row)

FETCH FORWARD 3 FROM c;
 x | y
---------------------------------------------------------------------
 5 | 51
 5 | 52
 5 | 53
(3 rows)

FETCH LAST FROM c;
 x | y
---------------------------------------------------------------------
 5 | 59
(1 row)

FETCH BACKWARD 3 FROM c;
 x | y
---------------------------------------------------------------------
 5 | 58
 5 | 57
 5 | 56
(3 rows)

FETCH FORWARD 3 FROM c;
 x | y
---------------------------------------------------------------------
 5 | 57
 5 | 58
 5 | 59
(3 rows)

CLOSE c;
-- Test DECLARE CURSOR .. WITH HOLD without parameter
CREATE OR REPLACE FUNCTION declares_cursor_2()
RETURNS void AS $$
	DECLARE c2 CURSOR WITH HOLD FOR SELECT * FROM cursor_me;
$$ LANGUAGE SQL;
SELECT declares_cursor_2();
 declares_cursor_2
---------------------------------------------------------------------

(1 row)

-- Test DECLARE CURSOR .. WITH HOLD with parameter on non-dist key
CREATE OR REPLACE FUNCTION declares_cursor_3(p int)
RETURNS void AS $$
	DECLARE c3 CURSOR WITH HOLD FOR SELECT * FROM cursor_me WHERE y = $1;
$$ LANGUAGE SQL;
SELECT declares_cursor_3(5);
 declares_cursor_3
---------------------------------------------------------------------

(1 row)

FETCH NEXT FROM c3;
 x | y
---------------------------------------------------------------------
 0 | 5
(1 row)

FETCH FORWARD 3 FROM c3;
 x | y
---------------------------------------------------------------------
(0 rows)

FETCH LAST FROM c3;
 x | y
---------------------------------------------------------------------
 0 | 5
(1 row)

FETCH BACKWARD 3 FROM c3;
 x | y
---------------------------------------------------------------------
(0 rows)

FETCH FORWARD 3 FROM c3;
 x | y
---------------------------------------------------------------------
 0 | 5
(1 row)

CLOSE c3;
-- Test DECLARE CURSOR .. WITH HOLD with parameter on dist key, but not fast-path planner
CREATE OR REPLACE FUNCTION declares_cursor_4(p int)
RETURNS void AS $$
	DECLARE c4 CURSOR WITH HOLD FOR SELECT *, (SELECT 1) FROM cursor_me WHERE x = $1;
$$ LANGUAGE SQL;
SELECT declares_cursor_4(5);
 declares_cursor_4
---------------------------------------------------------------------

(1 row)

FETCH NEXT FROM c4;
 x | y  | ?column?
---------------------------------------------------------------------
 5 | 50 |        1
(1 row)

FETCH FORWARD 3 FROM c4;
 x | y  | ?column?
---------------------------------------------------------------------
 5 | 51 |        1
 5 | 52 |        1
 5 | 53 |        1
(3 rows)

FETCH LAST FROM c4;
 x | y  | ?column?
---------------------------------------------------------------------
 5 | 59 |        1
(1 row)

FETCH BACKWARD 3 FROM c4;
 x | y  | ?column?
---------------------------------------------------------------------
 5 | 58 |        1
 5 | 57 |        1
 5 | 56 |        1
(3 rows)

FETCH FORWARD 3 FROM c4;
 x | y  | ?column?
---------------------------------------------------------------------
 5 | 57 |        1
 5 | 58 |        1
 5 | 59 |        1
(3 rows)

CLOSE c4;
CREATE OR REPLACE FUNCTION cursor_plpgsql(p int)
RETURNS SETOF int AS $$
DECLARE
  val int;
  my_cursor CURSOR (a INTEGER) FOR SELECT y FROM cursor_me WHERE x = $1 ORDER BY y;
BEGIN
   -- Open the cursor
   OPEN my_cursor(p);

   LOOP
      FETCH my_cursor INTO val;
      EXIT WHEN NOT FOUND;

      RETURN NEXT val;
   END LOOP;

   -- Close the cursor
   CLOSE my_cursor;
END; $$
LANGUAGE plpgsql;
SELECT cursor_plpgsql(4);
 cursor_plpgsql
---------------------------------------------------------------------
             40
             41
             42
             43
             44
             45
             46
             47
             48
             49
(10 rows)

DROP FUNCTION declares_cursor(int);
DROP FUNCTION cursor_plpgsql(int);
DROP TABLE cursor_me;
-- Test DECLARE CURSOR statement with SCROLL
DECLARE holdCursor SCROLL CURSOR WITH HOLD FOR
        SELECT l_orderkey, l_linenumber, l_quantity, l_discount
        FROM lineitem
        ORDER BY l_orderkey, l_linenumber;
FETCH NEXT FROM holdCursor;
 l_orderkey | l_linenumber | l_quantity | l_discount
---------------------------------------------------------------------
          1 |            1 |      17.00 |       0.04
(1 row)

FETCH FORWARD 5 FROM holdCursor;
 l_orderkey | l_linenumber | l_quantity | l_discount
---------------------------------------------------------------------
          1 |            2 |      36.00 |       0.09
          1 |            3 |       8.00 |       0.10
          1 |            4 |      28.00 |       0.09
          1 |            5 |      24.00 |       0.10
          1 |            6 |      32.00 |       0.07
(5 rows)

FETCH LAST FROM holdCursor;
 l_orderkey | l_linenumber | l_quantity | l_discount
---------------------------------------------------------------------
      14947 |            2 |      29.00 |       0.04
(1 row)

FETCH BACKWARD 5 FROM holdCursor;
 l_orderkey | l_linenumber | l_quantity | l_discount
---------------------------------------------------------------------
      14947 |            1 |      14.00 |       0.09
      14946 |            2 |      37.00 |       0.01
      14946 |            1 |      38.00 |       0.00
      14945 |            6 |      37.00 |       0.05
      14945 |            5 |      44.00 |       0.08
(5 rows)

-- Test WITHOUT HOLD cursors inside transactions
BEGIN;
DECLARE noHoldCursor SCROLL CURSOR FOR
        SELECT l_orderkey, l_linenumber, l_quantity, l_discount
        FROM lineitem
        ORDER BY l_orderkey, l_linenumber;
FETCH ABSOLUTE 5 FROM noHoldCursor;
 l_orderkey | l_linenumber | l_quantity | l_discount
---------------------------------------------------------------------
          1 |            5 |      24.00 |       0.10
(1 row)

FETCH BACKWARD noHoldCursor;
 l_orderkey | l_linenumber | l_quantity | l_discount
---------------------------------------------------------------------
          1 |            4 |      28.00 |       0.09
(1 row)

COMMIT;
FETCH ABSOLUTE 5 FROM noHoldCursor;
ERROR:  cursor "noholdcursor" does not exist
-- Test we don't throw an error for DROP IF EXISTS
DROP DATABASE IF EXISTS not_existing_database;
NOTICE:  database "not_existing_database" does not exist, skipping
DROP TABLE IF EXISTS not_existing_table;
NOTICE:  table "not_existing_table" does not exist, skipping
DROP SCHEMA IF EXISTS not_existing_schema;
NOTICE:  schema "not_existing_schema" does not exist, skipping
