mirror of
https://github.com/FirebirdSQL/firebird-qa.git
synced 2025-01-22 21:43:06 +01:00
202 lines
8.5 KiB
Python
202 lines
8.5 KiB
Python
#coding:utf-8
|
|
|
|
"""
|
|
ID: issue-8176
|
|
ISSUE: https://github.com/FirebirdSQL/firebird/issues/8176
|
|
TITLE: Firebird hangs after starting remote profiling session
|
|
DESCRIPTION:
|
|
We create two users: tmp_worker_usr and tmp_profiler_usr.
|
|
First of them will perform some 'useful work', second will PROFILE attachment of tmp_worker_usr.
|
|
Also, we create role 'tmp_profiler_role' and grant it to 'tmp_profiler_usr'.
|
|
Ability to profile ather attachment (by tmp_profiler_usr) is achieved via granting to role
|
|
tmp_profiler_role system privilege PROFILE_ANY_ATTACHMENT.
|
|
Then we create three connections to test DB belonging to tmp_worker_usr, tmp_profiler_usr and SYSDBA.
|
|
We pass attachment_id of tmp_worker_usr to the call 'select rdb$profiler.start_session(...)' performed
|
|
by tmp_profiler_usr. Executing of this causes creation of PLG$PROFILE* tables and views in the test DB
|
|
(they are created by special internal connection - this can be seen in the trace).
|
|
Unfortunately, usedr who calls rdb$profiler.start_session() will *NOT* have any access rights to created
|
|
PLG* objects. This must be donw explicitly to SYSDBA (and this is the reason why we create 3rd connection).
|
|
Finally, we do somewhat similar to example described doc/sql.extensions/README.profiler.md: run two dummy
|
|
procedures by tmp_worker_usr, and after that - call proc rdb$profiler.finish_session by tmp_profiler_usr.
|
|
At the last step, we query data from plg$prof_sessions (it must have number of records equal to the number
|
|
of profiling sessions that we have created).
|
|
NOTES:
|
|
[10.07.2024] pzotov
|
|
::: WARNING :::
|
|
1. On CLASSIC problem still exists: firebird hangs, although new connections to test DB are allowed (found both on 5.x and 6.x).
|
|
One may even to run 'delete from mon$attachments' (using new ISQL session) but there is no effect: server does not perform that.
|
|
Because of this, test currently can be run only on Super.
|
|
2. It looks weird that user (NON-sysdba) who has necessary rights to start profiling, must be explicitly granted to access PLG* tables/views.
|
|
|
|
Confirmed bug on 6.0.0.389-cc71c6f (SS), 5.0.1.1432-9d5a60a (SS) - server hanged and did not allow to make new connections to test DB.
|
|
Checked on 6.0.0.392-3fa8e6b, 5.0.1.1434-2593b3b.
|
|
|
|
[24.07.2024] pzotov
|
|
Checked fixed problem with hang on Windows, Servermode = CLASSIC
|
|
Commits:
|
|
https://github.com/FirebirdSQL/firebird/commit/fa90256cf080965f92eae11eba8d897c2d02e1b9
|
|
Merge pull request #8186 from FirebirdSQL/work/ProfilerIPC
|
|
Fixed a few issues with IPC used by remote profiler
|
|
https://github.com/FirebirdSQL/firebird/commit/f59905fc29f0b9288d61fc6113fd24301dce1327
|
|
Frontported PR #8186 : Fixed a few issues with IPC used by remote profiler
|
|
Snapshots: 6.0.0.398-f59905f, 5.0.1.1440-7b1b824
|
|
"""
|
|
|
|
import pytest
|
|
from firebird.qa import *
|
|
from firebird.driver import tpb, Isolation # , TraLockResolution, TraAccessMode, DatabaseError
|
|
import time
|
|
|
|
N_COUNT = 1000
|
|
init_script = f"""
|
|
create or alter procedure sp_ins as begin end;
|
|
create or alter procedure sp_del as begin end;
|
|
|
|
recreate table test (
|
|
id integer primary key,
|
|
val integer not null
|
|
);
|
|
|
|
set term ^;
|
|
|
|
create or alter function fn_mult(p1 integer, p2 integer) returns integer
|
|
as
|
|
begin
|
|
return p1 * p2;
|
|
end^
|
|
|
|
create or alter procedure sp_ins sql security definer
|
|
as
|
|
declare i integer = 1;
|
|
begin
|
|
while (i <= {N_COUNT})
|
|
do
|
|
begin
|
|
if (mod(i, 2) = 1) then
|
|
insert into test values (:i, fn_mult(:i, 2));
|
|
i = i + 1;
|
|
end
|
|
end
|
|
^
|
|
|
|
create or alter procedure sp_del sql security definer
|
|
as
|
|
declare i integer = 1;
|
|
begin
|
|
while (i <= {N_COUNT} / 2)
|
|
do
|
|
begin
|
|
if (mod(i, 2) = 1) then
|
|
delete from test where id = fn_mult(:i, 2);
|
|
i = i + 1;
|
|
end
|
|
end
|
|
^
|
|
set term ;^
|
|
commit;
|
|
|
|
grant execute on procedure sp_ins to public;
|
|
grant execute on procedure sp_del to public;
|
|
commit;
|
|
"""
|
|
|
|
tmp_worker_usr = user_factory('db', name='tmp_worker_8176', password='123')
|
|
tmp_profiler_usr = user_factory('db', name='tmp_profiler_8176', password='456')
|
|
tmp_profiler_role = role_factory('db', name='tmp_profiler_role')
|
|
|
|
db = db_factory(init=init_script)
|
|
act = python_act('db')
|
|
|
|
@pytest.mark.disabled_in_forks
|
|
@pytest.mark.version('>=5.0.1')
|
|
def test_1(act: Action, tmp_worker_usr: User, tmp_profiler_usr: User, tmp_profiler_role: Role, capsys):
|
|
|
|
addi_script = f"""
|
|
set wng off;
|
|
set bail on;
|
|
alter user {tmp_profiler_usr.name} revoke admin role;
|
|
revoke all on all from {tmp_profiler_usr.name};
|
|
commit;
|
|
-- doc/sql.extensions/README.profiler.md:
|
|
-- If the remote attachment is from a different user, the calling user must have the system privilege `PROFILE_ANY_ATTACHMENT`.
|
|
alter role {tmp_profiler_role.name}
|
|
set system privileges to PROFILE_ANY_ATTACHMENT;
|
|
commit;
|
|
grant default {tmp_profiler_role.name} to user {tmp_profiler_usr.name};
|
|
commit;
|
|
"""
|
|
act.isql(switches=['-q'], input=addi_script)
|
|
|
|
custom_tpb = tpb(isolation = Isolation.READ_COMMITTED_READ_CONSISTENCY, lock_timeout = 0)
|
|
|
|
with act.db.connect() as con_admin, \
|
|
act.db.connect(user = tmp_worker_usr.name, password = tmp_worker_usr.password) as con_worker, \
|
|
act.db.connect(user = tmp_profiler_usr.name, password = tmp_profiler_usr.password, role = tmp_profiler_role.name) as con_profiler:
|
|
|
|
cur_worker = con_worker.cursor()
|
|
cur_worker.execute('select current_connection from rdb$database')
|
|
worker_attach_id = cur_worker.fetchone()[0]
|
|
|
|
tx_profiler = con_profiler.transaction_manager(custom_tpb)
|
|
cur_profiler = tx_profiler.cursor()
|
|
|
|
#..............................................................................
|
|
|
|
tx_profiler.begin()
|
|
cur_profiler.execute(f"select rdb$profiler.start_session('remote_profiling_of_inserts', null, {worker_attach_id}) from rdb$database;")
|
|
cur_profiler.fetchall()
|
|
|
|
cur_worker.callproc('sp_ins')
|
|
|
|
cur_profiler.callproc(f'rdb$profiler.finish_session(true, {worker_attach_id})')
|
|
tx_profiler.commit()
|
|
|
|
#..............................................................................
|
|
|
|
tx_profiler.begin()
|
|
cur_profiler.execute(f"select rdb$profiler.start_session('remote_profiling_of_deletions', null, {worker_attach_id}) from rdb$database;")
|
|
cur_profiler.fetchall()
|
|
|
|
cur_worker.callproc('sp_del')
|
|
|
|
cur_profiler.callproc(f'rdb$profiler.finish_session(true, {worker_attach_id})')
|
|
tx_profiler.commit()
|
|
|
|
#------------------------------------------------------------------------------
|
|
# firebird.driver.types.DatabaseError: no permission for SELECT access to TABLE PLG$PROF_SESSIONS
|
|
# -Effective user is TMP_USER_PROFILER_ANY_ATT
|
|
#################################
|
|
# ::: NB ::: Why this is needed ?
|
|
#################################
|
|
con_admin.execute_immediate(f'grant select on plg$prof_sessions to role {tmp_profiler_role.name}')
|
|
con_admin.execute_immediate(f'grant select on plg$prof_psql_stats_view to role {tmp_profiler_role.name}')
|
|
con_admin.commit()
|
|
#------------------------------------------------------------------------------
|
|
|
|
tx_profiler.begin()
|
|
cur_profiler.execute('select description as profiler_session_descr, attachment_id as profiled_attachment, trim(user_name) as who_was_profiled from plg$prof_sessions order by profile_id')
|
|
cur_cols = cur_profiler.description
|
|
for r in cur_profiler:
|
|
for i in range(0,len(cur_cols)):
|
|
print( cur_cols[i][0], ':', r[i] )
|
|
|
|
#cur_profiler.execute('select * from plg$prof_psql_stats_view')
|
|
#cur_cols = cur_profiler.description
|
|
#for r in cur_profiler:
|
|
# for i in range(0,len(cur_cols)):
|
|
# print( cur_cols[i][0], ':', r[i] )
|
|
|
|
tx_profiler.commit()
|
|
|
|
act.expected_stdout = f"""
|
|
PROFILER_SESSION_DESCR : remote_profiling_of_inserts
|
|
PROFILED_ATTACHMENT : {worker_attach_id}
|
|
WHO_WAS_PROFILED : {tmp_worker_usr.name.upper()}
|
|
|
|
PROFILER_SESSION_DESCR : remote_profiling_of_deletions
|
|
PROFILED_ATTACHMENT : {worker_attach_id}
|
|
WHO_WAS_PROFILED : {tmp_worker_usr.name.upper()}
|
|
"""
|
|
act.stdout = capsys.readouterr().out
|
|
assert act.clean_stdout == act.clean_expected_stdout
|