-- All the tables, functions, etc. in this test file are created in
-- qp_misc_rio schema, so that they don't interfere with other tests
-- running in parallel.

-- start_ignore
create schema qp_misc_rio;

CREATE LANGUAGE plpython3u;
-- end_ignore
set search_path to qp_misc_rio;

-- ----------------------------------------------------------------------
-- Test: 9
-- ----------------------------------------------------------------------
-- Expect NO ERROR like "ERROR:  Unexpected internal error (cdbsetop.c)"



create table tb_function_test(a numeric,b numeric,c numeric,d character varying(20),e character varying(20)) distributed by (b,c);
select *,row_number() over(partition by a,b,c order by d),row_number() over(partition by a,b,c order by e) from tb_function_test where  b=1;

select *,row_number() over(partition by a,b,c order by d),row_number() over(partition by a,b,c order by e) from tb_function_test where  c=1;

select *,row_number() over(partition by a,b,c order by d),row_number() over(partition by a,b,c order by e) from tb_function_test where  a=1;

select *,row_number() over(partition by a,b,c order by d),row_number() over(partition by a,b,c order by e) from tb_function_test where b=(select a from tb_function_test limit 1);

-- ----------------------------------------------------------------------
-- Test: 11
-- ----------------------------------------------------------------------



create table t11_t(a bigint, b bigint) distributed by (a);
insert into t11_t select a, a / 10 from generate_series(1, 100)a;

select sum((select count(*) from t11_t group by b having b = s.b)) as sum_col from (select * from t11_t order by a)s group by b order by sum_col;

-- ----------------------------------------------------------------------
-- Test: 15
-- ----------------------------------------------------------------------
-- aggregate over partition by
-- GPDB_10_MERGE_FIXME: Here we cast the unknown typed literal to text. After
-- we move past postgres 10 we can drop the cast.
select state,
       sum(revenue) over (partition by state)
from
   (select 'A'::text as enc_email, 1 as revenue) b
   join (select 'A'::text as enc_email, 'B'::text as state ) c using(enc_email)
group by 1,b.revenue;

-- ----------------------------------------------------------------------
-- Test: 16
-- ----------------------------------------------------------------------


set enable_parallel = off;

CREATE TABLE testtable0000 AS SELECT spend, row_number() OVER (PARTITION BY 0) AS i, (spend % 2) AS r
FROM (select generate_series(1,10) as spend) x DISTRIBUTED RANDOMLY;

CREATE TABLE testtable0001 AS SELECT *, CASE WHEN (i % 6 = 0) THEN '00'
     WHEN (i % 6 = 1) THEN '11'
     WHEN (i % 6 = 2) THEN '22'
     WHEN (i % 6 = 3) THEN '33'
     WHEN (i % 6 = 4) THEN '44'
     WHEN (i % 6 = 5) THEN '55' END AS s1,
CASE WHEN (i % 6 = 0) THEN '00'
     WHEN (i % 6 = 1) THEN '11'
     WHEN (i % 6 = 2) THEN '22'
     WHEN (i % 6 = 3) THEN '33'
     WHEN (i % 6 = 4) THEN '44'
     WHEN (i % 6 = 5) THEN '55' END AS s2,
CASE WHEN (i % 6 = 0) THEN '00'
     WHEN (i % 6 = 1) THEN '11'
     WHEN (i % 6 = 2) THEN '22'
     WHEN (i % 6 = 3) THEN '33'
     WHEN (i % 6 = 4) THEN '44'
     WHEN (i % 6 = 5) THEN '55' END AS s3,
CASE WHEN (i % 6 = 0) THEN '00'
     WHEN (i % 6 = 1) THEN '11'
     WHEN (i % 6 = 2) THEN '22'
     WHEN (i % 6 = 3) THEN '33'
     WHEN (i % 6 = 4) THEN '44'
     WHEN (i % 6 = 5) THEN '55' END AS s4,
CASE WHEN (i % 6 = 0) THEN '00'
     WHEN (i % 6 = 1) THEN '11'
     WHEN (i % 6 = 2) THEN '22'
     WHEN (i % 6 = 3) THEN '33'
     WHEN (i % 6 = 4) THEN '44'
     WHEN (i % 6 = 5) THEN '55' END AS s5 FROM testtable0000;



CREATE VIEW testtable0002
AS SELECT testtable0001.*,
          miro_foo.s1_xform
FROM testtable0001
JOIN (SELECT s1,
                  COALESCE((AVG(CAST(r AS INT)) - 0.010000), 0)
		  AS s1_xform
           FROM testtable0001 GROUP BY s1)
	   AS miro_foo
ON testtable0001.s1 = miro_foo.s1;

SELECT MIN(s1_xform), MIN(s1_xform) FROM testtable0002;




SELECT s1,
       SUM(CAST(r AS INT)),
       COUNT(*) FILTER (WHERE r IS NOT NULL),
       COUNT(*)
FROM testtable0002 GROUP BY s1 order by s1;


CREATE VIEW testtable0003
AS SELECT testtable0002.*,
          miro_foo.s2_xform
FROM testtable0002
JOIN (SELECT s2,
                  COALESCE((AVG(CAST(r AS INT)) - 0.020000), 0)
		  AS s2_xform
           FROM testtable0002 GROUP BY s2)
	   AS miro_foo
ON testtable0002.s2 = miro_foo.s2;

SELECT MIN(s2_xform), MIN(s2_xform) FROM testtable0003;



SELECT s2,
       SUM(CAST(r AS INT)),
       COUNT(*) FILTER (WHERE r IS NOT NULL),
       COUNT(*)
FROM testtable0003 GROUP BY s2 order by s2;


CREATE VIEW testtable0004
AS SELECT testtable0003.*,
          miro_foo.s3_xform
FROM testtable0003
JOIN (SELECT s3,
                  COALESCE((AVG(CAST(r AS INT)) - 0.030000), 0)
		  AS s3_xform
           FROM testtable0003 GROUP BY s3)
	   AS miro_foo
ON testtable0003.s3 = miro_foo.s3;

SELECT MIN(s3_xform), MIN(s3_xform) FROM testtable0004;



SELECT s3,
       SUM(CAST(r AS INT)),
       COUNT(*) FILTER (WHERE r IS NOT NULL),
       COUNT(*)
FROM testtable0004 GROUP BY s3 order by s3;


CREATE VIEW testtable0005
AS SELECT testtable0004.*,
          miro_foo.s4_xform
FROM testtable0004
JOIN (SELECT s4,
                  COALESCE((AVG(CAST(r AS INT)) - 0.040000), 0)
		  AS s4_xform
           FROM testtable0004 GROUP BY s4)
	   AS miro_foo
ON testtable0004.s4 = miro_foo.s4;

SELECT MIN(s4_xform), MIN(s4_xform) FROM testtable0005;



SELECT s4,
       SUM(CAST(r AS INT)),
       COUNT(*) FILTER (WHERE r IS NOT NULL),
       COUNT(*)
FROM testtable0005 GROUP BY s4 order by s4;

CREATE VIEW testtable0006
AS SELECT testtable0005.*,
          miro_foo.s5_xform
FROM testtable0005
JOIN (SELECT s5,
                  COALESCE((AVG(CAST(r AS INT)) - 0.050000), 0)
		  AS s5_xform
           FROM testtable0005 GROUP BY s5)
	   AS miro_foo
ON testtable0005.s5 = miro_foo.s5;

SELECT MIN(s5_xform), MIN(s5_xform) FROM testtable0006;
reset enable_parallel;



SELECT s5,
       SUM(CAST(r AS INT)),
       COUNT(*) FILTER (WHERE r IS NOT NULL),
       COUNT(*)
FROM testtable0006 GROUP BY s5 order by s5;

-- ----------------------------------------------------------------------
-- Test: 18
-- ----------------------------------------------------------------------



CREATE FUNCTION t18_pytest() RETURNS VOID LANGUAGE plpython3u AS $$
  plpy.execute("SHOW client_min_messages")
$$;

SELECT t18_pytest();

DROP FUNCTION t18_pytest();

CREATE FUNCTION t18_pytest() RETURNS VARCHAR LANGUAGE plpython3u AS $$
  return plpy.execute("SELECT setting FROM pg_settings WHERE name='client_min_messages'")[0]['setting']
$$;

SELECT t18_pytest();

-- ----------------------------------------------------------------------
-- Test: 20
-- ----------------------------------------------------------------------
select distinct paramname
from gp_toolkit.gp_param_setting('allow_system_table_mods');

select distinct paramname
from gp_toolkit.gp_param_setting('max_resource_queues');

-- ----------------------------------------------------------------------
-- Test: 21
-- ----------------------------------------------------------------------


create table parts (
    partnum     text,
    cost        float8
);

create table shipped (
    ttype       char(2),
    ordnum      int4,
    partnum     text,
    value       float8
);

create view shipped_view as
    select * from shipped where ttype = 'wt';


insert into parts (partnum, cost) values (1, 1234.56);

insert into shipped (ordnum, partnum, value)
    values (0, 1, (select cost from parts where partnum = '1'));

select * from shipped_view ORDER BY 1,2;

-- ----------------------------------------------------------------------
-- Test: 23
-- ----------------------------------------------------------------------


CREATE OR REPLACE FUNCTION func_array_argument_plpythonu(arg FLOAT8[])
RETURNS FLOAT8
AS $$
    return arg[0];
$$ LANGUAGE plpython3u;

SELECT func_array_argument_plpythonu('{1,2,3}');

-- ----------------------------------------------------------------------
-- Test: 27
-- ----------------------------------------------------------------------



set gp_autostats_mode to 'ON_NO_STATS';
set gp_autostats_mode_in_functions to 'NONE';

-- prepare function and table
CREATE OR REPLACE FUNCTION func_truncate_load_plpgsql()
RETURNS void
AS $$
    BEGIN
        EXECUTE 'TRUNCATE TABLE tbl_truncate_load;';
        EXECUTE 'INSERT INTO tbl_truncate_load SELECT i, i FROM generate_series(1, 500000) i;';
    END;
$$ LANGUAGE plpgsql;

CREATE TABLE tbl_truncate_load (c1 int, c2 int) DISTRIBUTED BY (c1);

-- show default GUC value for gp_autostats_mode_in_functions
SELECT current_setting('gp_autostats_mode');
SELECT current_setting('gp_autostats_mode_in_functions');


-- test function with GUC value for gp_autostats_mode_in_functions as ON_NO_STATS
SELECT set_config('gp_autostats_mode_in_functions', 'ON_NO_STATS', False);

TRUNCATE TABLE tbl_truncate_load;
INSERT INTO tbl_truncate_load SELECT i, i FROM generate_series(1, 100000) i;
-- check if the difference between reltuples and number of records for table tbl_truncate_load is within +-5%
SELECT CASE WHEN abs(reltuples-100000)/100000 < 0.05 THEN 'reltuples and number of records for table tbl_truncate_load are consistent'
            ELSE 'reltuples and number of records for table tbl_truncate_load are inconsistent'
       END AS remark
FROM pg_class WHERE oid='tbl_truncate_load'::regclass;

SELECT COUNT(*) FROM tbl_truncate_load;

SELECT func_truncate_load_plpgsql();
-- check if the difference between reltuples and number of records for table tbl_truncate_load is within +-5%
SELECT CASE WHEN abs(reltuples-500000)/500000 < 0.05 THEN 'reltuples and number of records for table tbl_truncate_load are consistent'
            ELSE 'reltuples and number of records for table tbl_truncate_load are inconsistent'
       END AS remark
FROM pg_class WHERE oid='tbl_truncate_load'::regclass;
SELECT count(*) FROM tbl_truncate_load;


-- test function with GUC value for gp_autostats_mode_in_functions as NONE
SELECT set_config('gp_autostats_mode_in_functions', 'NONE', False);

TRUNCATE TABLE tbl_truncate_load;
INSERT INTO tbl_truncate_load SELECT i, i FROM generate_series(1, 100000) i;

-- check if the difference between reltuples and number of records for table tbl_truncate_load is within +-5%
SELECT CASE WHEN abs(reltuples-100000)/100000 < 0.05 THEN 'reltuples and number of records for table tbl_truncate_load are consistent'
            ELSE 'reltuples and number of records for table tbl_truncate_load are inconsistent'
       END AS remark
FROM pg_class WHERE oid='tbl_truncate_load'::regclass;

SELECT COUNT(*) FROM tbl_truncate_load;

SELECT func_truncate_load_plpgsql();

-- check if the difference between reltuples and number of records for table tbl_truncate_load is within +-5%
SELECT CASE WHEN abs(reltuples-500000)/500000 < 0.05 THEN 'reltuples and number of records for table tbl_truncate_load are consistent'
            ELSE 'reltuples and number of records for table tbl_truncate_load are inconsistent'
       END AS remark
FROM pg_class WHERE oid='tbl_truncate_load'::regclass;

SELECT count(*) FROM tbl_truncate_load;


-- clean up
RESET ALL;

-- ----------------------------------------------------------------------
-- Test: 30
-- ----------------------------------------------------------------------



CREATE TABLE nt (i INT, j INT) DISTRIBUTED BY (j);
INSERT INTO nt SELECT i, i FROM generate_series(1,10) i;

SELECT lag(j) OVER (ORDER BY i ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) FROM nt;
SELECT lag(j) OVER (w) FROM nt WINDOW w AS (ORDER BY i ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING);
SELECT lag(x) OVER (wx) FROM (SELECT 1 AS x, 2 AS y, 3 AS z) s WINDOW w AS (PARTITION BY y ORDER BY z), wx AS (w);

SELECT lead(j) OVER (ORDER BY i ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) FROM nt;
SELECT lead(j) OVER (w) FROM nt WINDOW w AS (ORDER BY i ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING);
SELECT lead(x) OVER (wx) FROM (SELECT 1 AS x, 2 AS y, 3 AS z) s WINDOW w AS (PARTITION BY y ORDER BY z), wx AS (w);

-- ----------------------------------------------------------------------
-- Test: 33
-- ----------------------------------------------------------------------

create table ccdd1 (a, b) as (select 1, 1 union select 1, 1 union select 1, 1);

select * from ccdd1;

-- ----------------------------------------------------------------------
-- Test: 34
-- ----------------------------------------------------------------------
-- This is expected to fail, with an error along the lines of:
-- function cannot execute on a QE slice because it accesses relation "qp_misc_rio.testdata_in"

set search_path to qp_misc_rio;

CREATE TABLE testdata_in ( c1 INT, c2 INT ) DISTRIBUTED BY (c1);
INSERT INTO testdata_in SELECT i, i FROM generate_series(1,10) i;

CREATE OR REPLACE FUNCTION func_plpythonu(n INT) RETURNS SETOF testdata_in
AS $$
        sqlstm = "SELECT * FROM testdata_in WHERE c1 <= %d ORDER BY c1;" % n
        return plpy.execute(sqlstm);
$$ LANGUAGE plpython3u;

INSERT INTO testdata_in SELECT * FROM func_plpythonu(2);

-- ----------------------------------------------------------------------
-- Test: 35
-- ----------------------------------------------------------------------

CREATE OR REPLACE FUNCTION func_plpythonu2(x INT)
RETURNS INT
AS $$
     plpy.execute('DROP TABLE IF EXISTS tbl_plpythonu;')
     plpy.execute('CREATE TEMP TABLE tbl_plpythonu(col INT) DISTRIBUTED RANDOMLY;')
     for i in range(0, x):
         plpy.execute('INSERT INTO tbl_plpythonu VALUES(%d)' % i);
     return plpy.execute('SELECT COUNT(*) AS col FROM tbl_plpythonu;')[0]['col']
 $$ LANGUAGE plpython3u;


SELECT func_plpythonu2(200);

-- ----------------------------------------------------------------------
-- Test: 38
-- ----------------------------------------------------------------------

-- start_ignore
drop role if exists triggertest_nopriv_a;
drop role if exists triggertest_nopriv_b;
-- end_ignore

-- Create a non-privileged user triggertest_nopriv_a
create role triggertest_nopriv_a with login ;

-- Create another non-privileged user triggertest_nopriv_b
create role triggertest_nopriv_b with login ;

GRANT ALL ON SCHEMA qp_misc_rio TO triggertest_nopriv_a;
GRANT ALL ON SCHEMA qp_misc_rio TO triggertest_nopriv_b;

-- Connect as non-privileged user "triggertest_nopriv_a"
SET ROLE triggertest_nopriv_a;
select user;

-- Create test table emp
CREATE TABLE emp (
    empname           text NOT NULL,
    salary            integer
);
-- Create a trigger function process_emp_audit()
begin;
create or replace function process_emp_audit() returns trigger as $$
begin
    raise notice '%', new.salary;
    return null;
end;
$$ language plpgsql security definer;
revoke all on function process_emp_audit() from public;
commit;

-- Create trigger using the trigger function

create trigger emp_audit
after insert on emp
    for each row execute procedure process_emp_audit();

-- Verified the trigger works correctly
insert into emp values ('Tammy', 100000);

-- connect as non-privileged user "triggertest_nopriv_b"
SET ROLE triggertest_nopriv_b;
select user;

-- Create test table emp
DROP TABLE IF EXISTS my_emp;
CREATE TABLE my_emp (
    empname           text NOT NULL,
    salary            integer
);

-- Create trigger using the trigger function process_emp_audit(),
-- which the current user does NOT have EXECUTE permission
create trigger my_emp_audit
after insert on my_emp
    for each row execute procedure process_emp_audit();

-- Verify that after grant trigger function's EXECUTE
-- permission, trigger can be created and executed correctly
-- Connect as trigger function's owner and grant EXECUTE permission
SET ROLE triggertest_nopriv_a;
grant execute on function process_emp_audit() to triggertest_nopriv_b;

-- connect as non-privileged user "triggertest_nopriv_b"
SET ROLE triggertest_nopriv_b;

-- Create trigger using the trigger function process_emp_audit(),
-- which the current user now has EXECUTE permission
-- the trigger should be created successfully
create trigger my_emp_audit
after insert on my_emp
    for each row execute procedure process_emp_audit();

-- Verified trigger can be run correctly
insert into my_emp values ('Tammy', 100000);

-- Now to confirm that we only check trigger function's EXECUTE
-- permission at trigger create time, but not at trigger run time
-- by revoking EXECUTE permission from triggertest_nopriv_b after
-- the trigger has been created
-- Connect as trigger function's owner and revoke EXECUTE permission
SET ROLE triggertest_nopriv_a;
revoke execute on function process_emp_audit() from triggertest_nopriv_b;

-- connect as non-privileged user "triggertest_nopriv_b"
SET ROLE triggertest_nopriv_b;

-- Verified that the existing trigger can still work
-- even the current user does NOT have the EXECUTE permission
-- on the trigger function.
insert into my_emp values ('Sammy', 100001);

-- Clean up
RESET ROLE;

-- ----------------------------------------------------------------------
-- Test: row_number() in subquery, with grouping in outer query
-- ----------------------------------------------------------------------

create table bfv_legacy_mpp2(a int);

insert into bfv_legacy_mpp2 values (generate_series(1,10));

select  median(a), avg(a)
from
(
    select a,row_number() over (order by a)
    from bfv_legacy_mpp2
) sub1
group by a
order by a;


-- ----------------------------------------------------------------------
-- Test: to_date() boundaries.
--
-- to_date() used to not check the input like the date input function
-- does. The fix was submitted to upstream PostgreSQL and fixed there in
-- version 8.4.16 (commit 5c4eb9166e.)
-- ----------------------------------------------------------------------
select to_date('-4713-11-23', 'yyyy-mm-dd');
select to_date('-4713-11-24', 'yyyy-mm-dd');
select to_date('5874897-12-31', 'yyyy-mm-dd');
select to_date('5874898-01-01', 'yyyy-mm-dd');
