8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 20:03:02 +01:00

Remove RDB$PROFILER.PURGE_SNAPSHOTS in favor of direct DELETE in RDB$PROFILE_SESSIONS.

Disallow direct modifications in others profile tables.

Add system privilege DELETE_ANY_PROFILE_SESSION and disallow deletion of others users' data without it.

Rename procedure and parameters UPDATE_SNAPSHOT to REFRESH_SNAPSHOTS.
This commit is contained in:
Adriano dos Santos Fernandes 2020-12-12 23:39:37 -03:00
parent 4fb58153f5
commit d2dc528b9c
8 changed files with 145 additions and 124 deletions

View File

@ -26,3 +26,4 @@ Only ones mentioned in this document could be used, but as necessities appears,
- [decltype](https://en.cppreference.com/w/cpp/language/decltype) - [decltype](https://en.cppreference.com/w/cpp/language/decltype)
- [std::is_convertible](https://en.cppreference.com/w/cpp/types/is_convertible) - [std::is_convertible](https://en.cppreference.com/w/cpp/types/is_convertible)
- [final specifier](https://en.cppreference.com/w/cpp/language/final) - [final specifier](https://en.cppreference.com/w/cpp/language/final)
- [raw string literal](https://en.cppreference.com/w/cpp/language/string_literal)

View File

@ -557,6 +557,7 @@ GRANT_REVOKE_ANY_DDL_RIGHT GRANT and REVOKE any DDL rights
CREATE_PRIVILEGED_ROLES Use SET SYSTEM PRIVILEGES in roles CREATE_PRIVILEGED_ROLES Use SET SYSTEM PRIVILEGES in roles
MODIFY_EXT_CONN_POOL Manage properties of pool of external connections MODIFY_EXT_CONN_POOL Manage properties of pool of external connections
REPLICATE_INTO_DATABASE Use replication API to load changesets into database REPLICATE_INTO_DATABASE Use replication API to load changesets into database
DELETE_ANY_PROFILE_SESSION May delete profile sessions from any user
22) New grantee type in GRANT and REVOKE operators - SYSTEM PRIVILEGE. 22) New grantee type in GRANT and REVOKE operators - SYSTEM PRIVILEGE.

View File

@ -10,7 +10,7 @@ A session may be paused to temporary disable statistics gathering in a session.
A new session may be started when a session is already active. In this case it has the same semantics of finishing the current session with `RDB$PROFILER.FINISH_SESSION(FALSE)` so snapshots are not updated in the same moment. A new session may be started when a session is already active. In this case it has the same semantics of finishing the current session with `RDB$PROFILER.FINISH_SESSION(FALSE)` so snapshots are not updated in the same moment.
To analyze the gathered data, the user must update the snapshots which may be done finishing or pausing a session (with `UPDATE_SNAPSHOT` parameter set to `TRUE`) or calling `RDB$PROFILER.UPDATE_SNAPSHOT`. To analyze the gathered data, the user must update the snapshots which may be done finishing or pausing a session (with `REFRESH_SNAPSHOTS` parameter set to `TRUE`) or calling `RDB$PROFILER.REFRESH_SNAPSHOTS`.
Following is a sample profile session. Following is a sample profile session.
@ -152,12 +152,12 @@ Return type: `BIGINT NOT NULL`.
`RDB$PROFILER.PAUSE_SESSION` pauses the current profiler session so the following PSQL executed statements are not accounted. `RDB$PROFILER.PAUSE_SESSION` pauses the current profiler session so the following PSQL executed statements are not accounted.
If `UPDATE_SNAPSHOT` is `TRUE` the snapshot tables are updated with data up to the current moment. Otherwise data remains only in the engine memory for later update. If `REFRESH_SNAPSHOTS` is `TRUE` the snapshot tables are updated with data up to the current moment. Otherwise data remains only in the engine memory for later update.
Calling `RDB$PROFILER.PAUSE_SESSION(TRUE)` has the same semantics of calling `RDB$PROFILER.PAUSE_SESSION(FALSE)` followed by `RDB$PROFILER.UPDATE_SNAPSHOT`. Calling `RDB$PROFILER.PAUSE_SESSION(TRUE)` has the same semantics of calling `RDB$PROFILER.PAUSE_SESSION(FALSE)` followed by `RDB$PROFILER.REFRESH_SNAPSHOTS`.
Input parameters: Input parameters:
- `UPDATE_SNAPSHOT` type `BOOLEAN NOT NULL` - `REFRESH_SNAPSHOTS` type `BOOLEAN NOT NULL`
## Procedure `RESUME_SESSION` ## Procedure `RESUME_SESSION`
@ -167,27 +167,29 @@ Input parameters:
`RDB$PROFILER.FINISH_SESSION` finishes the current profiler session. `RDB$PROFILER.FINISH_SESSION` finishes the current profiler session.
If `UPDATE_SNAPSHOT` is `TRUE` the snapshot tables are updated with data of the finished session (and old finished sessions not yet present in the snapshot). Otherwise data remains only in the engine memory for later update. If `REFRESH_SNAPSHOTS` is `TRUE` the snapshot tables are updated with data of the finished session (and old finished sessions not yet present in the snapshot). Otherwise data remains only in the engine memory for later update.
Calling `RDB$PROFILER.FINISH_SESSION(TRUE)` has the same semantics of calling `RDB$PROFILER.FINISH_SESSION(FALSE)` followed by `RDB$PROFILER.UPDATE_SNAPSHOT`. Calling `RDB$PROFILER.FINISH_SESSION(TRUE)` has the same semantics of calling `RDB$PROFILER.FINISH_SESSION(FALSE)` followed by `RDB$PROFILER.REFRESH_SNAPSHOTS`.
Input parameters: Input parameters:
- `UPDATE_SNAPSHOT` type `BOOLEAN NOT NULL` - `REFRESH_SNAPSHOTS` type `BOOLEAN NOT NULL`
## Procedure `UPDATE_SNAPSHOT` ## Procedure `REFRESH_SNAPSHOTS`
`RDB$PROFILER.UPDATE_SNAPSHOT` updates the system tables snapshots with data from the profile sessions in memory. `RDB$PROFILER.REFRESH_SNAPSHOTS` updates the system tables snapshots with data from the profile sessions in memory.
After update data is stored in tables `RDB$PROFILE_SESSIONS`, `RDB$PROFILE_REQUESTS`, `RDB$PROFILE_STATS` and `PROFILE_RECORD_SOURCE_STATS` and may be read and analyzed by the user. After update data is stored in tables `RDB$PROFILE_SESSIONS`, `RDB$PROFILE_REQUESTS`, `RDB$PROFILE_STATS` and `PROFILE_RECORD_SOURCE_STATS` and may be read and analyzed by the user.
It also removes finished sessions from engine memory, so if `RDB$PROFILER.PURGE_SNAPSHOTS` is later called these data are not recovered. It also removes finished sessions from engine memory.
## Procedure `PURGE_SNAPSHOTS`
`RDB$PROFILER.PURGE_SNAPSHOTS` removes all profile snapshots from the system tables and remove finished profile sessions from engine memory.
# Snapshot system tables # Snapshot system tables
Profile snapshot tables are read only with one exception - `RDB$PROFILE_SESSIONS` may be used with `DELETE` command.
An user can delete profile sessions from their own, and if it has the `DELETE_ANY_PROFILE_SESSION` system privilege it may also delete sessions from any users.
When a session is deleted the related data in others profiler snapshot tables are internally and automatically deleted too.
Below is the list of system tables that stores profile data. Note that `gbak` does not backup these tables. Below is the list of system tables that stores profile data. Note that `gbak` does not backup these tables.
## Table `RDB$PROFILE_SESSIONS` ## Table `RDB$PROFILE_SESSIONS`

View File

@ -37,7 +37,7 @@ using namespace Firebird;
//-------------------------------------- //--------------------------------------
IExternalResultSet* ProfilerPackage::updateSnapshotProcedure(ThrowStatusExceptionWrapper* status, IExternalResultSet* ProfilerPackage::refreshSnapshotsProcedure(ThrowStatusExceptionWrapper* status,
IExternalContext* context, const void* in, void* out) IExternalContext* context, const void* in, void* out)
{ {
const auto tdbb = JRD_get_thread_data(); const auto tdbb = JRD_get_thread_data();
@ -47,7 +47,7 @@ IExternalResultSet* ProfilerPackage::updateSnapshotProcedure(ThrowStatusExceptio
const auto profiler = attachment->getProfiler(tdbb); const auto profiler = attachment->getProfiler(tdbb);
profiler->updateSnapshot(tdbb); profiler->refreshSnapshots(tdbb);
return nullptr; return nullptr;
} }
@ -72,8 +72,10 @@ IExternalResultSet* ProfilerPackage::finishSessionProcedure(ThrowStatusException
profileSession->finishTimeStamp.value.time_zone = attachment->att_current_timezone; profileSession->finishTimeStamp.value.time_zone = attachment->att_current_timezone;
} }
if (in->updateSnapshot) profiler->currentSessionId = 0;
profiler->updateSnapshot(tdbb);
if (in->refreshSnapshots)
profiler->refreshSnapshots(tdbb);
return nullptr; return nullptr;
} }
@ -93,49 +95,8 @@ IExternalResultSet* ProfilerPackage::pauseSessionProcedure(ThrowStatusExceptionW
profiler->paused = true; profiler->paused = true;
if (in->updateSnapshot) if (in->refreshSnapshots)
profiler->updateSnapshot(tdbb); profiler->refreshSnapshots(tdbb);
return nullptr;
}
IExternalResultSet* ProfilerPackage::purgeSnapshotsProcedure(ThrowStatusExceptionWrapper* status,
IExternalContext* context, const void* in, void* out)
{
const auto tdbb = JRD_get_thread_data();
const auto attachment = tdbb->getAttachment();
Attachment::SyncGuard guard(attachment, FB_FUNCTION);
const auto profiler = attachment->getProfiler(tdbb);
IAttachment* const attachmentIntf = attachment->getInterface();
ITransaction* const transactionIntf = tdbb->getTransaction()->getInterface(false);
ThrowLocalStatus throwStatus;
const char* purgeSql =
"execute block as\n"
"begin\n"
" delete from rdb$profile_stats;\n"
" delete from rdb$profile_record_source_stats;\n"
" delete from rdb$profile_requests;\n"
" delete from rdb$profile_sessions;\n"
"end";
attachmentIntf->execute(&throwStatus, transactionIntf, 0, purgeSql, SQL_DIALECT_CURRENT,
nullptr, nullptr, nullptr, nullptr);
auto sessionAccessor = profiler->sessions.accessor();
for (bool sessionFound = sessionAccessor.getFirst(); sessionFound;)
{
const auto sessionId = sessionAccessor.current()->first;
if (!profiler->activeSession || sessionId != profiler->currentSessionId)
sessionFound = sessionAccessor.fastRemove();
else
sessionFound = sessionAccessor.getNext();
}
return nullptr; return nullptr;
} }
@ -211,6 +172,37 @@ Profiler* Profiler::create(thread_db* tdbb)
return FB_NEW_POOL(*tdbb->getAttachment()->att_pool) Profiler(tdbb); return FB_NEW_POOL(*tdbb->getAttachment()->att_pool) Profiler(tdbb);
} }
void Profiler::deleteSessionDetails(thread_db* tdbb, SINT64 sessionId)
{
const auto attachment = tdbb->getAttachment();
AutoSetRestore<bool> autoInSystemPackage(&attachment->att_in_system_routine, true);
IAttachment* const attachmentIntf = attachment->getInterface();
ITransaction* const transactionIntf = tdbb->getTransaction()->getInterface(false);
ThrowLocalStatus throwStatus;
const char* deleteSessionSql = R"""(
execute block (session_id type of rdb$profile_session_id = ?) as
begin
delete from rdb$profile_record_source_stats where rdb$profile_session_id = :session_id;
delete from rdb$profile_stats where rdb$profile_session_id = :session_id;
delete from rdb$profile_requests where rdb$profile_session_id = :session_id;
end
)""";
FB_MESSAGE(SessionMessage, ThrowWrapper,
(FB_BIGINT, sessionId)
) sessionMessage(&throwStatus, fb_get_master_interface());
sessionMessage.clear();
sessionMessage->sessionId = sessionId;
sessionMessage->sessionIdNull = FB_FALSE;
attachmentIntf->execute(&throwStatus, transactionIntf, 0, deleteSessionSql, SQL_DIALECT_CURRENT,
sessionMessage.getMetadata(), sessionMessage.getData(), nullptr, nullptr);
}
void Profiler::setupCursor(thread_db* tdbb, jrd_req* request, const Cursor* cursor) void Profiler::setupCursor(thread_db* tdbb, jrd_req* request, const Cursor* cursor)
{ {
if (!isActive()) if (!isActive())
@ -322,7 +314,7 @@ void Profiler::hitRecSourceGetRecord(jrd_req* request, ULONG recSourceId, SINT64
profileRecSource->fetchStats.hit(runTime); profileRecSource->fetchStats.hit(runTime);
} }
void Profiler::updateSnapshot(thread_db* tdbb) void Profiler::refreshSnapshots(thread_db* tdbb)
{ {
const static UCHAR TEMP_BPB[] = {isc_bpb_version1, isc_bpb_storage, 1, isc_bpb_storage_temp}; const static UCHAR TEMP_BPB[] = {isc_bpb_version1, isc_bpb_storage, 1, isc_bpb_storage_temp};
@ -330,34 +322,12 @@ void Profiler::updateSnapshot(thread_db* tdbb)
ITransaction* const transaction = tdbb->getTransaction()->getInterface(false); ITransaction* const transaction = tdbb->getTransaction()->getInterface(false);
ThrowLocalStatus throwStatus; ThrowLocalStatus throwStatus;
const char* sessionSql = const char* sessionSql = R"""(
"update or insert into rdb$profile_sessions\n" update or insert into rdb$profile_sessions
" (rdb$profile_session_id, rdb$attachment_id, rdb$user, rdb$description, rdb$start_timestamp, rdb$finish_timestamp)\n" (rdb$profile_session_id, rdb$attachment_id, rdb$user, rdb$description, rdb$start_timestamp, rdb$finish_timestamp)
" values (?, ?, ?, ?, ?, ?)\n" values (?, ?, ?, ?, ?, ?)
" matching (rdb$profile_session_id)"; matching (rdb$profile_session_id);
)""";
const char* requestSql =
"update or insert into rdb$profile_requests\n"
" (rdb$profile_session_id, rdb$profile_request_id, rdb$timestamp, rdb$request_type, rdb$package_name,\n"
" rdb$routine_name, rdb$sql_text)\n"
" values (?, ?, ?, ?, ?, ?, ?)\n"
" matching (rdb$profile_session_id, rdb$profile_request_id)";
const char* recSrcStatsSql =
"update or insert into rdb$profile_record_source_stats\n"
" (rdb$profile_session_id, rdb$profile_request_id, rdb$cursor_id, rdb$record_source_id,\n"
" rdb$parent_record_source_id, rdb$access_path,\n"
" rdb$open_counter, rdb$open_min_time, rdb$open_max_time, rdb$open_total_time,\n"
" rdb$fetch_counter, rdb$fetch_min_time, rdb$fetch_max_time, rdb$fetch_total_time)\n"
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n"
" matching (rdb$profile_session_id, rdb$profile_request_id, rdb$cursor_id, rdb$record_source_id)";
const char* statsSql =
"update or insert into rdb$profile_stats\n"
" (rdb$profile_session_id, rdb$profile_request_id, rdb$line, rdb$column,\n"
" rdb$counter, rdb$min_time, rdb$max_time, rdb$total_time)\n"
" values (?, ?, ?, ?, ?, ?, ?, ?)\n"
" matching (rdb$profile_session_id, rdb$profile_request_id, rdb$line, rdb$column)";
FB_MESSAGE(SessionMessage, ThrowWrapper, FB_MESSAGE(SessionMessage, ThrowWrapper,
(FB_BIGINT, sessionId) (FB_BIGINT, sessionId)
@ -369,6 +339,14 @@ void Profiler::updateSnapshot(thread_db* tdbb)
) sessionMessage(&throwStatus, fb_get_master_interface()); ) sessionMessage(&throwStatus, fb_get_master_interface());
sessionMessage.clear(); sessionMessage.clear();
const char* requestSql = R"""(
update or insert into rdb$profile_requests
(rdb$profile_session_id, rdb$profile_request_id, rdb$timestamp, rdb$request_type, rdb$package_name,
rdb$routine_name, rdb$sql_text)
values (?, ?, ?, ?, ?, ?, ?)
matching (rdb$profile_session_id, rdb$profile_request_id)
)""";
FB_MESSAGE(RequestMessage, ThrowWrapper, FB_MESSAGE(RequestMessage, ThrowWrapper,
(FB_BIGINT, sessionId) (FB_BIGINT, sessionId)
(FB_BIGINT, requestId) (FB_BIGINT, requestId)
@ -380,6 +358,16 @@ void Profiler::updateSnapshot(thread_db* tdbb)
) requestMessage(&throwStatus, fb_get_master_interface()); ) requestMessage(&throwStatus, fb_get_master_interface());
requestMessage.clear(); requestMessage.clear();
const char* recSrcStatsSql = R"""(
update or insert into rdb$profile_record_source_stats
(rdb$profile_session_id, rdb$profile_request_id, rdb$cursor_id, rdb$record_source_id,
rdb$parent_record_source_id, rdb$access_path,
rdb$open_counter, rdb$open_min_time, rdb$open_max_time, rdb$open_total_time,
rdb$fetch_counter, rdb$fetch_min_time, rdb$fetch_max_time, rdb$fetch_total_time)
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
matching (rdb$profile_session_id, rdb$profile_request_id, rdb$cursor_id, rdb$record_source_id)
)""";
FB_MESSAGE(RecSrcStatsMessage, ThrowWrapper, FB_MESSAGE(RecSrcStatsMessage, ThrowWrapper,
(FB_BIGINT, sessionId) (FB_BIGINT, sessionId)
(FB_BIGINT, requestId) (FB_BIGINT, requestId)
@ -398,6 +386,14 @@ void Profiler::updateSnapshot(thread_db* tdbb)
) recSrcStatsMessage(&throwStatus, fb_get_master_interface()); ) recSrcStatsMessage(&throwStatus, fb_get_master_interface());
recSrcStatsMessage.clear(); recSrcStatsMessage.clear();
const char* statsSql = R"""(
update or insert into rdb$profile_stats
(rdb$profile_session_id, rdb$profile_request_id, rdb$line, rdb$column,
rdb$counter, rdb$min_time, rdb$max_time, rdb$total_time)
values (?, ?, ?, ?, ?, ?, ?, ?)
matching (rdb$profile_session_id, rdb$profile_request_id, rdb$line, rdb$column)
)""";
FB_MESSAGE(StatsMessage, ThrowWrapper, FB_MESSAGE(StatsMessage, ThrowWrapper,
(FB_BIGINT, sessionId) (FB_BIGINT, sessionId)
(FB_BIGINT, requestId) (FB_BIGINT, requestId)
@ -630,7 +626,7 @@ ProfilerPackage::ProfilerPackage(MemoryPool& pool)
prc_executable, prc_executable,
// input parameters // input parameters
{ {
{"UPDATE_SNAPSHOT", fld_bool, false} {"REFRESH_SNAPSHOTS", fld_bool, false}
}, },
// output parameters // output parameters
{ {
@ -638,8 +634,8 @@ ProfilerPackage::ProfilerPackage(MemoryPool& pool)
), ),
SystemProcedure( SystemProcedure(
pool, pool,
"UPDATE_SNAPSHOT", "REFRESH_SNAPSHOTS",
SystemProcedureFactory<VoidMessage, VoidMessage, updateSnapshotProcedure>(), SystemProcedureFactory<VoidMessage, VoidMessage, refreshSnapshotsProcedure>(),
prc_executable, prc_executable,
// input parameters // input parameters
{ {
@ -655,19 +651,7 @@ ProfilerPackage::ProfilerPackage(MemoryPool& pool)
prc_executable, prc_executable,
// input parameters // input parameters
{ {
{"UPDATE_SNAPSHOT", fld_bool, false} {"REFRESH_SNAPSHOTS", fld_bool, false}
},
// output parameters
{
}
),
SystemProcedure(
pool,
"PURGE_SNAPSHOTS",
SystemProcedureFactory<VoidMessage, VoidMessage, purgeSnapshotsProcedure>(),
prc_executable,
// input parameters
{
}, },
// output parameters // output parameters
{ {

View File

@ -149,6 +149,7 @@ private:
public: public:
static Profiler* create(thread_db* tdbb); static Profiler* create(thread_db* tdbb);
static void deleteSessionDetails(thread_db* tdbb, SINT64 sessionId);
public: public:
void setupCursor(thread_db* tdbb, jrd_req* request, const Cursor* cursor); void setupCursor(thread_db* tdbb, jrd_req* request, const Cursor* cursor);
@ -173,15 +174,15 @@ private:
ULONG((lineColumn >> 32) & 0xFFFFFFFF), ULONG(lineColumn & 0xFFFFFFFF)); ULONG((lineColumn >> 32) & 0xFFFFFFFF), ULONG(lineColumn & 0xFFFFFFFF));
} }
void updateSnapshot(thread_db* tdbb); void refreshSnapshots(thread_db* tdbb);
Request* getRequest(jrd_req* request); Request* getRequest(jrd_req* request);
private: private:
ULONG currentSessionId = 0; SINT64 currentSessionId = 0;
bool activeSession = false; bool activeSession = false;
bool paused = false; bool paused = false;
Firebird::RightPooledMap<ULONG, Session> sessions; Firebird::RightPooledMap<SINT64, Session> sessions;
}; };
@ -191,13 +192,13 @@ public:
ProfilerPackage(Firebird::MemoryPool& pool); ProfilerPackage(Firebird::MemoryPool& pool);
private: private:
static Firebird::IExternalResultSet* updateSnapshotProcedure(Firebird::ThrowStatusExceptionWrapper* status, static Firebird::IExternalResultSet* refreshSnapshotsProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const void* in, void* out); Firebird::IExternalContext* context, const void* in, void* out);
//---------- //----------
FB_MESSAGE(FinishSessionInput, Firebird::ThrowStatusExceptionWrapper, FB_MESSAGE(FinishSessionInput, Firebird::ThrowStatusExceptionWrapper,
(FB_BOOLEAN, updateSnapshot) (FB_BOOLEAN, refreshSnapshots)
); );
static Firebird::IExternalResultSet* finishSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status, static Firebird::IExternalResultSet* finishSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
@ -206,7 +207,7 @@ private:
//---------- //----------
FB_MESSAGE(PauseSessionInput, Firebird::ThrowStatusExceptionWrapper, FB_MESSAGE(PauseSessionInput, Firebird::ThrowStatusExceptionWrapper,
(FB_BOOLEAN, updateSnapshot) (FB_BOOLEAN, refreshSnapshots)
); );
static Firebird::IExternalResultSet* pauseSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status, static Firebird::IExternalResultSet* pauseSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
@ -214,11 +215,6 @@ private:
//---------- //----------
static Firebird::IExternalResultSet* purgeSnapshotsProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const void* in, void* out);
//----------
static Firebird::IExternalResultSet* resumeSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status, static Firebird::IExternalResultSet* resumeSessionProcedure(Firebird::ThrowStatusExceptionWrapper* status,
Firebird::IExternalContext* context, const void* in, void* out); Firebird::IExternalContext* context, const void* in, void* out);

View File

@ -65,6 +65,7 @@ SYSTEM_PRIVILEGE(CREATE_PRIVILEGED_ROLES)
SYSTEM_PRIVILEGE(GET_DBCRYPT_INFO) SYSTEM_PRIVILEGE(GET_DBCRYPT_INFO)
SYSTEM_PRIVILEGE(MODIFY_EXT_CONN_POOL) SYSTEM_PRIVILEGE(MODIFY_EXT_CONN_POOL)
SYSTEM_PRIVILEGE(REPLICATE_INTO_DATABASE) SYSTEM_PRIVILEGE(REPLICATE_INTO_DATABASE)
SYSTEM_PRIVILEGE(DELETE_ANY_PROFILE_SESSION)
#ifdef FB_JRD_SYSTEM_PRIVILEGES_TMP #ifdef FB_JRD_SYSTEM_PRIVILEGES_TMP
maxSystemPrivilege maxSystemPrivilege

View File

@ -615,6 +615,11 @@ void INI_format(const char* owner, const char* charset)
store_admin_grant(tdbb, buf.c_str(), obj_privilege, "RDB$DB_CREATORS", obj_relation, "SIUDR"); store_admin_grant(tdbb, buf.c_str(), obj_privilege, "RDB$DB_CREATORS", obj_relation, "SIUDR");
GRANT_privileges(tdbb, "RDB$DB_CREATORS", obj_relation, attachment->getSysTransaction()); GRANT_privileges(tdbb, "RDB$DB_CREATORS", obj_relation, attachment->getSysTransaction());
// Allow everyone to delete RDB$PROFILE_SESSIONS. VIO_delete will check record permissions.
buf = "PUBLIC";
store_admin_grant(tdbb, buf.c_str(), obj_user, "RDB$PROFILE_SESSIONS", obj_relation, "D");
GRANT_privileges(tdbb, "RDB$PROFILE_SESSIONS", obj_relation, attachment->getSysTransaction());
DFW_perform_system_work(tdbb); DFW_perform_system_work(tdbb);
} }

View File

@ -88,6 +88,7 @@
#include "../jrd/Function.h" #include "../jrd/Function.h"
#include "../common/StatusArg.h" #include "../common/StatusArg.h"
#include "../jrd/GarbageCollector.h" #include "../jrd/GarbageCollector.h"
#include "../jrd/Profiler.h"
#include "../jrd/trace/TraceManager.h" #include "../jrd/trace/TraceManager.h"
#include "../jrd/trace/TraceJrdHelpers.h" #include "../jrd/trace/TraceJrdHelpers.h"
@ -1454,7 +1455,7 @@ static bool check_prepare_result(int prepare_result, jrd_tra* transaction, jrd_r
************************************** **************************************
* *
* Functional description * Functional description
* Called by VIO_modify and VIO_erase. Raise update conflict error if not in * Called by VIO_modify and VIO_erase. Raise update conflict error if not in
* read consistency transaction or lock error happens or if request is already * read consistency transaction or lock error happens or if request is already
* in update conflict mode. In latter case set TRA_ex_restart flag to correctly * in update conflict mode. In latter case set TRA_ex_restart flag to correctly
* handle request restart. * handle request restart.
@ -1465,17 +1466,17 @@ static bool check_prepare_result(int prepare_result, jrd_tra* transaction, jrd_r
jrd_req* top_request = request->req_snapshot.m_owner; jrd_req* top_request = request->req_snapshot.m_owner;
const bool restart_ready = top_request && const bool restart_ready = top_request &&
(top_request->req_flags & req_restart_ready); (top_request->req_flags & req_restart_ready);
// Second update conflict when request is already in update conflict mode // Second update conflict when request is already in update conflict mode
// means we have some (indirect) UPDATE\DELETE in WHERE clause of primary // means we have some (indirect) UPDATE\DELETE in WHERE clause of primary
// cursor. In this case all we can do is restart whole request immediately. // cursor. In this case all we can do is restart whole request immediately.
const bool secondary = top_request && const bool secondary = top_request &&
(top_request->req_flags & req_update_conflict) && (top_request->req_flags & req_update_conflict) &&
(prepare_result != PREPARE_LOCKERR); (prepare_result != PREPARE_LOCKERR);
if (!(transaction->tra_flags & TRA_read_consistency) || prepare_result == PREPARE_LOCKERR || if (!(transaction->tra_flags & TRA_read_consistency) || prepare_result == PREPARE_LOCKERR ||
secondary || !restart_ready) secondary || !restart_ready)
{ {
if (secondary) if (secondary)
@ -1610,9 +1611,31 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
case rel_packages: case rel_packages:
case rel_charsets: case rel_charsets:
case rel_pubs: case rel_pubs:
case rel_prof_requests:
case rel_prof_stats:
case rel_prof_recsrc_stats:
protect_system_table_delupd(tdbb, relation, "DELETE"); protect_system_table_delupd(tdbb, relation, "DELETE");
break; break;
case rel_prof_sessions:
if (EVL_field(0, rpb->rpb_record, f_prof_ses_user, &desc) &&
EVL_field(0, rpb->rpb_record, f_prof_ses_id, &desc2))
{
MetaName user;
MOV_get_metaname(tdbb, &desc, user);
if (user != tdbb->getAttachment()->att_user->getUserName() &&
!tdbb->getAttachment()->locksmith(tdbb, DELETE_ANY_PROFILE_SESSION))
{
ERR_post(
Arg::Gds(isc_miss_prvlg) <<
Arg::Str("DELETE_ANY_PROFILE_SESSION"));
}
Profiler::deleteSessionDetails(tdbb, MOV_get_long(tdbb, &desc2, 0));
}
break;
case rel_relations: case rel_relations:
protect_system_table_delupd(tdbb, relation, "DELETE"); protect_system_table_delupd(tdbb, relation, "DELETE");
if (EVL_field(0, rpb->rpb_record, f_rel_id, &desc2)) if (EVL_field(0, rpb->rpb_record, f_rel_id, &desc2))
@ -2861,6 +2884,10 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
case rel_roles: case rel_roles:
case rel_ccon: case rel_ccon:
case rel_pub_tables: case rel_pub_tables:
case rel_prof_sessions:
case rel_prof_requests:
case rel_prof_stats:
case rel_prof_recsrc_stats:
protect_system_table_delupd(tdbb, relation, "UPDATE"); protect_system_table_delupd(tdbb, relation, "UPDATE");
break; break;
@ -3197,7 +3224,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
const bool backVersion = (org_rpb->rpb_b_page != 0); const bool backVersion = (org_rpb->rpb_b_page != 0);
record_param temp; record_param temp;
PageStack stack; PageStack stack;
int prepare_result = prepare_update(tdbb, transaction, org_rpb->rpb_transaction_nr, org_rpb, int prepare_result = prepare_update(tdbb, transaction, org_rpb->rpb_transaction_nr, org_rpb,
&temp, new_rpb, stack, false); &temp, new_rpb, stack, false);
if (!check_prepare_result(prepare_result, transaction, tdbb->getRequest(), org_rpb)) if (!check_prepare_result(prepare_result, transaction, tdbb->getRequest(), org_rpb))
return false; return false;
@ -3497,6 +3524,10 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
case rel_dpds: case rel_dpds:
case rel_dims: case rel_dims:
case rel_segments: case rel_segments:
case rel_prof_sessions:
case rel_prof_requests:
case rel_prof_stats:
case rel_prof_recsrc_stats:
protect_system_table_insert(tdbb, request, relation); protect_system_table_insert(tdbb, request, relation);
break; break;