-- just a permanent playground to explore optimization of the central recursive CTE query for RBAC

select * from hs_statistics_view;

-- ========================================================

-- An example for a restricted view (_rv) as generated by our RBAC system:
drop view if exists hs_hosting_asset_example_rv;
create view hs_hosting_asset_example_rv as
    with accessible_hs_hosting_asset_uuids as (

        with recursive
            recursive_grants as (
                select distinct rbacgrants.descendantuuid,
                                rbacgrants.ascendantuuid,
                                1 as level,
                                true
                    from rbacgrants
                    where (rbacgrants.ascendantuuid = any (currentsubjectsuuids()))
                --and rbacgrants.assumed
                union all
                select distinct g.descendantuuid,
                                g.ascendantuuid,
                                grants.level + 1 as level,
                                assertTrue(grants.level < 22, 'too many grant-levels: ' || grants.level)
                    from rbacgrants g
                             join recursive_grants grants on grants.descendantuuid = g.ascendantuuid
                    where g.assumed
            ),
            grant_count as (
                select count(*) as grant_count from recursive_grants
            ),
            count_check as (
                select assertTrue((select grant_count from grant_count) < 600000,
                                  'too many grants for current subjects: ' || (select grant_count from grant_count)) as valid
            )
        select distinct perm.objectuuid
            from recursive_grants
                     join rbacpermission perm on recursive_grants.descendantuuid = perm.uuid
                     join rbacobject obj on obj.uuid = perm.objectuuid
                     join count_check cc on cc.valid
            where obj.objecttable::text = 'hs_hosting_asset'::text
              and obj.type = 'EMAIL_ADDRESS'::hshostingassettype -- with/without this type condition
    )
    select target.*
        from hs_hosting_asset target
        where (target.uuid in (select accessible_hs_hosting_asset_uuids.objectuuid
                                   from accessible_hs_hosting_asset_uuids));
-- end of the example view.

-- -------------------------------------------------------------------------------

rollback transaction;
DO language plpgsql $$
DECLARE
    start_time timestamp;
    end_time timestamp;
    total_time interval;
    letter char(1);
BEGIN
    start_time := clock_timestamp();

    CALL defineContext('performance testing', null, 'superuser-alex@hostsharing.net',
                       'hs_booking_project#D-1000000-hshdefaultproject:ADMIN');
--                        'hs_booking_project#D-1000300-mihdefaultproject:ADMIN');
    SET TRANSACTION READ ONLY;

    FOR i IN 0..25 LOOP
            letter := chr(i+ascii('a'));
            PERFORM count(*) from (

                -- An example for a business query based on the view:
                select type, uuid, identifier, caption
                  from hs_hosting_asset_example_rv
                 where type = 'EMAIL_ADDRESS'
                    and identifier like letter || '%'
                 -- end of the business query example.

                ) AS timed;

    END LOOP;

    end_time := clock_timestamp();
    total_time := end_time - start_time;

    RAISE NOTICE 'average execution time: %', total_time/26;
END;
$$;

-- average seconds per recursive CTE select as role 'hs_hosting_asset:<DEBITOR>defaultproject:ADMIN'
--      joined with business query for all 'EMAIL_ADDRESSES':
--                                              D-1000000-hsh      D-1000300-mih
--  - without type comparision in rbacobject:   ~3.30 - ~3.49      ~0.23
--  - with type comparision  in rbacobject:     ~2.99 - ~3.08       ~0.21


-- =============================================================================

-- extending the rbacobject table:

alter table rbacobject
    -- just for performance testing, we would need a joined enum or a varchar(16) which would make it slow
    add column type hshostingassettype;

-- and fill the type column with hs_hosting_asset types:

rollback transaction;
begin transaction;
call defineContext('setting rbacobject.type from hs_hosting_asset.type', null, 'superuser-alex@hostsharing.net');

    UPDATE rbacobject
    SET type = hs.type
        FROM hs_hosting_asset hs
        WHERE rbacobject.uuid = hs.uuid;

end transaction;

-- check the result:

select
    (select count(*) as "total" from rbacobject),
    (select count(*) as "not null" from rbacobject where type is not null),
    (select count(*) as "null" from rbacobject where type is null);

