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

Fix #7553 - Firebird 5 profiler error with subselects.
Some checks reported errors
continuous-integration/drone/push Build encountered an error

This commit is contained in:
Adriano dos Santos Fernandes 2023-04-26 20:02:39 -03:00
parent 5205d16b9f
commit e05d8f7d15
13 changed files with 148 additions and 102 deletions

View File

@ -58,9 +58,7 @@ static const int MAX_MEMBER_LIST = 1500;
BoolExprNode* BoolExprNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
pass2Boolean1(tdbb, csb);
ExprNode::pass2(tdbb, csb);
pass2Boolean2(tdbb, csb);
pass2Boolean(tdbb, csb, [=] { ExprNode::pass2(tdbb, csb); });
if (nodFlags & FLAG_INVARIANT)
{
@ -593,14 +591,13 @@ BoolExprNode* ComparativeBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
return this;
}
void ComparativeBoolNode::pass2Boolean1(thread_db* /*tdbb*/, CompilerScratch* csb)
void ComparativeBoolNode::pass2Boolean(thread_db* tdbb, CompilerScratch* csb, std::function<void ()> process)
{
if (nodFlags & FLAG_INVARIANT)
csb->csb_invariants.push(&impureOffset);
}
void ComparativeBoolNode::pass2Boolean2(thread_db* tdbb, CompilerScratch* csb)
{
process();
RecordKeyNode* keyNode;
if (arg3)
@ -1131,6 +1128,8 @@ BoolExprNode* ComparativeBoolNode::createRseNode(DsqlCompilerScratch* dsqlScratc
// Create output node.
RseBoolNode* rseBoolNode = FB_NEW_POOL(pool) RseBoolNode(pool, rseBlrOp, rse);
rseBoolNode->line = line;
rseBoolNode->column = column;
// Finish off by cleaning up contexts
dsqlScratch->unionContext.clear(baseUnion);
@ -1211,8 +1210,10 @@ BoolExprNode* MissingBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
return BoolExprNode::pass1(tdbb, csb);
}
void MissingBoolNode::pass2Boolean2(thread_db* tdbb, CompilerScratch* csb)
void MissingBoolNode::pass2Boolean(thread_db* tdbb, CompilerScratch* csb, std::function<void ()> process)
{
process();
RecordKeyNode* keyNode = nodeAs<RecordKeyNode>(arg);
if (keyNode && keyNode->aggregate)
@ -1433,9 +1434,7 @@ RseBoolNode::RseBoolNode(MemoryPool& pool, UCHAR aBlrOp, RecordSourceNode* aDsql
: TypedNode<BoolExprNode, ExprNode::TYPE_RSE_BOOL>(pool),
blrOp(aBlrOp),
ownSavepoint(true),
dsqlRse(aDsqlRse),
rse(NULL),
subQuery(NULL)
dsqlRse(aDsqlRse)
{
}
@ -1493,6 +1492,8 @@ BoolExprNode* RseBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
void RseBoolNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
dsqlScratch->appendUChar(blrOp);
dsqlScratch->putDebugSrcInfo(line, column);
GEN_rse(dsqlScratch, nodeAs<RseNode>(dsqlRse));
}
@ -1580,7 +1581,7 @@ BoolExprNode* RseBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
return BoolExprNode::pass1(tdbb, csb);
}
void RseBoolNode::pass2Boolean1(thread_db* tdbb, CompilerScratch* csb)
void RseBoolNode::pass2Boolean(thread_db* tdbb, CompilerScratch* csb, std::function<void ()> process)
{
if (rse->isInvariant())
{
@ -1588,11 +1589,12 @@ void RseBoolNode::pass2Boolean1(thread_db* tdbb, CompilerScratch* csb)
csb->csb_invariants.push(&impureOffset);
}
rse->pass2Rse(tdbb, csb);
}
AutoSetCurrentCursorProfileId autoSetCurrentCursorProfileId(csb);
rse->pass2Rse(tdbb, csb);
process();
void RseBoolNode::pass2Boolean2(thread_db* tdbb, CompilerScratch* csb)
{
if (nodFlags & FLAG_INVARIANT)
impureOffset = csb->allocImpure<impure_value>();

View File

@ -117,8 +117,7 @@ public:
virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const;
virtual bool sameAs(const ExprNode* other, bool ignoreStreams) const;
virtual BoolExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean1(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean2(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean(thread_db* tdbb, CompilerScratch* csb, std::function<void ()> process);
virtual bool execute(thread_db* tdbb, Request* request) const;
private:
@ -168,7 +167,7 @@ public:
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
virtual BoolExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean2(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean(thread_db* tdbb, CompilerScratch* csb, std::function<void ()> process);
virtual bool execute(thread_db* tdbb, Request* request) const;
public:
@ -209,7 +208,7 @@ public:
class RseBoolNode final : public TypedNode<BoolExprNode, ExprNode::TYPE_RSE_BOOL>
{
public:
RseBoolNode(MemoryPool& pool, UCHAR aBlrOp, RecordSourceNode* aDsqlRse = NULL);
RseBoolNode(MemoryPool& pool, UCHAR aBlrOp, RecordSourceNode* aDsqlRse = nullptr);
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
@ -251,8 +250,7 @@ public:
virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const;
virtual bool sameAs(const ExprNode* other, bool ignoreStreams) const;
virtual BoolExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean1(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean2(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean(thread_db* tdbb, CompilerScratch* csb, std::function<void ()> process);
virtual bool execute(thread_db* tdbb, Request* request) const;
private:

View File

@ -11049,7 +11049,6 @@ DmlNode* SubQueryNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
SubQueryNode* node = FB_NEW_POOL(pool) SubQueryNode(pool, (blrOp == blr_from ? blr_via : blrOp));
node->rse = PAR_rse(tdbb, csb);
node->rse->flags |= RseNode::FLAG_SUB_QUERY;
if (blrOp != blr_count)
@ -11112,6 +11111,9 @@ ValueExprNode* SubQueryNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
SubQueryNode* node = FB_NEW_POOL(dsqlScratch->getPool()) SubQueryNode(dsqlScratch->getPool(), blrOp, rse,
rse->dsqlSelectList->items[0], NullNode::instance());
node->line = line;
node->column = column;
// Finish off by cleaning up contexts.
dsqlScratch->context->clear(base);
@ -11126,7 +11128,10 @@ void SubQueryNode::setParameterName(dsql_par* parameter) const
void SubQueryNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
dsqlScratch->appendUChar(blrOp);
dsqlScratch->putDebugSrcInfo(line, column);
GEN_expr(dsqlScratch, dsqlRse);
GEN_expr(dsqlScratch, value1);
GEN_expr(dsqlScratch, value2);
}
@ -11341,6 +11346,8 @@ ValueExprNode* SubQueryNode::pass2(thread_db* tdbb, CompilerScratch* csb)
csb->csb_invariants.push(&impureOffset);
}
AutoSetCurrentCursorProfileId autoSetCurrentCursorProfileId(csb);
rse->pass2Rse(tdbb, csb);
ValueExprNode::pass2(tdbb, csb);
@ -11351,6 +11358,7 @@ ValueExprNode* SubQueryNode::pass2(thread_db* tdbb, CompilerScratch* csb)
dsc desc;
getDesc(tdbb, csb, &desc);
}
if (blrOp == blr_average && !(nodFlags & FLAG_DECFLOAT))
nodFlags |= FLAG_DOUBLE;

View File

@ -731,40 +731,37 @@ public:
{
}
virtual Kind getKind()
Kind getKind() override
{
return KIND_BOOLEAN;
}
virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch)
BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) override
{
ExprNode::dsqlPass(dsqlScratch);
return this;
}
virtual BoolExprNode* dsqlFieldRemapper(FieldRemapper& visitor)
BoolExprNode* dsqlFieldRemapper(FieldRemapper& visitor) override
{
ExprNode::dsqlFieldRemapper(visitor);
return this;
}
virtual BoolExprNode* pass1(thread_db* tdbb, CompilerScratch* csb)
BoolExprNode* pass1(thread_db* tdbb, CompilerScratch* csb) override
{
ExprNode::pass1(tdbb, csb);
return this;
}
virtual BoolExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
BoolExprNode* pass2(thread_db* tdbb, CompilerScratch* csb) override final;
virtual void pass2Boolean1(thread_db* /*tdbb*/, CompilerScratch* /*csb*/)
virtual void pass2Boolean(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, std::function<void ()> process)
{
process();
}
virtual void pass2Boolean2(thread_db* /*tdbb*/, CompilerScratch* /*csb*/)
{
}
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const = 0;
BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const override = 0;
virtual bool execute(thread_db* tdbb, Request* request) const = 0;
};

View File

@ -1297,6 +1297,8 @@ DeclareCursorNode* DeclareCursorNode::pass1(thread_db* tdbb, CompilerScratch* cs
DeclareCursorNode* DeclareCursorNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
AutoSetCurrentCursorProfileId autoSetCurrentCursorProfileId(csb);
rse->pass2Rse(tdbb, csb);
ExprNode::doPass2(tdbb, csb, rse.getAddress());
@ -5061,6 +5063,8 @@ StmtNode* ForNode::pass1(thread_db* tdbb, CompilerScratch* csb)
StmtNode* ForNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
AutoSetCurrentCursorProfileId autoSetCurrentCursorProfileId(csb);
rse->pass2Rse(tdbb, csb);
doPass2(tdbb, csb, stall.getAddress(), this);

View File

@ -27,6 +27,7 @@
#include "../jrd/tra.h"
#include "../jrd/ids.h"
#include "../jrd/recsrc/Cursor.h"
#include "../dsql/BoolNodes.h"
#include "../jrd/dpm_proto.h"
#include "../jrd/lck_proto.h"
#include "../jrd/met_proto.h"
@ -464,20 +465,20 @@ SINT64 ProfilerManager::startSession(thread_db* tdbb, Nullable<SLONG> flushInter
return currentSession->pluginSession->getId();
}
void ProfilerManager::prepareCursor(thread_db* tdbb, Request* request, const Cursor* cursor)
void ProfilerManager::prepareCursor(thread_db* tdbb, Request* request, const Select* select)
{
auto profileStatement = getStatement(request);
if (!profileStatement)
return;
auto cursorId = cursor->getCursorProfileId();
auto cursorId = select->getCursorProfileId();
if (profileStatement->definedCursors.exist(cursorId))
return;
currentSession->pluginSession->defineCursor(profileStatement->id, cursorId,
cursor->getName().nullStr(), cursor->getLine(), cursor->getColumn());
select->getName().nullStr(), select->getLine(), select->getColumn());
profileStatement->definedCursors.add(cursorId);
}

View File

@ -35,9 +35,9 @@
namespace Jrd {
class Attachment;
class Cursor;
class Request;
class RecordSource;
class Select;
class thread_db;
class ProfilerListener;
@ -123,7 +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 prepareCursor(thread_db* tdbb, Request* request, const Select* select);
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

@ -2754,6 +2754,8 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
RseNode* RseNode::copy(thread_db* tdbb, NodeCopier& copier) const
{
RseNode* newSource = FB_NEW_POOL(*tdbb->getDefaultPool()) RseNode(*tdbb->getDefaultPool());
newSource->line = line;
newSource->column = column;
for (const auto sub : rse_relations)
newSource->rse_relations.add(sub->copy(tdbb, copier));

View File

@ -518,7 +518,7 @@ RecordSource* CMP_post_rse(thread_db* tdbb, CompilerScratch* csb, RseNode* rse)
**************************************/
SET_TDBB(tdbb);
AutoSetRestore<ULONG> autoCurrentCursorProfileId(&csb->csb_currentCursorProfileId, csb->csb_nextCursorProfileId++);
fb_assert(csb->csb_currentCursorProfileId);
const auto rsb = Optimizer::compile(tdbb, csb, rse);

View File

@ -36,6 +36,7 @@
#include "../jrd/Relation.h"
#include "../common/classes/array.h"
#include "../jrd/MetaName.h"
#include "../common/classes/auto.h"
#include "../common/classes/fb_pair.h"
#include "../common/classes/NestConst.h"
@ -670,6 +671,17 @@ inline void CompilerScratch::csb_repeat::deactivate()
}
class AutoSetCurrentCursorProfileId : private Firebird::AutoSetRestore<ULONG>
{
public:
explicit AutoSetCurrentCursorProfileId(CompilerScratch* csb)
: AutoSetRestore(&csb->csb_currentCursorProfileId,
(csb->csb_currentCursorProfileId == 0 ? csb->csb_nextCursorProfileId++ : csb->csb_currentCursorProfileId))
{
}
};
class StatusXcp
{
Firebird::FbLocalStatus status;

View File

@ -81,6 +81,7 @@ static void par_error(BlrReader& blrReader, const Arg::StatusVector& v, bool isS
static PlanNode* par_plan(thread_db*, CompilerScratch*);
static void getBlrVersion(CompilerScratch* csb);
static void parseSubRoutines(thread_db* tdbb, CompilerScratch* csb);
static void setNodeLineColumn(CompilerScratch* csb, DmlNode* node, ULONG blrOffset);
namespace
@ -1319,9 +1320,12 @@ RseNode* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
{
SET_TDBB(tdbb);
const ULONG blrOffset = csb->csb_blr_reader.getOffset() - 1;
int count = (unsigned int) csb->csb_blr_reader.getByte();
RseNode* rse = FB_NEW_POOL(*tdbb->getDefaultPool()) RseNode(*tdbb->getDefaultPool());
setNodeLineColumn(csb, rse, blrOffset);
if (rse_op == blr_lateral_rse)
rse->flags |= RseNode::FLAG_LATERAL;
@ -1452,34 +1456,35 @@ RseNode* PAR_rse(thread_db* tdbb, CompilerScratch* csb)
{
SET_TDBB(tdbb);
const ULONG blrOffset = csb->csb_blr_reader.getOffset();
const SSHORT blrOp = csb->csb_blr_reader.getByte();
RseNode* rseNode = nullptr;
switch (blrOp)
{
case blr_rse:
case blr_lateral_rse:
case blr_rs_stream:
return PAR_rse(tdbb, csb, blrOp);
rseNode = PAR_rse(tdbb, csb, blrOp);
break;
case blr_singular:
{
RseNode* rseNode = PAR_rse(tdbb, csb);
rseNode = PAR_rse(tdbb, csb);
rseNode->flags |= RseNode::FLAG_SINGULAR;
return rseNode;
}
break;
case blr_scrollable:
{
RseNode* rseNode = PAR_rse(tdbb, csb);
rseNode = PAR_rse(tdbb, csb);
rseNode->flags |= RseNode::FLAG_SCROLLABLE;
return rseNode;
}
break;
default:
PAR_syntax_error(csb, "RecordSelExpr");
}
return NULL; // warning
setNodeLineColumn(csb, rseNode, blrOffset);
return rseNode;
}
@ -1600,10 +1605,10 @@ DmlNode* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb)
{
SET_TDBB(tdbb);
const ULONG blr_offset = csb->csb_blr_reader.getOffset();
const SSHORT blr_operator = csb->csb_blr_reader.getByte();
const ULONG blrOffset = csb->csb_blr_reader.getOffset();
const SSHORT blrOperator = csb->csb_blr_reader.getByte();
if (blr_operator < 0 || blr_operator >= FB_NELEM(blr_parsers))
if (blrOperator < 0 || blrOperator >= FB_NELEM(blr_parsers))
{
// NS: This error string is correct, please do not mangle it again and again.
// The whole error message is "BLR syntax error: expected %s at offset %d, encountered %d"
@ -1612,7 +1617,7 @@ DmlNode* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb)
// Dispatch on operator type.
switch (blr_operator)
switch (blrOperator)
{
case blr_rse:
case blr_lateral_rse:
@ -1642,21 +1647,11 @@ DmlNode* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb)
return PAR_parseRecordSource(tdbb, csb);
}
if (!blr_parsers[blr_operator])
if (!blr_parsers[blrOperator])
PAR_syntax_error(csb, "valid BLR code");
DmlNode* node = blr_parsers[blr_operator](tdbb, *tdbb->getDefaultPool(), csb, blr_operator);
FB_SIZE_T pos = 0;
if (node->getKind() == DmlNode::KIND_STATEMENT && csb->csb_dbg_info->blrToSrc.find(blr_offset, pos))
{
MapBlrToSrcItem& i = csb->csb_dbg_info->blrToSrc[pos];
StmtNode* stmt = static_cast<StmtNode*>(node);
stmt->hasLineColumn = true;
stmt->line = i.mbs_src_line;
stmt->column = i.mbs_src_col;
}
DmlNode* node = blr_parsers[blrOperator](tdbb, *tdbb->getDefaultPool(), csb, blrOperator);
setNodeLineColumn(csb, node, blrOffset);
return node;
}
@ -1750,3 +1745,20 @@ static void parseSubRoutines(thread_db* tdbb, CompilerScratch* csb)
PAR_blr(tdbb, nullptr, node->blrStart, node->blrLength, nullptr, &node->subCsb, nullptr, false, 0);
}
}
// Set node line/column for a given blr offset.
static void setNodeLineColumn(CompilerScratch* csb, DmlNode* node, ULONG blrOffset)
{
FB_SIZE_T pos;
if (node && csb->csb_dbg_info->blrToSrc.find(blrOffset, pos))
{
MapBlrToSrcItem& i = csb->csb_dbg_info->blrToSrc[pos];
node->line = i.mbs_src_line;
node->column = i.mbs_src_col;
if (node->getKind() == DmlNode::KIND_STATEMENT)
static_cast<StmtNode*>(node)->hasLineColumn = true;
}
}

View File

@ -52,6 +52,16 @@ namespace
// Select implementation
// ---------------------
Select::Select(const RecordSource* source, const RseNode* rse, ULONG line, ULONG column, const MetaName& cursorName)
: m_top(source),
m_rse(rse),
m_cursorProfileId(source->getCursorProfileId()),
m_cursorName(cursorName),
m_line(line),
m_column(column)
{
}
void Select::initializeInvariants(Request* request) const
{
// Initialize dependent invariants, if any
@ -109,18 +119,32 @@ void Select::printPlan(thread_db* tdbb, string& plan, bool detailed) const
m_top->print(tdbb, plan, detailed, 0, true);
}
void Select::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);
}
// ---------------------
// SubQuery implementation
// ---------------------
SubQuery::SubQuery(const RecordSource* rsb, const RseNode* rse)
: Select(rsb, rse)
: Select(rsb, rse, rse->line, rse->column)
{
fb_assert(m_top);
}
void SubQuery::open(thread_db* tdbb) const
{
prepareProfiler(tdbb, tdbb->getRequest());
initializeInvariants(tdbb->getRequest());
m_top->open(tdbb);
}
@ -135,6 +159,8 @@ bool SubQuery::fetch(thread_db* tdbb) const
if (!validate(tdbb))
return false;
prepareProfiler(tdbb, tdbb->getRequest());
return m_top->getRecord(tdbb);
}
@ -146,7 +172,6 @@ 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);
@ -409,18 +434,6 @@ void Cursor::checkState(Request* request) const
{
status_exception::raise(
Arg::Gds(isc_cursor_not_positioned) <<
Arg::Str(m_cursorName));
getName());
}
}
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

@ -43,20 +43,27 @@ namespace Jrd
INVARIANT = 2
};
Select(const RecordSource* source, const RseNode* rse,
ULONG line = 0, ULONG column = 0, const MetaName& cursorName = "")
: m_top(source), m_rse(rse), m_cursorName(cursorName),
m_line(line), m_column(column)
{}
Select(const RecordSource* source, const RseNode* rse, ULONG line = 0, ULONG column = 0,
const MetaName& cursorName = {});
virtual ~Select()
{}
ULONG getCursorProfileId() const
{
return m_cursorProfileId;
}
const RecordSource* getAccessPath() const
{
return m_top;
}
const MetaName& getName() const
{
return m_cursorName;
}
ULONG getLine() const
{
return m_line;
@ -73,12 +80,16 @@ namespace Jrd
virtual void open(thread_db* tdbb) const = 0;
virtual void close(thread_db* tdbb) const = 0;
protected:
void prepareProfiler(thread_db* tdbb, Request* request) const;
protected:
const RecordSource* const m_top;
const RseNode* const m_rse;
MetaName m_cursorName; // optional name for explicit PSQL cursors
private:
const ULONG m_cursorProfileId;
MetaName m_cursorName; // optional name for explicit PSQL cursors
ULONG m_line = 0;
ULONG m_column = 0;
};
@ -125,26 +136,12 @@ namespace Jrd
void checkState(Request* request) const;
ULONG getCursorProfileId() const
{
return m_cursorProfileId;
}
bool isUpdateCounters() const
{
return m_updateCounters;
}
const MetaName& getName() const
{
return m_cursorName;
}
private:
void prepareProfiler(thread_db* tdbb, Request* request) const;
private:
const ULONG m_cursorProfileId;
ULONG m_impure;
const bool m_updateCounters;
};