-- These tests verify that vacuum freeze correctly updates age of auxiliary
-- tables along with the age of a parent appendonly table

-- First, create some helper functions.

CREATE TEMPORARY TABLE dummytable (id int4) distributed randomly;

CREATE FUNCTION advance_xid_counter(n integer) RETURNS void as $$
declare
  i integer;
begin
  -- do multiple updates to advance the XID counter
  -- The purpose of the exception block is to begin a new subtransaction for
  -- each command, to consume an XID.
  for i in 1..n loop
    begin
      insert into dummytable values (i);
    exception when others then
      raise notice 'something went wrong: %', sqlerrm;
    end;
  end loop;
end;
$$ language 'plpgsql';

CREATE FUNCTION classify_age(age integer) RETURNS text AS $$
  SELECT CASE WHEN $1 < 0 THEN 'negative'
              WHEN $1 = 0 THEN 'zero'
	      WHEN $1 < 50 THEN 'very young' -- less than vacuum_freeze_min_age=50 that we use below
	      WHEN $1 < 100 THEN 'young' -- recently processed by vacuum freeze
	      ELSE 'old' END; -- not frozen
$$ LANGUAGE SQL IMMUTABLE STRICT;

CREATE TYPE rel_ages AS (segid integer, relname text, age integer);

-- Get age(relfrozenxid) of a table, and all its auxiliary tables. On master,
-- and on all segments. For AO and CO table relfrozenxid = 0 and should stay
-- 0. So, essentially base AO / CO tables should not show-up in the results.
CREATE OR REPLACE FUNCTION aux_rel_ages(testrelid regclass) RETURNS SETOF rel_ages as
$$
declare
  rec rel_ages;
begin
  for rec in select gp_segment_id, replace(relname, testrelid::oid::text, '<oid>'), age(relfrozenxid)
    from pg_class
    where relkind in ('r','t','o','b','M') and relam in (2, 3434, 3435)
    and (relname like '%\_' || testrelid::oid or oid = testrelid::oid )
    and not relfrozenxid = 0
  loop
    return next rec;
  end loop;

  for rec in select gp_segment_id, replace(relname, testrelid::oid::text, '<oid>'), age(relfrozenxid)
    from gp_dist_random('pg_class')
    where relkind in ('r','t','o','b','M') and relam in (2, 3434, 3435)
    and (relname like '%\_' || testrelid::oid or oid = testrelid::oid )
    and not relfrozenxid = 0
  loop
    return next rec;
  end loop;
end;
$$ language plpgsql;


-- Start tests
--
-- The basic test structure is:
-- 1. CREATE TABLE, leave it empty
-- 2. Run some commands, to advance XID counter
-- 3. VACUUM
-- 4. Verify that the relfrozenxid was advanced by the vacuum
--
set vacuum_freeze_min_age = 50;

create table test_table_heap (id int, col1 int) with (appendonly=false);
create table test_table_heap_with_toast (id int, col1 int, col2 text) with (appendonly=false);
create table test_table_ao (id int, col1 int) with (appendonly=true, orientation=row);
create table test_table_ao_with_toast (id int, col1 int, col2 text) with (appendonly=true, orientation=row);
create table test_table_co (id int, col1 int) with (appendonly=true, orientation=column);

create index test_heap_idx on test_table_heap using btree(id);
create index test_heap_wt_idx on test_table_heap_with_toast using btree(id);
create index test_heap_ao_idx on test_table_ao using btree(id);
create index test_heap_ao_wt_idx on test_table_ao_with_toast using btree(id);
create index test_heap_co_idx on test_table_co using btree(id);

-- Advance XID counter, vacuum, and check that relfrozenxid was advanced for
-- all the tables, including auxiliary tables, even though there were no
-- dead tuples.
select advance_xid_counter(500);

-- check table ages before vacuum.
select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_heap')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_heap_with_toast')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_ao')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_ao_with_toast')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_co')
group by segid = -1, relname, classify_age(age);

-- Vacuum. This should advance relfrozenxid on all the tables.
vacuum test_table_heap;
vacuum test_table_heap_with_toast;
vacuum test_table_ao;
vacuum test_table_ao_with_toast;
vacuum test_table_co;

-- Check table ages.
select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_heap')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_heap_with_toast')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_ao')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_ao_with_toast')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_co')
group by segid = -1, relname, classify_age(age);

-- Repeat the tests on a table that has been inserted to, but all the rows
-- have been deleted.
INSERT INTO test_table_heap select i, i*2 from generate_series(1, 20)i;
INSERT INTO test_table_heap_with_toast select i, i*2, i*5 from generate_series(1, 20)i;
INSERT INTO test_table_ao select i, i*2 from generate_series(1, 20)i;
INSERT INTO test_table_ao_with_toast select i, i*2, i*5 from generate_series(1, 20)i;
INSERT INTO test_table_co select i, i*2 from generate_series(1, 20)i;

delete from test_table_heap;
delete from test_table_heap_with_toast;
delete from test_table_ao;
delete from test_table_ao_with_toast;
delete from test_table_co;

select count(*) from test_table_heap;
select count(*) from test_table_heap_with_toast;
select count(*) from test_table_ao;
select count(*) from test_table_ao_with_toast;
select count(*) from test_table_co;

select advance_xid_counter(500);

vacuum freeze test_table_heap;
vacuum freeze test_table_heap_with_toast;
vacuum freeze test_table_ao;
vacuum freeze test_table_ao_with_toast;
vacuum freeze test_table_co;

-- Check table ages again. Because we used VACUUM FREEZE, they should be
-- very young now.
select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_heap')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_heap_with_toast')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_ao')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_ao_with_toast')
group by segid = -1, relname, classify_age(age);

select segid = -1 as is_master, relname, classify_age(age) from aux_rel_ages('test_table_co')
group by segid = -1, relname, classify_age(age);
