SET client_min_messages = warning;
\set ECHO none
/*
NOTES ON ROLES:
if a superuser executes:
grant execute on f1() to admin;
grant admin to client;
then f1() can be executed by admin and client
revoke admin from client;
then f1() can only be executed by admin.

if a superuser toto executes:
grant execute on f2() to toto;
then f2() can be executed by public!!

select * from information_schema.enabled_roles;
	list of roles enabled

select * from information_schema.role_routine_grants;
	list of grantees for execution of routines
*/

--------------------------------------------------------------------------------
/*
create table tsave_tmp(
	n	int,
	id 	int,
	ord	yorder,
	nr	int,
	pat	yflow
);
--------------------------------------------------------------------------------
-- common to insertorder() and getquote() 
CREATE FUNCTION fcreate_tmp_mod(_id int,_ord yorder,_np int,_nr int) RETURNS int AS $$
DECLARE 
	_MAXORDERFETCH	 int := fgetconst('MAXORDERFETCH'); 
	_MAXCYCLE 	int := fgetconst('MAXCYCLE');
	_cnt int;
	_idx  int;
BEGIN
	-- DROP TABLE IF EXISTS _tmp;
	-- RAISE INFO 'pivot: id=% ord=%, np=%, nr=%',_id,_ord,_np,_nr;
	CREATE TEMPORARY TABLE _tmp ON COMMIT DROP AS (
		WITH RECURSIVE search_backward(id,ord,pat,np,nr) AS (
			SELECT 	_id,_ord,yflow_get(_ord),_np,_nr
			UNION ALL
			SELECT 	X.id,X.ord,
				yflow_get(X.ord,Y.pat), -- add the order at the begin of the yflow
				X.np,X.nr
				FROM vorderinsert X, search_backward Y
				WHERE  X.np = yorder_nr(Y.ord) -- use of indexe 
					AND yflow_follow(_MAXCYCLE,X.ord,Y.pat) 
					-- X->Y === X.qtt>0 and X.np=Y[0].nr
					-- Y.pat does not contain X.ord 
					-- len(X.ord+Y.path) <= _MAXCYCLE	
					-- Y[!=-1]|->X === Y[i].np != X.nr with i!= -1
		)
		SELECT id,ord,nr,pat 
		FROM search_backward  --draft
	);

	SELECT COUNT(*) INTO _cnt FROM _tmp;
		
	SELECT max(n) INTO _idx FROM tsave_tmp;
	IF(_idx IS NULL) THEN _idx := 0; END IF;
	WITH a AS (SELECT * FROM _tmp) 
	INSERT INTO tsave_tmp SELECT _idx+1 as n,a.id,a.ord,a.nr,a.pat FROM a;
	
	DELETE FROM _tmp WHERE yflow_status(pat)!=3;
	
	RETURN _cnt;
END;
$$ LANGUAGE PLPGSQL;
*/



--------------------------------------------------------------------------------
/* gives the flow representation of a group of movements */
CREATE FUNCTION fgetflow(_grp int8) RETURNS text AS $$
DECLARE
	_o	torder%rowtype;
	_res	text;
	_begin	bool;
BEGIN
	_res := '[';
	_begin := true;
	FOR _o IN SELECT o.* FROM torder o,tmvt m WHERE m.grp=_grp AND m.oruuid=o.uuid ORDER BY m.id ASC LOOP
		IF(NOT _begin) THEN
			_res := _res || ',';
		END IF;
		_begin := false;
		_res :=   _res || '(' || _o.id || ',' || _o.own  || ',' || _o.nr || ',' || _o.qtt_requ || ',' || _o.np || ',' || _o.qtt_requ  || ',' || _o.np || ')';
	END LOOP; 
	_res := _res || ']';
	RAISE NOTICE 'flow_to_matrix(flow)=%',yflow_to_matrix(_res::yflow);
	RETURN _res;
END;
$$ LANGUAGE PLPGSQL;
--------------------------------------------------------------------------------
/* usage:
_t timestamp := current_timestamp;
action to measure
perform frec('action_name',_t);
then execute getdelays.py
 */
CREATE FUNCTION frectime(_name text,_start timestamp) RETURNS VOID AS $$
DECLARE
	_x	int8;
	_dn	text;
BEGIN
	_dn := 'perf_delay_' || _name;
	_x := extract(microsecond from (current_timestamp - _start)); 
	UPDATE tconst SET value = value + _x WHERE name = _dn;
	IF(NOT FOUND) THEN
		INSERT INTO tconst (name,value) VALUES (_dn,_x);
	END IF;
	_dn := 'perf_count_' || _name;
	UPDATE tconst SET value = value + 1 WHERE name = _dn;
	IF(NOT FOUND) THEN
		INSERT INTO tconst (name,value) VALUES (_dn,1);
	END IF;
	RETURN;
END;
$$ LANGUAGE PLPGSQL;

--------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION fomega(pat yflow) RETURNS float8 AS $$
DECLARE
	_f float8[];
BEGIN
	_f := yflow_qtts(pat)::float8[];
	-- qtt_prov/qtt_requ
	RETURN (_f[2])/(_f[1]);
END;
$$ LANGUAGE PLPGSQL;

--------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION fnpnr(pat yflow) RETURNS int8[] AS $$
DECLARE
	_vi int8[];
	_dim int;
BEGIN
	_vi := yflow_to_matrix(pat);
	_dim := yflow_dim(pat);
	-- qlt_prov,qlt_requ
	RETURN array[_vi[_dim][5],_vi[1][3]];
END;
$$ LANGUAGE PLPGSQL;

--------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION fpopulate(nbq int,nbo int) RETURNS int AS $$
DECLARE
	_f float8[];
	_i int;
	_range float :=1000;
BEGIN
	with t as (select i from generate_series(1,nbq) g(i))
	insert into tquality select t.i,'q' || t.i::text,1,session_user,0 from t;
	select setval('tquality_id_seq',nbq+1,false) INTO _i;

	with t as (select i from generate_series(1,nbo) g(i))
	insert into towner select t.i,t.i::text from t;
	select setval('towner_id_seq',nbo+1,false) INTO _i;

	with t as(select i from generate_series(1,nbo) g(i))
	INSERT INTO torder select --(id,uuid,own,nr,qtt_requ,np,qtt_prov,qtt,created,updated) 
		t.i as id,t.i::text as uuid,t.i as own,round(random()*(nbq-1))::int+1 as nr,(round(random()*_range)::int+1)*100 as qtt_requ,
		round(random()*(nbq-1))::int+1 as np,(round(random()*_range)::int+1)*100 as qtt_prov,1 as qtt,
		statement_timestamp() as created,NULL as updated from t;
	select setval('torder_id_seq',nbo+1,false) INTO _i;

	update torder set np=np-1 where np=nr and np>2; -- all must be different
	update torder set np=2 where np=nr and np=1;
	update torder set qtt=qtt_prov;

	WITH t as (select np, sum(qtt) as qtt from torder group by np)
	update tquality set qtt = t.qtt from t where id=t.np ;
	RETURN 1;
END;
$$ LANGUAGE PLPGSQL;

\set ECHO all
 RESET client_min_messages;

