-- -- __workflow__simple_p/2 -- create or replace function __workflow__simple_p( character varying, integer ) returns bool as $$ declare simple_p__workflow_key alias for $1; v_session_id alias for $2; -- previous_place_list t_place_table; -- target_place_list t_place_table; -- guard_list t_guard_table; guard_list_1 varchar; guard_list_2 varchar; target_place_list_1 varchar; target_place_list_2 varchar; previous_place_list_i varchar; v_row_count integer default 0; v_count integer; v_count2 integer; v_place_key wf_places.place_key%TYPE; v_end_place wf_places.place_key%TYPE; v_transition_key wf_transitions.transition_key%TYPE; v_rownum integer; v_target record; begin /* Let us do some simple checks first */ /* Places with more than one arc out */ select count(*) into v_count from wf_places p where p.workflow_key = simple_p__workflow_key and 1 < (select count(*) from wf_arcs a where a.workflow_key = p.workflow_key and a.place_key = p.place_key and direction = 'in'); raise notice 'query 1'; if v_count > 0 then return 'f'; end if; /* Transitions with more than one arc in */ select count(*) into v_count from wf_transitions t where t.workflow_key = simple_p__workflow_key and 1 < (select count(*) from wf_arcs a where a.workflow_key = t.workflow_key and a.transition_key = t.transition_key and direction = 'in'); raise notice 'query 2'; if v_count > 0 then return 'f'; end if; /* Transitions with more than two arcs out */ select count(*) into v_count from wf_transitions t where t.workflow_key = simple_p__workflow_key and 2 < (select count(*) from wf_arcs a where a.workflow_key = t.workflow_key and a.transition_key = t.transition_key and direction = 'out'); raise notice 'query 3'; if v_count > 0 then return 'f'; end if; /* Now we do the more complicated checks. * We keep a list of visited places because I could not think * of a nicer way that was not susceptable to infinite loops. */ v_place_key := 'start'; v_end_place := 'end'; loop exit when v_place_key = v_end_place; -- previous_place_list(v_row_count) := v_place_key; insert into previous_place_list (session_id,rcnt,ky) values (v_session_id,v_row_count,v_place_key); raise notice 'query 4'; select distinct transition_key into v_transition_key from wf_arcs where workflow_key = simple_p__workflow_key and place_key = v_place_key and direction = 'in'; raise notice 'query 5'; select count(*) into v_count from wf_arcs where workflow_key = simple_p__workflow_key and transition_key = v_transition_key and direction = 'out'; raise notice 'query 6'; if v_count = 1 then select distinct place_key into v_place_key from wf_arcs where workflow_key = simple_p__workflow_key and transition_key = v_transition_key and direction = 'out'; raise notice 'query 7'; else if v_count = 0 then /* deadend! */ return 'f'; else /* better be two based on our earlier test */ v_rownum := 1; for v_target in select place_key,guard_callback from wf_arcs where workflow_key = simple_p__workflow_key and transition_key = v_transition_key and direction = 'out' LOOP -- target_place_list(v_target.rownum) := v_target.place_key; raise notice 'query 8'; insert into target_place_list (session_id,rcnt,ky) values (v_session_id,v_rownum,v_target.place_key); raise notice 'query 9'; -- guard_list(v_target.rownum) := v_target.guard_callback; insert into guard_list (session_id,rcnt,ky) values (v_session_id,v_rownum,v_target.guard_callback); v_rownum := v_rownum + 1; raise notice 'query 10'; end loop; /* Check that the guard functions are the negation of each other * by looking for the magic entry "#" (exactly once) */ select ky into guard_list_1 from guard_list where session_id = v_session_id and rcnt = 1; raise notice 'query 11'; select ky into guard_list_2 from guard_list where session_id = v_session_id and rcnt = 2; raise notice 'query 12'; if ((guard_list_1 != '#' and guard_list_2 != '#') or (guard_list_1 = '#' and guard_list_2 = '#')) then return 'f'; end if; /* Check that exactly one of the targets is in the previous list */ v_count2 := 0; select ky into target_place_list_1 from target_place_list where session_id = v_session_id and rcnt = 1; raise notice 'query 13'; select ky into target_place_list_2 from target_place_list where session_id = v_session_id and rcnt = 2; raise notice 'query 14'; for i in 0..v_row_count LOOP select ky into previous_place_list_i from previous_place_list where session_id = v_session_id and rcnt = i; if target_place_list_1 = previous_place_list_i then v_count2 := v_count2 + 1; v_place_key := target_place_list_2; end if; if target_place_list_2 = previous_place_list_i then v_count2 := v_count2 + 1; v_place_key := target_place_list_1; end if; end loop; raise notice 'query 15'; if v_count2 != 1 then return 'f'; end if; end if; end if; v_row_count := v_row_count + 1; end loop; /* if we got here, it must be okay */ return 't'; end;$$ language plpgsql;