Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More cursor-related details in the plan output #7441

Merged
merged 2 commits into from
Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/dsql/BoolNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1444,6 +1444,8 @@ DmlNode* RseBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
RseBoolNode* node = FB_NEW_POOL(pool) RseBoolNode(pool, blrOp);
node->rse = PAR_rse(tdbb, csb);

node->rse->flags |= RseNode::FLAG_SUB_QUERY;

if (blrOp == blr_any || blrOp == blr_exists) // maybe for blr_unique as well?
node->rse->flags |= RseNode::FLAG_OPT_FIRST_ROWS;

Expand Down Expand Up @@ -1607,9 +1609,8 @@ void RseBoolNode::pass2Boolean2(thread_db* tdbb, CompilerScratch* csb)
rsb->setAnyBoolean(rse->rse_boolean, ansiAny, ansiNot);
}

csb->csb_fors.add(rsb);

subQuery = FB_NEW_POOL(*tdbb->getDefaultPool()) SubQuery(rsb, rse->rse_invariants);
subQuery = FB_NEW_POOL(*tdbb->getDefaultPool()) SubQuery(rsb, rse);
csb->csb_fors.add(subQuery);
}

bool RseBoolNode::execute(thread_db* tdbb, Request* request) const
Expand Down
7 changes: 4 additions & 3 deletions src/dsql/ExprNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11036,6 +11036,8 @@ DmlNode* SubQueryNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*

node->rse = PAR_rse(tdbb, csb);

node->rse->flags |= RseNode::FLAG_SUB_QUERY;

if (blrOp != blr_count)
node->value1 = PAR_parse_value(tdbb, csb);

Expand Down Expand Up @@ -11356,9 +11358,8 @@ ValueExprNode* SubQueryNode::pass2(thread_db* tdbb, CompilerScratch* csb)
// Finish up processing of record selection expressions.

RecordSource* const rsb = CMP_post_rse(tdbb, csb, rse);
csb->csb_fors.add(rsb);

subQuery = FB_NEW_POOL(*tdbb->getDefaultPool()) SubQuery(rsb, rse->rse_invariants);
subQuery = FB_NEW_POOL(*tdbb->getDefaultPool()) SubQuery(rsb, rse);
csb->csb_fors.add(subQuery);

return this;
}
Expand Down
18 changes: 11 additions & 7 deletions src/dsql/StmtNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1302,14 +1302,17 @@ DeclareCursorNode* DeclareCursorNode::pass2(thread_db* tdbb, CompilerScratch* cs
ExprNode::doPass2(tdbb, csb, rse.getAddress());
ExprNode::doPass2(tdbb, csb, refs.getAddress());

MetaName cursorName;
csb->csb_dbg_info->curIndexToName.get(cursorNumber, cursorName);

// Finish up processing of record selection expressions.

RecordSource* const rsb = CMP_post_rse(tdbb, csb, rse.getObject());
csb->csb_fors.add(rsb);

cursor = FB_NEW_POOL(*tdbb->getDefaultPool()) Cursor(csb, rsb, rse->rse_invariants,
(rse->flags & RseNode::FLAG_SCROLLABLE), true);
csb->csb_dbg_info->curIndexToName.get(cursorNumber, cursor->name);
cursor = FB_NEW_POOL(*tdbb->getDefaultPool())
Cursor(csb, rsb, rse, true, line, column, cursorName);

csb->csb_fors.add(cursor);

StreamList cursorStreams;
cursor->getAccessPath()->findUsedStreams(cursorStreams);
Expand Down Expand Up @@ -5065,14 +5068,15 @@ StmtNode* ForNode::pass2(thread_db* tdbb, CompilerScratch* csb)
// Finish up processing of record selection expressions.

RecordSource* const rsb = CMP_post_rse(tdbb, csb, rse.getObject());
csb->csb_fors.add(rsb);

cursor = FB_NEW_POOL(*tdbb->getDefaultPool()) Cursor(csb, rsb, rse->rse_invariants,
(rse->flags & RseNode::FLAG_SCROLLABLE), !(marks & MARK_AVOID_COUNTERS));
cursor = FB_NEW_POOL(*tdbb->getDefaultPool())
Cursor(csb, rsb, rse, !(marks & MARK_AVOID_COUNTERS), line, column);
// ASF: We cannot define the name of the cursor here, but this is not a problem,
// as implicit cursors are always positioned in a valid record, and the name is
// only used to raise isc_cursor_not_positioned.

csb->csb_fors.add(cursor);

if (rse->flags & RseNode::FLAG_WRITELOCK)
withLock = true;

Expand Down
20 changes: 12 additions & 8 deletions src/jrd/RecordSourceNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -717,14 +717,18 @@ class WindowSourceNode final : public TypedNode<RecordSourceNode, RecordSourceNo
class RseNode final : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_RSE>
{
public:
static const USHORT FLAG_VARIANT = 0x01; // variant (not invariant?)
static const USHORT FLAG_SINGULAR = 0x02; // singleton select
static const USHORT FLAG_WRITELOCK = 0x04; // locked for write
static const USHORT FLAG_SCROLLABLE = 0x08; // scrollable cursor
static const USHORT FLAG_DSQL_COMPARATIVE = 0x10; // transformed from DSQL ComparativeBoolNode
static const USHORT FLAG_OPT_FIRST_ROWS = 0x20; // optimize retrieval for first rows
static const USHORT FLAG_LATERAL = 0x40; // lateral derived table
static const USHORT FLAG_SKIP_LOCKED = 0x80; // skip locked
enum : USHORT
{
FLAG_VARIANT = 0x01, // variant (not invariant?)
FLAG_SINGULAR = 0x02, // singleton select
FLAG_WRITELOCK = 0x04, // locked for write
FLAG_SCROLLABLE = 0x08, // scrollable cursor
FLAG_DSQL_COMPARATIVE = 0x10, // transformed from DSQL ComparativeBoolNode
FLAG_OPT_FIRST_ROWS = 0x20, // optimize retrieval for first rows
FLAG_LATERAL = 0x40, // lateral derived table
FLAG_SKIP_LOCKED = 0x80, // skip locked
FLAG_SUB_QUERY = 0x100 // sub-query
};

explicit RseNode(MemoryPool& pool)
: TypedNode<RecordSourceNode, RecordSourceNode::TYPE_RSE>(pool),
Expand Down
8 changes: 3 additions & 5 deletions src/jrd/Statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "../jrd/met_proto.h"
#include "../jrd/scl_proto.h"
#include "../jrd/Collation.h"
#include "../jrd/recsrc/Cursor.h"

using namespace Firebird;
using namespace Jrd;
Expand Down Expand Up @@ -723,11 +724,8 @@ string Statement::getPlan(thread_db* tdbb, bool detailed) const
{
string plan;

for (const auto rsb : fors)
{
plan += detailed ? "\nSelect Expression" : "\nPLAN ";
rsb->print(tdbb, plan, detailed, 0, true);
}
for (const auto select : fors)
select->printPlan(tdbb, plan, detailed);

return plan;
}
Expand Down
2 changes: 1 addition & 1 deletion src/jrd/Statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class Statement : public pool_alloc<type_req>
Statement* parentStatement; // Sub routine's parent statement
Firebird::Array<Statement*> subStatements; // Array of subroutines' statements
const StmtNode* topNode; // top of execution tree
Firebird::Array<const RecordSource*> fors; // record sources
Firebird::Array<const Select*> fors; // select expressions
Firebird::Array<const DeclareLocalTableNode*> localTables; // local tables
Firebird::Array<ULONG*> invariants; // pointer to nodes invariant offsets
Firebird::RefStrPtr sqlText; // SQL text (encoded in the metadata charset)
Expand Down
15 changes: 7 additions & 8 deletions src/jrd/exe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -947,25 +947,24 @@ void EXE_unwind(thread_db* tdbb, Request* request)
{
const Statement* statement = request->getStatement();

if (statement->fors.getCount() || request->req_ext_resultset || request->req_ext_stmt)
if (statement->fors.hasData() || request->req_ext_resultset || request->req_ext_stmt)
{
Jrd::ContextPoolHolder context(tdbb, request->req_pool);
Request* old_request = tdbb->getRequest();
jrd_tra* old_transaction = tdbb->getTransaction();
try {

try
{
tdbb->setRequest(request);
tdbb->setTransaction(request->req_transaction);

for (const RecordSource* const* ptr = statement->fors.begin();
ptr != statement->fors.end(); ++ptr)
{
(*ptr)->close(tdbb);
}
for (const auto select : statement->fors)
select->close(tdbb);

if (request->req_ext_resultset)
{
delete request->req_ext_resultset;
request->req_ext_resultset = NULL;
request->req_ext_resultset = nullptr;
}

while (request->req_ext_stmt)
Expand Down
3 changes: 2 additions & 1 deletion src/jrd/exe.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class DeclareVariableNode;
class MessageNode;
class PlanNode;
class RecordSource;
class Select;

// Direction for each column in sort order
enum SortDirection { ORDER_ANY, ORDER_ASC, ORDER_DESC };
Expand Down Expand Up @@ -551,7 +552,7 @@ class CompilerScratch : public pool_alloc<type_csb>
vec<DeclareVariableNode*>* csb_variables; // Vector of variables, if any
ResourceList csb_resources; // Resources (relations and indexes)
Firebird::Array<Dependency> csb_dependencies; // objects that this statement depends upon
Firebird::Array<const RecordSource*> csb_fors; // record sources
Firebird::Array<const Select*> csb_fors; // select expressions
Firebird::Array<const DeclareLocalTableNode*> csb_localTables; // local tables
Firebird::Array<ULONG*> csb_invariants; // stack of pointer to nodes invariant offsets
Firebird::Array<ExprNode*> csb_current_nodes; // RseNode's and other invariant
Expand Down
93 changes: 71 additions & 22 deletions src/jrd/recsrc/Cursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,34 +46,82 @@ namespace

return true;
}
}

// ---------------------
// Select implementation
// ---------------------

// Initialize dependent invariants
void initializeInvariants(Request* request, const VarInvariantArray* invariants)
void Select::initializeInvariants(Request* request) const
{
// Initialize dependent invariants, if any

if (m_rse->rse_invariants)
{
if (invariants)
for (const auto offset : *m_rse->rse_invariants)
{
for (const ULONG* iter = invariants->begin(); iter < invariants->end(); ++iter)
{
impure_value* const invariantImpure = request->getImpure<impure_value>(*iter);
invariantImpure->vlu_flags = 0;
}
const auto invariantImpure = request->getImpure<impure_value>(offset);
invariantImpure->vlu_flags = 0;
}
}
}

void Select::printPlan(thread_db* tdbb, string& plan, bool detailed) const
{
if (detailed)
{
if (m_rse->flags & RseNode::FLAG_SUB_QUERY)
{
plan += "\nSub-query";

if (!(m_rse->flags & RseNode::FLAG_VARIANT))
plan += " (invariant)";
}
else if (m_cursorName.hasData())
{
plan += "\nCursor \"" + string(m_cursorName) + "\"";

if (m_rse->flags & RseNode::FLAG_SCROLLABLE)
plan += " (scrollable)";
}
else
plan += "\nSelect Expression";

if (m_line || m_column)
{
string pos;
pos.printf(" (line %u, column %u)", m_line, m_column);
plan += pos;
}
}
else
{
if (m_line || m_column)
{
string pos;
pos.printf("\n-- line %u, column %u", m_line, m_column);
plan += pos;
}

plan += "\nPLAN ";
}

m_top->print(tdbb, plan, detailed, 0, true);
}

// ---------------------
// SubQuery implementation
// ---------------------

SubQuery::SubQuery(const RecordSource* rsb, const VarInvariantArray* invariants)
: m_top(rsb), m_invariants(invariants)
SubQuery::SubQuery(const RecordSource* rsb, const RseNode* rse)
: Select(rsb, rse)
{
fb_assert(m_top);
}

void SubQuery::open(thread_db* tdbb) const
{
initializeInvariants(tdbb->getRequest(), m_invariants);
initializeInvariants(tdbb->getRequest());
m_top->open(tdbb);
}

Expand All @@ -95,9 +143,10 @@ bool SubQuery::fetch(thread_db* tdbb) const
// Cursor implementation
// ---------------------

Cursor::Cursor(CompilerScratch* csb, const RecordSource* rsb,
const VarInvariantArray* invariants, bool scrollable, bool updateCounters)
: m_top(rsb), m_invariants(invariants), m_scrollable(scrollable), m_updateCounters(updateCounters)
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_updateCounters(updateCounters)
{
fb_assert(m_top);

Expand All @@ -112,7 +161,7 @@ void Cursor::open(thread_db* tdbb) const
impure->irsb_active = true;
impure->irsb_state = BOS;

initializeInvariants(request, m_invariants);
initializeInvariants(request);
m_top->open(tdbb);
}

Expand All @@ -130,7 +179,7 @@ void Cursor::close(thread_db* tdbb) const

bool Cursor::fetchNext(thread_db* tdbb) const
{
if (m_scrollable)
if (m_rse->flags & RseNode::FLAG_SCROLLABLE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An inline isScrollable() method would make code more clear.

return fetchRelative(tdbb, 1);

if (!validate(tdbb))
Expand Down Expand Up @@ -166,7 +215,7 @@ bool Cursor::fetchNext(thread_db* tdbb) const

bool Cursor::fetchPrior(thread_db* tdbb) const
{
if (!m_scrollable)
if (!(m_rse->flags & RseNode::FLAG_SCROLLABLE))
{
// error: invalid fetch direction
status_exception::raise(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("PRIOR"));
Expand All @@ -177,7 +226,7 @@ bool Cursor::fetchPrior(thread_db* tdbb) const

bool Cursor::fetchFirst(thread_db* tdbb) const
{
if (!m_scrollable)
if (!(m_rse->flags & RseNode::FLAG_SCROLLABLE))
{
// error: invalid fetch direction
status_exception::raise(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("FIRST"));
Expand All @@ -188,7 +237,7 @@ bool Cursor::fetchFirst(thread_db* tdbb) const

bool Cursor::fetchLast(thread_db* tdbb) const
{
if (!m_scrollable)
if (!(m_rse->flags & RseNode::FLAG_SCROLLABLE))
{
// error: invalid fetch direction
status_exception::raise(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("LAST"));
Expand All @@ -199,7 +248,7 @@ bool Cursor::fetchLast(thread_db* tdbb) const

bool Cursor::fetchAbsolute(thread_db* tdbb, SINT64 offset) const
{
if (!m_scrollable)
if (!(m_rse->flags & RseNode::FLAG_SCROLLABLE))
{
// error: invalid fetch direction
status_exception::raise(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("ABSOLUTE"));
Expand Down Expand Up @@ -260,7 +309,7 @@ bool Cursor::fetchAbsolute(thread_db* tdbb, SINT64 offset) const

bool Cursor::fetchRelative(thread_db* tdbb, SINT64 offset) const
{
if (!m_scrollable)
if (!(m_rse->flags & RseNode::FLAG_SCROLLABLE))
{
// error: invalid fetch direction
status_exception::raise(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("RELATIVE"));
Expand Down Expand Up @@ -350,6 +399,6 @@ void Cursor::checkState(Request* request) const
{
status_exception::raise(
Arg::Gds(isc_cursor_not_positioned) <<
Arg::Str(name));
Arg::Str(m_cursorName));
}
}
Loading