-- wait for server establishment
select pg_sleep(3);

set search_path = pl_debugger;

-- only one record is expected
select count(*) from debug_info;

-- attach debug server
select dbe_pldebugger.attach(nodename, port) from debug_info;

select * from dbe_pldebugger.info_locals();

create table tmp_holder (res text);

do $$
declare
    funcoid oid;
begin
    select oid from pg_proc into funcoid where proname = 'test_debug';
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 0); -- negative
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 5); -- headerline
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 15); -- ok
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 17); -- invalid
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 22); -- ok
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 15); -- duplicate
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 29); -- ok
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 32); -- ok
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 35); -- ok
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 39); -- ok
    insert into tmp_holder select * from dbe_pldebugger.disable_breakpoint(4); -- ok
    insert into tmp_holder select * from dbe_pldebugger.disable_breakpoint(5); -- ok
    insert into tmp_holder select * from dbe_pldebugger.enable_breakpoint( 5); -- ok
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 50); -- exceeds
    insert into tmp_holder select * from dbe_pldebugger.delete_breakpoint(1);  -- ok
    insert into tmp_holder select * from dbe_pldebugger.delete_breakpoint(0);  -- ok
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 15); -- add new bp at previously deleted one, bp id should proceed
    insert into tmp_holder select breakpointno || ':' || lineno || ':' || query || ':' || enable from dbe_pldebugger.info_breakpoints();
end;
$$;

select * from tmp_holder;

select * from dbe_pldebugger.print_var('test.c');

select * from dbe_pldebugger.print_var('<UNKNOWN>');

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select * from dbe_pldebugger.info_locals();

select * from dbe_pldebugger.print_var('cur');

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select * from dbe_pldebugger.info_locals();

select * from dbe_pldebugger.print_var('rec');

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select * from dbe_pldebugger.info_locals();

select * from dbe_pldebugger.print_var('row');

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select * from dbe_pldebugger.info_locals();

select * from dbe_pldebugger.print_var('b_tmp');

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.continue();

-- wait again
select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

select * from dbe_pldebugger.abort();

-- wait for test_debug2
select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

-- wait for test_debug3
select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

select funcname, lineno, query from dbe_pldebugger.next();

select * from dbe_pldebugger.info_locals();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.continue();

select funcname, lineno, query from dbe_pldebugger.next();

-- wait for test_debug4
select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

select funcname, lineno, query from dbe_pldebugger.step();

select * from dbe_pldebugger.info_locals();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.continue();

select funcname, lineno, query from dbe_pldebugger.continue();

-- test with client error in exception
select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

SELECT funcname, lineno, query FROM DBE_PLDEBUGGER.step(); 

SELECT funcname, lineno, query FROM DBE_PLDEBUGGER.step(); 

SELECT funcname, lineno, query FROM DBE_PLDEBUGGER.step(); 

SELECT funcname, lineno, query FROM DBE_PLDEBUGGER.step(); 

SELECT funcname, lineno, query FROM DBE_PLDEBUGGER.step(); 

SELECT * FROM DBE_PLDEBUGGER.abort();

-- test with breakpoint

select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

truncate tmp_holder;

do $$
declare
    funcoid oid;
    funcoid2 oid;
begin
    select oid from pg_proc into funcoid where proname = 'test_debug';
    select oid from pg_proc into funcoid2 where proname = 'test_debug4';
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 31);
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 44);
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid2, 12);
    insert into tmp_holder select breakpointno || ':' || lineno || ':' || query from dbe_pldebugger.info_breakpoints();
end;
$$;

select * from tmp_holder;

select funcname, lineno, query from dbe_pldebugger.continue();

select * from dbe_pldebugger.info_locals();

select funcname, lineno, query from dbe_pldebugger.continue();

select frameno, funcname, lineno, query from dbe_pldebugger.backtrace();

select * from dbe_pldebugger.info_locals();

select funcname, lineno, query from dbe_pldebugger.continue();

select frameno, funcname, lineno, query from dbe_pldebugger.backtrace();

select * from dbe_pldebugger.info_locals();

select funcname, lineno, query from dbe_pldebugger.continue();

select funcname, lineno, query from dbe_pldebugger.continue();

-- test with finish without encountered breakpoint

select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.finish();

select funcname, lineno, query from dbe_pldebugger.finish();

-- test with finish with encountered breakpoint and inner error

select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

truncate tmp_holder;

do $$
declare
    funcoid oid;
begin
    select oid from pg_proc into funcoid where proname = 'test_debug';
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 31);
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 44);
    insert into tmp_holder select breakpointno || ':' || lineno || ':' || query from dbe_pldebugger.info_breakpoints();
end;
$$;

select funcname, lineno, query from dbe_pldebugger.finish();

select funcname, lineno, query from dbe_pldebugger.finish();

select funcname, lineno, query from dbe_pldebugger.finish();

select funcname, lineno, query from dbe_pldebugger.finish();

-- test recursive debug

select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

truncate tmp_holder;

do $$
declare
    funcoid oid;
begin
    select oid from pg_proc into funcoid where proname = 'test_debug_recursive';
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 5);
    insert into tmp_holder select breakpointno || ':' || lineno || ':' || query from dbe_pldebugger.info_breakpoints();
end;
$$;

select funcname, lineno, query from dbe_pldebugger.step();

select frameno, funcname, lineno, query from dbe_pldebugger.backtrace();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.step();

select frameno, funcname, lineno, query from dbe_pldebugger.backtrace();

select funcname, lineno, query from dbe_pldebugger.step();

select funcname, lineno, query from dbe_pldebugger.step();

select frameno, funcname, lineno, query from dbe_pldebugger.backtrace();

select funcname, lineno, query from dbe_pldebugger.continue();

select frameno, funcname, lineno, query from dbe_pldebugger.backtrace();

select funcname, lineno, query from dbe_pldebugger.continue();

select frameno, funcname, lineno, query from dbe_pldebugger.backtrace();

select funcname, lineno, query from dbe_pldebugger.continue();

select frameno, funcname, lineno, query from dbe_pldebugger.backtrace();

select * from dbe_pldebugger.info_locals();

select * from dbe_pldebugger.info_locals(0);

select * from dbe_pldebugger.info_locals(1);

select * from dbe_pldebugger.info_locals(2);

select * from dbe_pldebugger.info_locals(3);

select * from dbe_pldebugger.info_locals(4); -- exceeds

select * from dbe_pldebugger.info_locals(-1); -- exceeds

select * from dbe_pldebugger.print_var('ct');

select * from dbe_pldebugger.print_var('ct', 0);

select * from dbe_pldebugger.print_var('ct', 1);

select * from dbe_pldebugger.print_var('ct', 2);

select * from dbe_pldebugger.print_var('ct', 3);

select * from dbe_pldebugger.print_var('ct', 4);

select * from dbe_pldebugger.print_var('ct', -1); -- exceeds

do $$
declare
    funcoid oid;
begin
    select oid from pg_proc into funcoid where proname = 'test_debug_recursive';
    insert into tmp_holder select * from dbe_pldebugger.delete_breakpoint(0);
    insert into tmp_holder select breakpointno || ':' || lineno || ':' || query from dbe_pldebugger.info_breakpoints();
end;
$$;

select funcname, lineno, query from dbe_pldebugger.continue();

select frameno, funcname, lineno, query from dbe_pldebugger.backtrace();

select funcname, lineno, query from dbe_pldebugger.continue();

-- test_empty
select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;


-- test set_var
select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

select * from dbe_pldebugger.info_locals();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

-- immutable to sql injection
select * from dbe_pldebugger.set_var('x', '1; create table injection(a int)');
select * from dbe_pldebugger.set_var('x', 'create table injection(a int)');

select * from dbe_pldebugger.set_var('x', '1');

select * from dbe_pldebugger.set_var('vint', '1+1'); -- can be expresion

select * from dbe_pldebugger.set_var('vnum', '1'); -- support type cast

select * from dbe_pldebugger.set_var('vfloat', '1');

select * from dbe_pldebugger.set_var('vvarchar', 'there is no spoon'); -- fails if not quoted

select * from dbe_pldebugger.set_var('vvarchar', '$$there is no spoon$$'); -- this works

select * from dbe_pldebugger.set_var('vtext', '$$Why oh why didnt I take the blue pill?$$');

select * from dbe_pldebugger.set_var('vrow', '1'); -- can not directly assign row type

select * from dbe_pldebugger.set_var('vrow', 'select * from test order by 1 limit 1'); -- syntax error

select * from dbe_pldebugger.set_var('vrow', '$$select * from test order by 1 limit 1$$'); -- still won't work

-- row should be changed by assignment member by member
select * from dbe_pldebugger.set_var('test.a', '1');
select * from dbe_pldebugger.set_var('test.b', '$$now$$');
select * from dbe_pldebugger.set_var('test.c', '$$2021-07-31$$::timestamp + now() - now()'); -- function call is not ok
select * from dbe_pldebugger.set_var('test.c', '$$2021-07-31$$::timestamp'); -- function call is ok

select * from dbe_pldebugger.set_var('vrec', '(1,1,1)::test%rowtype'); -- not ok
select * from dbe_pldebugger.set_var('vrec', 'ROW(1,1,1)');

select * from dbe_pldebugger.set_var('vrefcursor', '1'); -- set cursor variable directly is not allowed

select * from dbe_pldebugger.set_var('vconst', '1'); -- set constant variable is not allowed

select * from dbe_pldebugger.set_var('vint', '1;SELECT OID FROM PG_PROC limit 1;'); -- embedding of another sql is not allowed

select * from dbe_pldebugger.set_var('vint', '1;S'); -- incomplete second stmt will give warning


select * from dbe_pldebugger.info_locals();

select funcname, lineno, query from dbe_pldebugger.next();

select funcname, lineno, query from dbe_pldebugger.next();

select * from dbe_pldebugger.info_locals();

select funcname, lineno, query from dbe_pldebugger.next();

select * from dbe_pldebugger.info_locals();

select funcname, lineno, query from dbe_pldebugger.next();

-- test package
select pg_sleep(1);

select dbe_pldebugger.attach(nodename, port) from debug_info;

select * from dbe_pldebugger.info_locals();

select * from dbe_pldebugger.next();

select * from dbe_pldebugger.next();

truncate tmp_holder;

do $$
declare
    funcoid oid;
begin
    select oid from pg_proc into funcoid where proname = 'pro1';
    insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(funcoid, 12);
    insert into tmp_holder select breakpointno || ':' || lineno || ':' || query from dbe_pldebugger.info_breakpoints();
end;
$$;

select funcname, lineno, query from dbe_pldebugger.continue();

SELECT * FROM DBE_PLDEBUGGER.info_locals();

SELECT * FROM DBE_PLDEBUGGER.backtrace();

SELECT * FROM DBE_PLDEBUGGER.continue();

--test anonymous
select pg_sleep(1);
delete from tmp_holder;

select dbe_pldebugger.attach(nodename, port) from debug_info;

select dbe_pldebugger.info_code(0);

insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(0, 0); -- negative
insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(0, 6); -- headerline
insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(0, 6); -- already
insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(0, 8); -- ok
insert into tmp_holder select * from dbe_pldebugger.add_breakpoint(0, 13); -- negative
insert into tmp_holder select * from dbe_pldebugger.disable_breakpoint(1); -- ok
insert into tmp_holder select * from dbe_pldebugger.enable_breakpoint(1); -- ok
insert into tmp_holder select * from dbe_pldebugger.delete_breakpoint(0);  -- ok
select funcname, lineno, query from dbe_pldebugger.next();
select funcname, lineno, query from dbe_pldebugger.continue();
insert into tmp_holder select * from dbe_pldebugger.add_breakpoint((select oid from pg_proc where proname='test_increment'), 6); -- ok
select funcname, lineno, query from dbe_pldebugger.continue();
select funcname, lineno, query from dbe_pldebugger.step();
select frameno, funcname, lineno, query from dbe_pldebugger.backtrace();
select * from dbe_pldebugger.info_locals();
select funcname, lineno, query from dbe_pldebugger.finish();
select * from dbe_pldebugger.print_var('k');
select * from dbe_pldebugger.abort();

select * from tmp_holder;