Skip to content

Commit

Permalink
Merge pull request #7441 from FirebirdSQL/v5-pretty-explained-plan
Browse files Browse the repository at this point in the history
More cursor-related details in the plan output
  • Loading branch information
dyemanov authored Jan 10, 2023
2 parents 6c431cb + 1c2470c commit a6ce0ec
Show file tree
Hide file tree
Showing 15 changed files with 219 additions and 99 deletions.
9 changes: 5 additions & 4 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 @@ -1580,7 +1582,7 @@ BoolExprNode* RseBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)

void RseBoolNode::pass2Boolean1(thread_db* tdbb, CompilerScratch* csb)
{
if (!(rse->flags & RseNode::FLAG_VARIANT))
if (rse->isInvariant())
{
nodFlags |= FLAG_INVARIANT;
csb->csb_invariants.push(&impureOffset);
Expand All @@ -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
9 changes: 5 additions & 4 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 @@ -11319,7 +11321,7 @@ ValueExprNode* SubQueryNode::pass2(thread_db* tdbb, CompilerScratch* csb)
if (!rse)
ERR_post(Arg::Gds(isc_wish_list));

if (!(rse->flags & RseNode::FLAG_VARIANT))
if (rse->isInvariant())
{
nodFlags |= FLAG_INVARIANT;
csb->csb_invariants.push(&impureOffset);
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
20 changes: 12 additions & 8 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,15 +5068,16 @@ 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.

if (rse->flags & RseNode::FLAG_WRITELOCK)
csb->csb_fors.add(cursor);

if (rse->hasWriteLock())
withLock = true;

if (marks & MARK_MERGE)
Expand Down
4 changes: 2 additions & 2 deletions src/dsql/gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,10 +547,10 @@ void GEN_rse(DsqlCompilerScratch* dsqlScratch, RseNode* rse)
for (const NestConst<RecordSourceNode>* const end = rse->dsqlStreams->items.end(); ptr != end; ++ptr)
GEN_expr(dsqlScratch, *ptr);

if (rse->flags & RseNode::FLAG_WRITELOCK)
if (rse->hasWriteLock())
dsqlScratch->appendUChar(blr_writelock);

if (rse->flags & RseNode::FLAG_SKIP_LOCKED)
if (rse->hasSkipLocked())
dsqlScratch->appendUChar(blr_skip_locked);

if (rse->dsqlFirst)
Expand Down
4 changes: 2 additions & 2 deletions src/dsql/pass1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2177,13 +2177,13 @@ static RseNode* pass1_rse_impl(DsqlCompilerScratch* dsqlScratch, RecordSourceNod
parentRse->dsqlStreams = streamList = FB_NEW_POOL(pool) RecSourceListNode(pool, 1);
streamList->items[0] = window;

if (rse->flags & RseNode::FLAG_WRITELOCK)
if (rse->hasWriteLock())
{
parentRse->flags |= RseNode::FLAG_WRITELOCK;
rse->flags &= ~RseNode::FLAG_WRITELOCK;
}

if (rse->flags & RseNode::FLAG_SKIP_LOCKED)
if (rse->hasSkipLocked())
{
parentRse->flags |= RseNode::FLAG_SKIP_LOCKED;
rse->flags &= ~RseNode::FLAG_SKIP_LOCKED;
Expand Down
8 changes: 2 additions & 6 deletions src/jrd/RecordSourceNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2951,9 +2951,7 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
// where we are just trying to inner join more than 2 streams. If possible,
// try to flatten the tree out before we go any further.

const auto isLateral = (this->flags & RseNode::FLAG_LATERAL) != 0;

if (!isLateral &&
if (!isLateral() &&
rse->rse_jointype == blr_inner &&
rse_jointype == blr_inner &&
!rse_sorted && !rse_projection &&
Expand Down Expand Up @@ -3046,8 +3044,6 @@ RecordSource* RseNode::compile(thread_db* tdbb, Optimizer* opt, bool innerSubStr

BoolExprNodeStack conjunctStack;

const auto isLateral = (this->flags & RseNode::FLAG_LATERAL) != 0;

// pass RseNode boolean only to inner substreams because join condition
// should never exclude records from outer substreams
if (opt->isInnerJoin() || (opt->isLeftJoin() && innerSubStream))
Expand All @@ -3060,7 +3056,7 @@ RecordSource* RseNode::compile(thread_db* tdbb, Optimizer* opt, bool innerSubStr

StreamStateHolder stateHolder(csb, opt->getOuterStreams());

if (opt->isLeftJoin() || isLateral)
if (opt->isLeftJoin() || isLateral())
{
stateHolder.activate();

Expand Down
55 changes: 47 additions & 8 deletions src/jrd/RecordSourceNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -717,14 +717,53 @@ 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
};

bool isInvariant() const
{
return (flags & FLAG_VARIANT) == 0;
}

bool isSingular() const
{
return (flags & FLAG_SINGULAR) != 0;
}

bool isScrollable() const
{
return (flags & FLAG_SCROLLABLE) != 0;
}

bool isLateral() const
{
return (flags & FLAG_LATERAL) != 0;
}

bool isSubQuery() const
{
return (flags & FLAG_SUB_QUERY) != 0;
}

bool hasWriteLock() const
{
return (flags & FLAG_WRITELOCK) != 0;
}

bool hasSkipLocked() const
{
return (flags & FLAG_SKIP_LOCKED) != 0;
}

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
8 changes: 4 additions & 4 deletions src/jrd/optimizer/Optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
if (rse->rse_skip)
rsb = FB_NEW_POOL(getPool()) SkipRowsStream(csb, rsb, rse->rse_skip);

if (rse->flags & RseNode::FLAG_WRITELOCK)
if (rse->hasWriteLock())
{
for (const auto compileStream : compileStreams)
{
Expand All @@ -1048,16 +1048,16 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
SCL_update, obj_relations, tail->csb_relation->rel_name);
}

rsb = FB_NEW_POOL(getPool()) LockedStream(csb, rsb, (rse->flags & RseNode::FLAG_SKIP_LOCKED));
rsb = FB_NEW_POOL(getPool()) LockedStream(csb, rsb, rse->hasSkipLocked());
}

if (rse->rse_first)
rsb = FB_NEW_POOL(getPool()) FirstRowsStream(csb, rsb, rse->rse_first);

if (rse->flags & RseNode::FLAG_SINGULAR)
if (rse->isSingular())
rsb = FB_NEW_POOL(getPool()) SingularStream(csb, rsb);

if (rse->flags & RseNode::FLAG_SCROLLABLE)
if (rse->isScrollable())
rsb = FB_NEW_POOL(getPool()) BufferedStream(csb, rsb);

return rsb;
Expand Down
2 changes: 1 addition & 1 deletion src/jrd/par.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1404,7 +1404,7 @@ RseNode* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
break;

case blr_skip_locked:
if (!(rse->flags & RseNode::FLAG_WRITELOCK))
if (!rse->hasWriteLock())
{
PAR_error(csb,
Arg::Gds(isc_random) <<
Expand Down
Loading

0 comments on commit a6ce0ec

Please sign in to comment.