8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:40:38 +01:00

Add PLG$PROF_CURSORS and some others fixes.

This commit is contained in:
Adriano dos Santos Fernandes 2023-01-10 20:45:24 -03:00 committed by Adriano dos Santos Fernandes
parent 88d89bb918
commit 4595a2c0e3
9 changed files with 245 additions and 11 deletions

View File

@ -248,6 +248,16 @@ Below is the list of tables that stores profile data.
- `SQL_TEXT` type `BLOB subtype TEXT CHARACTER SET UTF8` - SQL text for BLOCK
- Primary key: `PROFILE_ID, STATEMENT_ID`
## Table `PLG$PROF_CURSORS`
- `PROFILE_ID` type `BIGINT` - Profile session ID
- `STATEMENT_ID` type `BIGINT` - Statement ID
- `CURSOR_ID` type `INTEGER` - Cursor ID
- `NAME` type `CHAR(63) CHARACTER SET UTF8` - Name of explicit cursor
- `LINE_NUM` type `INTEGER` - Line number of the cursor
- `COLUMN_NUM` type `INTEGER` - Column number of the cursor
- Primary key: `PROFILE_ID, STATEMENT_ID, CURSOR_ID`
## Table `PLG$PROF_RECORD_SOURCES`
- `PROFILE_ID` type `BIGINT` - Profile session ID
@ -403,6 +413,9 @@ select rstat.profile_id,
statement_id = coalesce(sta.parent_statement_id, rstat.statement_id)
) sql_text,
rstat.cursor_id,
cur.name cursor_name,
cur.line_num cursor_line_num,
cur.column_num cursor_column_num,
rstat.record_source_id,
recsrc.parent_record_source_id,
recsrc.access_path,
@ -418,6 +431,10 @@ select rstat.profile_id,
cast(sum(rstat.fetch_total_elapsed_time) / nullif(sum(rstat.fetch_counter), 0) as bigint) fetch_avg_elapsed_time,
cast(coalesce(sum(rstat.open_total_elapsed_time), 0) + coalesce(sum(rstat.fetch_total_elapsed_time), 0) as bigint) open_fetch_total_elapsed_time
from plg$prof_record_source_stats rstat
join plg$prof_cursors cur
on cur.profile_id = rstat.profile_id and
cur.statement_id = rstat.statement_id and
cur.cursor_id = rstat.cursor_id
join plg$prof_record_sources recsrc
on recsrc.profile_id = rstat.profile_id and
recsrc.statement_id = rstat.statement_id and
@ -438,6 +455,9 @@ select rstat.profile_id,
sta_parent.statement_type,
sta_parent.routine_name,
rstat.cursor_id,
cur.name,
cur.line_num,
cur.column_num,
rstat.record_source_id,
recsrc.parent_record_source_id,
recsrc.access_path

View File

@ -1741,7 +1741,7 @@ interface ProfilerSession : Disposable
void defineStatement(Status status, int64 statementId, int64 parentStatementId,
const string type, const string packageName, const string routineName, const string sqlText);
//// TODO: Add defineCursor with line/column
void defineCursor(int64 statementId, uint cursorId, const string name, uint line, uint column);
void defineRecordSource(int64 statementId, uint cursorId, uint recSourceId,
const string accessPath, uint parentRecSourceId);

View File

@ -6953,6 +6953,7 @@ namespace Firebird
void (CLOOP_CARG *cancel)(IProfilerSession* self, IStatus* status) CLOOP_NOEXCEPT;
void (CLOOP_CARG *finish)(IProfilerSession* self, IStatus* status, ISC_TIMESTAMP_TZ timestamp) CLOOP_NOEXCEPT;
void (CLOOP_CARG *defineStatement)(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) CLOOP_NOEXCEPT;
void (CLOOP_CARG *defineCursor)(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column) CLOOP_NOEXCEPT;
void (CLOOP_CARG *defineRecordSource)(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) CLOOP_NOEXCEPT;
void (CLOOP_CARG *onRequestStart)(IProfilerSession* self, IStatus* status, ISC_INT64 requestId, ISC_INT64 statementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) CLOOP_NOEXCEPT;
void (CLOOP_CARG *onRequestFinish)(IProfilerSession* self, IStatus* status, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats) CLOOP_NOEXCEPT;
@ -7013,6 +7014,11 @@ namespace Firebird
StatusType::checkException(status);
}
void defineCursor(ISC_INT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column)
{
static_cast<VTable*>(this->cloopVTable)->defineCursor(this, statementId, cursorId, name, line, column);
}
void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId)
{
static_cast<VTable*>(this->cloopVTable)->defineRecordSource(this, statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
@ -20426,6 +20432,7 @@ namespace Firebird
this->cancel = &Name::cloopcancelDispatcher;
this->finish = &Name::cloopfinishDispatcher;
this->defineStatement = &Name::cloopdefineStatementDispatcher;
this->defineCursor = &Name::cloopdefineCursorDispatcher;
this->defineRecordSource = &Name::cloopdefineRecordSourceDispatcher;
this->onRequestStart = &Name::clooponRequestStartDispatcher;
this->onRequestFinish = &Name::clooponRequestFinishDispatcher;
@ -20509,6 +20516,18 @@ namespace Firebird
}
}
static void CLOOP_CARG cloopdefineCursorDispatcher(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column) CLOOP_NOEXCEPT
{
try
{
static_cast<Name*>(self)->Name::defineCursor(statementId, cursorId, name, line, column);
}
catch (...)
{
StatusType::catchException(0);
}
}
static void CLOOP_CARG cloopdefineRecordSourceDispatcher(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) CLOOP_NOEXCEPT
{
try
@ -20652,6 +20671,7 @@ namespace Firebird
virtual void cancel(StatusType* status) = 0;
virtual void finish(StatusType* status, ISC_TIMESTAMP_TZ timestamp) = 0;
virtual void defineStatement(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) = 0;
virtual void defineCursor(ISC_INT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column) = 0;
virtual void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) = 0;
virtual void onRequestStart(StatusType* status, ISC_INT64 requestId, ISC_INT64 statementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) = 0;
virtual void onRequestFinish(StatusType* status, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats) = 0;

View File

@ -726,6 +726,7 @@ type
IProfilerSession_cancelPtr = procedure(this: IProfilerSession; status: IStatus); cdecl;
IProfilerSession_finishPtr = procedure(this: IProfilerSession; status: IStatus; timestamp: ISC_TIMESTAMP_TZ); cdecl;
IProfilerSession_defineStatementPtr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl;
IProfilerSession_defineCursorPtr = procedure(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal); cdecl;
IProfilerSession_defineRecordSourcePtr = procedure(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl;
IProfilerSession_onRequestStartPtr = procedure(this: IProfilerSession; status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); cdecl;
IProfilerSession_onRequestFinishPtr = procedure(this: IProfilerSession; status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats); cdecl;
@ -3814,6 +3815,7 @@ type
cancel: IProfilerSession_cancelPtr;
finish: IProfilerSession_finishPtr;
defineStatement: IProfilerSession_defineStatementPtr;
defineCursor: IProfilerSession_defineCursorPtr;
defineRecordSource: IProfilerSession_defineRecordSourcePtr;
onRequestStart: IProfilerSession_onRequestStartPtr;
onRequestFinish: IProfilerSession_onRequestFinishPtr;
@ -3835,6 +3837,7 @@ type
procedure cancel(status: IStatus);
procedure finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ);
procedure defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar);
procedure defineCursor(statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal);
procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal);
procedure onRequestStart(status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ);
procedure onRequestFinish(status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats);
@ -3855,6 +3858,7 @@ type
procedure cancel(status: IStatus); virtual; abstract;
procedure finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ); virtual; abstract;
procedure defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); virtual; abstract;
procedure defineCursor(statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal); virtual; abstract;
procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); virtual; abstract;
procedure onRequestStart(status: IStatus; requestId: Int64; statementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); virtual; abstract;
procedure onRequestFinish(status: IStatus; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats); virtual; abstract;
@ -9082,6 +9086,11 @@ begin
FbException.checkException(status);
end;
procedure IProfilerSession.defineCursor(statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal);
begin
ProfilerSessionVTable(vTable).defineCursor(Self, statementId, cursorId, name, line, column);
end;
procedure IProfilerSession.defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal);
begin
ProfilerSessionVTable(vTable).defineRecordSource(Self, statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
@ -15788,6 +15797,15 @@ begin
end
end;
procedure IProfilerSessionImpl_defineCursorDispatcher(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal); cdecl;
begin
try
IProfilerSessionImpl(this).defineCursor(statementId, cursorId, name, line, column);
except
on e: Exception do FbException.catchException(nil, e);
end
end;
procedure IProfilerSessionImpl_defineRecordSourceDispatcher(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl;
begin
try
@ -16903,6 +16921,7 @@ initialization
IProfilerSessionImpl_vTable.cancel := @IProfilerSessionImpl_cancelDispatcher;
IProfilerSessionImpl_vTable.finish := @IProfilerSessionImpl_finishDispatcher;
IProfilerSessionImpl_vTable.defineStatement := @IProfilerSessionImpl_defineStatementDispatcher;
IProfilerSessionImpl_vTable.defineCursor := @IProfilerSessionImpl_defineCursorDispatcher;
IProfilerSessionImpl_vTable.defineRecordSource := @IProfilerSessionImpl_defineRecordSourceDispatcher;
IProfilerSessionImpl_vTable.onRequestStart := @IProfilerSessionImpl_onRequestStartDispatcher;
IProfilerSessionImpl_vTable.onRequestFinish := @IProfilerSessionImpl_onRequestFinishDispatcher;

View File

@ -464,6 +464,24 @@ SINT64 ProfilerManager::startSession(thread_db* tdbb, Nullable<SLONG> flushInter
return currentSession->pluginSession->getId();
}
void ProfilerManager::prepareCursor(thread_db* tdbb, Request* request, const Cursor* cursor)
{
auto profileStatement = getStatement(request);
if (!profileStatement)
return;
auto cursorId = cursor->getCursorProfileId();
if (profileStatement->definedCursors.exist(cursorId))
return;
currentSession->pluginSession->defineCursor(profileStatement->id, cursorId,
cursor->getName().nullStr(), cursor->getLine(), cursor->getColumn());
profileStatement->definedCursors.add(cursorId);
}
void ProfilerManager::prepareRecSource(thread_db* tdbb, Request* request, const RecordSource* rsb)
{
auto profileStatement = getStatement(request);
@ -474,6 +492,8 @@ void ProfilerManager::prepareRecSource(thread_db* tdbb, Request* request, const
if (profileStatement->recSourceSequence.exist(rsb->getRecSourceProfileId()))
return;
fb_assert(profileStatement->definedCursors.exist(rsb->getCursorProfileId()));
Array<NonPooledPair<const RecordSource*, const RecordSource*>> tree;
tree.add({rsb, nullptr});

View File

@ -35,6 +35,7 @@
namespace Jrd {
class Attachment;
class Cursor;
class Request;
class RecordSource;
class thread_db;
@ -71,6 +72,7 @@ private:
public:
Statement(MemoryPool& pool)
: cursorNextSequence(pool),
definedCursors(pool),
recSourceSequence(pool)
{
}
@ -80,6 +82,7 @@ private:
SINT64 id = 0;
Firebird::NonPooledMap<ULONG, ULONG> cursorNextSequence;
Firebird::SortedArray<ULONG> definedCursors;
Firebird::NonPooledMap<ULONG, ULONG> recSourceSequence;
};
@ -120,6 +123,7 @@ public:
SINT64 startSession(thread_db* tdbb, Nullable<SLONG> flushInterval,
const Firebird::PathName& pluginName, const Firebird::string& description, const Firebird::string& options);
void prepareCursor(thread_db* tdbb, Request* request, const Cursor* cursor);
void prepareRecSource(thread_db* tdbb, Request* request, const RecordSource* rsb);
void onRequestFinish(Request* request, Stats& stats);
void beforePsqlLineColumn(Request* request, ULONG line, ULONG column);

View File

@ -146,6 +146,7 @@ bool SubQuery::fetch(thread_db* tdbb) const
Cursor::Cursor(CompilerScratch* csb, const RecordSource* rsb, const RseNode* rse,
bool updateCounters, ULONG line, ULONG column, const MetaName& name)
: Select(rsb, rse, line, column, name),
m_cursorProfileId(rsb->getCursorProfileId()),
m_updateCounters(updateCounters)
{
fb_assert(m_top);
@ -156,6 +157,9 @@ Cursor::Cursor(CompilerScratch* csb, const RecordSource* rsb, const RseNode* rse
void Cursor::open(thread_db* tdbb) const
{
const auto request = tdbb->getRequest();
prepareProfiler(tdbb, request);
Impure* impure = request->getImpure<Impure>(m_impure);
impure->irsb_active = true;
@ -197,6 +201,8 @@ bool Cursor::fetchNext(thread_db* tdbb) const
if (impure->irsb_state == EOS)
return false;
prepareProfiler(tdbb, request);
if (!m_top->getRecord(tdbb))
{
impure->irsb_state = EOS;
@ -287,6 +293,8 @@ bool Cursor::fetchAbsolute(thread_db* tdbb, SINT64 offset) const
return false;
}
prepareProfiler(tdbb, request);
impure->irsb_position = position;
buffer->locate(tdbb, impure->irsb_position);
@ -364,6 +372,8 @@ bool Cursor::fetchRelative(thread_db* tdbb, SINT64 offset) const
return false;
}
prepareProfiler(tdbb, request);
impure->irsb_position = position;
buffer->locate(tdbb, impure->irsb_position);
@ -402,3 +412,15 @@ void Cursor::checkState(Request* request) const
Arg::Str(m_cursorName));
}
}
void Cursor::prepareProfiler(thread_db* tdbb, Request* request) const
{
const auto attachment = tdbb->getAttachment();
const auto profilerManager = attachment->isProfilerActive() && !request->hasInternalStatement() ?
attachment->getProfilerManager(tdbb) :
nullptr;
if (profilerManager)
profilerManager->prepareCursor(tdbb, request, this);
}

View File

@ -57,6 +57,16 @@ namespace Jrd
return m_top;
}
ULONG getLine() const
{
return m_line;
}
ULONG getColumn() const
{
return m_column;
}
void initializeInvariants(Request* request) const;
void printPlan(thread_db* tdbb, Firebird::string& plan, bool detailed) const;
@ -115,10 +125,12 @@ namespace Jrd
void checkState(Request* request) const;
#if (!defined __GNUC__) || (__GNUC__ > 6)
constexpr
#endif
bool isUpdateCounters() const
ULONG getCursorProfileId() const
{
return m_cursorProfileId;
}
bool isUpdateCounters() const
{
return m_updateCounters;
}
@ -129,6 +141,10 @@ namespace Jrd
}
private:
void prepareProfiler(thread_db* tdbb, Request* request) const;
private:
const ULONG m_cursorProfileId;
ULONG m_impure;
const bool m_updateCounters;
};

View File

@ -86,6 +86,13 @@ struct Stats
FB_UINT64 totalElapsedTime = 0;
};
struct Cursor
{
MetaString name{defaultPool()};
unsigned line;
unsigned column;
};
struct RecordSource
{
Nullable<ULONG> parentId;
@ -124,6 +131,7 @@ struct Request
NonPooledMap<LineColumnKey, Stats> psqlStats{defaultPool()};
};
using StatementCursorKey = NonPooledPair<SINT64, unsigned>;
using StatementCursorRecSourceKey = NonPooledPair<NonPooledPair<SINT64, unsigned>, unsigned>;
class Session final :
@ -159,6 +167,8 @@ public:
void defineStatement(ThrowStatusExceptionWrapper* status, SINT64 statementId, SINT64 parentStatementId,
const char* type, const char* packageName, const char* routineName, const char* sqlText) override;
void defineCursor(SINT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column) override;
void defineRecordSource(SINT64 statementId, unsigned cursorId, unsigned recSourceId,
const char* accessPath, unsigned parentRecordSourceId) override;
@ -191,6 +201,7 @@ public:
public:
RefPtr<ProfilerPlugin> plugin;
NonPooledMap<SINT64, Statement> statements{defaultPool()};
NonPooledMap<StatementCursorKey, Cursor> cursors{defaultPool()};
NonPooledMap<StatementCursorRecSourceKey, RecordSource> recordSources{defaultPool()};
NonPooledMap<SINT64, Request> requests{defaultPool()};
SINT64 id;
@ -374,6 +385,23 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status)
) statementMessage(status, MasterInterfacePtr());
statementMessage.clear();
constexpr auto cursorSql = R"""(
update or insert into plg$prof_cursors
(profile_id, statement_id, cursor_id, name, line_num, column_num)
values (?, ?, ?, ?, ?, ?)
matching (profile_id, statement_id, cursor_id)
)""";
FB_MESSAGE(CursorMessage, ThrowStatusExceptionWrapper,
(FB_BIGINT, profileId)
(FB_BIGINT, statementId)
(FB_INTEGER, cursorId)
(FB_INTL_VARCHAR(METADATA_IDENTIFIER_CHAR_LEN * 4, CS_UTF8), name)
(FB_BIGINT, lineNum)
(FB_BIGINT, columnNum)
) cursorMessage(status, MasterInterfacePtr());
cursorMessage.clear();
constexpr auto recSrcSql = R"""(
update or insert into plg$prof_record_sources
(profile_id, statement_id, cursor_id, record_source_id,
@ -387,7 +415,7 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status)
(FB_BIGINT, statementId)
(FB_INTEGER, cursorId)
(FB_INTEGER, recordSourceId)
(FB_BIGINT, parentRecordSourceId)
(FB_INTEGER, parentRecordSourceId)
(FB_INTL_VARCHAR(1024 * 4, CS_UTF8), accessPath)
) recSrcMessage(status, MasterInterfacePtr());
recSrcMessage.clear();
@ -523,11 +551,13 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status)
auto sessionStmt = makeNoIncRef(userAttachment->prepare(status, transaction, 0, sessionSql, SQL_DIALECT_CURRENT, 0));
auto statementStmt = makeNoIncRef(userAttachment->prepare(
status, transaction, 0, statementSql, SQL_DIALECT_CURRENT, 0));
auto recSrcsStmt = makeNoIncRef(userAttachment->prepare(
auto cursorStmt = makeNoIncRef(userAttachment->prepare(
status, transaction, 0, cursorSql, SQL_DIALECT_CURRENT, 0));
auto recSrcStmt = makeNoIncRef(userAttachment->prepare(
status, transaction, 0, recSrcSql, SQL_DIALECT_CURRENT, 0));
auto requestBatch = makeNoIncRef(userAttachment->createBatch(status, transaction, 0, requestSql, SQL_DIALECT_CURRENT,
requestMessage.getMetadata(), 0, nullptr));
auto recSrcStatsBatch = makeNoIncRef(userAttachment->createBatch(
auto recSrcStatBatch = makeNoIncRef(userAttachment->createBatch(
status, transaction, 0, recSrcStatSql, SQL_DIALECT_CURRENT, recSrcStatMessage.getMetadata(), 0, nullptr));
auto psqlStatBatch = makeNoIncRef(userAttachment->createBatch(
status, transaction, 0, psqlStatSql, SQL_DIALECT_CURRENT, psqlStatMessage.getMetadata(), 0, nullptr));
@ -550,7 +580,7 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status)
auto executeBatches = [&]()
{
executeBatch(requestBatch, requestBatchSize);
executeBatch(recSrcStatsBatch, recSrcStatBatchSize);
executeBatch(recSrcStatBatch, recSrcStatBatchSize);
executeBatch(psqlStatBatch, psqlStatBatchSize);
};
@ -653,6 +683,34 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status)
}
}
for (const auto& cursorIt : session->cursors)
{
const auto statementId = cursorIt.first.first;
const auto cursorId = cursorIt.first.second;
const auto& cursor = cursorIt.second;
cursorMessage->profileIdNull = FB_FALSE;
cursorMessage->profileId = session->getId();
cursorMessage->statementIdNull = FB_FALSE;
cursorMessage->statementId = statementId;
cursorMessage->cursorIdNull = FB_FALSE;
cursorMessage->cursorId = cursorId;
cursorMessage->nameNull = cursor.name.isEmpty();
cursorMessage->name.set(cursor.name.c_str());
cursorMessage->lineNumNull = cursor.line == 0 ? FB_TRUE : FB_FALSE;
cursorMessage->lineNum = cursor.line;
cursorMessage->columnNumNull = cursor.column == 0 ? FB_TRUE : FB_FALSE;
cursorMessage->columnNum = cursor.column;
cursorStmt->execute(status, transaction, cursorMessage.getMetadata(),
cursorMessage.getData(), nullptr, nullptr);
}
for (const auto& recSourceIt : session->recordSources)
{
const auto statementId = recSourceIt.first.first.first;
@ -678,7 +736,7 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status)
recSrcMessage->accessPathNull = FB_FALSE;
recSrcMessage->accessPath.set(recSrc.accessPath.c_str());
recSrcsStmt->execute(status, transaction, recSrcMessage.getMetadata(),
recSrcStmt->execute(status, transaction, recSrcMessage.getMetadata(),
recSrcMessage.getData(), nullptr, nullptr);
}
@ -791,7 +849,7 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status)
recSrcStatMessage->fetchTotalElapsedTimeNull = FB_FALSE;
recSrcStatMessage->fetchTotalElapsedTime = stats.fetchStats.totalElapsedTime;
addBatch(recSrcStatsBatch, recSrcStatBatchSize, recSrcStatMessage);
addBatch(recSrcStatBatch, recSrcStatBatchSize, recSrcStatMessage);
}
profileRequest.recordSourcesStats.clear();
@ -838,6 +896,7 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status)
{
session->statements.clear();
session->recordSources.clear();
session->cursors.clear();
for (const auto requestId : finishedRequests)
session->requests.remove(requestId);
@ -905,6 +964,29 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr<
"grant select, update, insert, delete on table plg$prof_statements to plg$profiler",
R"""(
create table plg$prof_cursors (
profile_id bigint not null
constraint plg$prof_cursors_session_fk
references plg$prof_sessions
on delete cascade
using index plg$prof_cursors_profile,
statement_id bigint not null,
cursor_id integer not null,
name char(63) character set utf8,
line_num integer,
column_num integer,
constraint plg$prof_cursors_pk
primary key (profile_id, statement_id, cursor_id)
using index plg$prof_cursors_profile_statement_cursor,
constraint plg$prof_cursors_statement_fk
foreign key (profile_id, statement_id) references plg$prof_statements
on delete cascade
using index plg$prof_cursors_profile_statement
))""",
"grant select, update, insert, delete on table plg$prof_cursors to plg$profiler",
R"""(
create table plg$prof_record_sources (
profile_id bigint not null
@ -924,6 +1006,10 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr<
foreign key (profile_id, statement_id) references plg$prof_statements
on delete cascade
using index plg$prof_record_sources_profile_statement,
constraint plg$prof_record_sources_cursor_fk
foreign key (profile_id, statement_id, cursor_id) references plg$prof_cursors
on delete cascade
using index plg$prof_record_sources_profile_statement_cursor,
constraint plg$prof_record_sources_parent_record_source_fk
foreign key (profile_id, statement_id, cursor_id, parent_record_source_id)
references plg$prof_record_sources (profile_id, statement_id, cursor_id, record_source_id)
@ -1021,6 +1107,10 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr<
foreign key (profile_id, statement_id) references plg$prof_statements
on delete cascade
using index plg$prof_record_source_stats_profile_statement,
constraint plg$prof_record_source_stats_cursor_fk
foreign key (profile_id, statement_id, cursor_id) references plg$prof_cursors
on delete cascade
using index plg$prof_record_source_stats_statement_cursor,
constraint plg$prof_record_source_stats_record_source_fk
foreign key (profile_id, statement_id, cursor_id, record_source_id) references plg$prof_record_sources
on delete cascade
@ -1132,6 +1222,9 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr<
statement_id = coalesce(sta.parent_statement_id, rstat.statement_id)
) sql_text,
rstat.cursor_id,
cur.name cursor_name,
cur.line_num cursor_line_num,
cur.column_num cursor_column_num,
rstat.record_source_id,
recsrc.parent_record_source_id,
recsrc.access_path,
@ -1147,6 +1240,10 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr<
cast(sum(rstat.fetch_total_elapsed_time) / nullif(sum(rstat.fetch_counter), 0) as bigint) fetch_avg_elapsed_time,
cast(coalesce(sum(rstat.open_total_elapsed_time), 0) + coalesce(sum(rstat.fetch_total_elapsed_time), 0) as bigint) open_fetch_total_elapsed_time
from plg$prof_record_source_stats rstat
join plg$prof_cursors cur
on cur.profile_id = rstat.profile_id and
cur.statement_id = rstat.statement_id and
cur.cursor_id = rstat.cursor_id
join plg$prof_record_sources recsrc
on recsrc.profile_id = rstat.profile_id and
recsrc.statement_id = rstat.statement_id and
@ -1167,6 +1264,9 @@ void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr<
sta_parent.statement_type,
sta_parent.routine_name,
rstat.cursor_id,
cur.name,
cur.line_num,
cur.column_num,
rstat.record_source_id,
recsrc.parent_record_source_id,
recsrc.access_path
@ -1277,6 +1377,19 @@ void Session::defineStatement(ThrowStatusExceptionWrapper* status, SINT64 statem
statement->sqlText = sqlText;
}
void Session::defineCursor(SINT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column)
{
const auto cursor = cursors.put({statementId, cursorId});
fb_assert(cursor);
if (!cursor)
return;
cursor->name = name;
cursor->line = line;
cursor->column = column;
}
void Session::defineRecordSource(SINT64 statementId, unsigned cursorId, unsigned recSourceId,
const char* accessPath, unsigned parentRecordSourceId)
{