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

Refactor: SelectNode (DSQL) and blr_select (JRD) has no relation with each other.

This commit is contained in:
Adriano dos Santos Fernandes 2023-09-18 20:27:13 -03:00
parent 8693554daf
commit 0278a9bfdb
6 changed files with 116 additions and 84 deletions

View File

@ -1445,6 +1445,7 @@ public:
TYPE_RETURN,
TYPE_SAVEPOINT,
TYPE_SELECT,
TYPE_SELECT_MESSAGE,
TYPE_SESSION_MANAGEMENT_WRAPPER,
TYPE_SET_GENERATOR,
TYPE_STALL,

View File

@ -1236,7 +1236,7 @@ DeclareCursorNode* DeclareCursorNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
SelectExprNode* dt = FB_NEW_POOL(dsqlScratch->getPool()) SelectExprNode(dsqlScratch->getPool());
dt->dsqlFlags = RecordSourceNode::DFLAG_DERIVED | RecordSourceNode::DFLAG_CURSOR;
dt->querySpec = dsqlSelect->dsqlExpr;
dt->querySpec = dsqlSelect->selectExpr;
dt->alias = dsqlName.c_str();
rse = PASS1_derived_table(dsqlScratch, dt, NULL, dsqlSelect);
@ -4933,7 +4933,7 @@ ForNode* ForNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
SelectExprNode* dt = FB_NEW_POOL(dsqlScratch->getPool()) SelectExprNode(dsqlScratch->getPool());
dt->dsqlFlags = RecordSourceNode::DFLAG_DERIVED | RecordSourceNode::DFLAG_CURSOR;
dt->querySpec = dsqlSelect->dsqlExpr;
dt->querySpec = dsqlSelect->selectExpr;
dt->alias = dsqlCursor->dsqlName.c_str();
node->rse = PASS1_derived_table(dsqlScratch, dt, NULL, dsqlSelect);
@ -4943,7 +4943,7 @@ ForNode* ForNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
dsqlScratch->cursors.push(dsqlCursor);
}
else
node->rse = dsqlSelect->dsqlPass(dsqlScratch)->dsqlRse;
node->rse = dsqlSelect->dsqlPass(dsqlScratch)->rse;
node->dsqlInto = dsqlPassArray(dsqlScratch, dsqlInto);
@ -5573,10 +5573,10 @@ StmtNode* MergeNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
selectExpr->dsqlFlags |= RecordSourceNode::DFLAG_SINGLETON;
const auto dsqlSelect = FB_NEW_POOL(pool) SelectNode(pool);
dsqlSelect->dsqlExpr = selectExpr;
dsqlSelect->selectExpr = selectExpr;
const auto mergeNode = FB_NEW_POOL(pool) MergeNode(pool);
mergeNode->rse = dsqlSelect->dsqlPass(dsqlScratch)->dsqlRse;
mergeNode->rse = dsqlSelect->dsqlPass(dsqlScratch)->rse;
// Get the already processed relations.
const auto processedRse = nodeAs<RseNode>(mergeNode->rse->dsqlStreams->items[0]);
@ -8189,35 +8189,17 @@ const StmtNode* StoreNode::store(thread_db* tdbb, Request* request, WhichTrigger
//--------------------
static RegisterNode<SelectNode> regSelectNode({blr_select});
DmlNode* SelectNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/)
{
SelectNode* node = FB_NEW_POOL(pool) SelectNode(pool);
while (csb->csb_blr_reader.peekByte() != blr_end)
{
if (csb->csb_blr_reader.peekByte() != blr_receive)
PAR_syntax_error(csb, "blr_receive");
node->statements.add(PAR_parse_stmt(tdbb, csb));
}
csb->csb_blr_reader.getByte(); // skip blr_end
return node;
}
SelectNode* SelectNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
SelectNode* node = FB_NEW_POOL(dsqlScratch->getPool()) SelectNode(dsqlScratch->getPool());
node->dsqlForUpdate = dsqlForUpdate;
node->dsqlOptimizeForFirstRows = dsqlOptimizeForFirstRows;
node->forUpdate = forUpdate;
node->optimizeForFirstRows = optimizeForFirstRows;
const DsqlContextStack::iterator base(*dsqlScratch->context);
node->dsqlRse = PASS1_rse(dsqlScratch, dsqlExpr, this);
node->rse = PASS1_rse(dsqlScratch, selectExpr, this);
dsqlScratch->context->clear(base);
if (dsqlForUpdate)
if (forUpdate)
{
dsqlScratch->getDsqlStatement()->setType(DsqlStatement::TYPE_SELECT_UPD);
dsqlScratch->getDsqlStatement()->addFlags(DsqlStatement::FLAG_NO_BATCH);
@ -8228,9 +8210,7 @@ SelectNode* SelectNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
// stored procedure occurs in the select list. In these cases all of stored procedure is
// executed under savepoint for open cursor.
RseNode* rseNode = nodeAs<RseNode>(node->dsqlRse);
if (rseNode->dsqlOrder || rseNode->dsqlDistinct)
if (node->rse->dsqlOrder || node->rse->dsqlDistinct)
{
dsqlScratch->getDsqlStatement()->setFlags(
dsqlScratch->getDsqlStatement()->getFlags() & ~DsqlStatement::FLAG_NO_BATCH);
@ -8244,11 +8224,12 @@ string SelectNode::internalPrint(NodePrinter& printer) const
{
StmtNode::internalPrint(printer);
NODE_PRINT(printer, dsqlExpr);
NODE_PRINT(printer, dsqlForUpdate);
NODE_PRINT(printer, dsqlWithLock);
NODE_PRINT(printer, dsqlRse);
NODE_PRINT(printer, statements);
NODE_PRINT(printer, selectExpr);
NODE_PRINT(printer, optimizeForFirstRows);
NODE_PRINT(printer, forUpdate);
NODE_PRINT(printer, withLock);
NODE_PRINT(printer, skipLocked);
NODE_PRINT(printer, rse);
return "SelectNode";
}
@ -8256,10 +8237,9 @@ string SelectNode::internalPrint(NodePrinter& printer) const
// Generate BLR for a SELECT statement.
void SelectNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
RseNode* const rse = nodeAs<RseNode>(dsqlRse);
fb_assert(rse);
DsqlStatement* const statement = dsqlScratch->getDsqlStatement();
const auto statement = dsqlScratch->getDsqlStatement();
// Set up parameter for things in the select list.
ValueListNode* list = rse->dsqlSelectList;
@ -8284,7 +8264,7 @@ void SelectNode::genBlr(DsqlCompilerScratch* dsqlScratch)
GenericMap<NonPooled<dsql_par*, dsql_ctx*> > paramContexts(*getDefaultMemoryPool());
dsql_ctx* context;
if (dsqlForUpdate && !rse->dsqlDistinct)
if (forUpdate && !rse->dsqlDistinct)
{
RecSourceListNode* streamList = rse->dsqlStreams;
@ -8345,7 +8325,7 @@ void SelectNode::genBlr(DsqlCompilerScratch* dsqlScratch)
dsqlScratch->appendUChar(blr_for);
dsqlScratch->appendUChar(blr_stall);
GEN_rse(dsqlScratch, dsqlRse);
GEN_rse(dsqlScratch, rse);
dsqlScratch->appendUChar(blr_send);
dsqlScratch->appendUChar(message->msg_number);
@ -8401,26 +8381,57 @@ void SelectNode::genBlr(DsqlCompilerScratch* dsqlScratch)
GEN_parameter(dsqlScratch, statement->getEof());
}
SelectNode* SelectNode::pass1(thread_db* tdbb, CompilerScratch* csb)
//--------------------
static RegisterNode<SelectMessageNode> regSelectMessageNode({blr_select});
DmlNode* SelectMessageNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/)
{
for (NestConst<StmtNode>* i = statements.begin(); i != statements.end(); ++i)
doPass1(tdbb, csb, i->getAddress());
const auto node = FB_NEW_POOL(pool) SelectMessageNode(pool);
while (csb->csb_blr_reader.peekByte() != blr_end)
{
if (csb->csb_blr_reader.peekByte() != blr_receive)
PAR_syntax_error(csb, "blr_receive");
node->statements.add(PAR_parse_stmt(tdbb, csb));
}
csb->csb_blr_reader.getByte(); // skip blr_end
return node;
}
string SelectMessageNode::internalPrint(NodePrinter& printer) const
{
StmtNode::internalPrint(printer);
NODE_PRINT(printer, statements);
return "SelectMessageNode";
}
SelectMessageNode* SelectMessageNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
for (auto statement : statements)
doPass1(tdbb, csb, statement.getAddress());
return this;
}
SelectNode* SelectNode::pass2(thread_db* tdbb, CompilerScratch* csb)
SelectMessageNode* SelectMessageNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
for (NestConst<StmtNode>* i = statements.begin(); i != statements.end(); ++i)
doPass2(tdbb, csb, i->getAddress(), this);
for (auto statement : statements)
doPass2(tdbb, csb, statement.getAddress(), this);
return this;
}
// Execute a SELECT statement. This is more than a little obscure.
// Execute a blr_select statement. This is more than a little obscure.
// We first set up the SELECT statement as the "message" and stall on receive (waiting for user send).
// EXE_send will then loop thru the sub-statements of select looking for the appropriate RECEIVE
// statement. When (or if) it finds it, it will set it up the next statement to be executed.
// The RECEIVE, then, will be entered with the operation "req_proceed".
const StmtNode* SelectNode::execute(thread_db* /*tdbb*/, Request* request, ExeState* /*exeState*/) const
const StmtNode* SelectMessageNode::execute(thread_db* /*tdbb*/, Request* request, ExeState* /*exeState*/) const
{
switch (request->req_operation)
{

View File

@ -1318,11 +1318,34 @@ public:
};
class SelectNode final : public TypedNode<StmtNode, StmtNode::TYPE_SELECT>
class SelectNode final : public TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_SELECT>
{
public:
explicit SelectNode(MemoryPool& pool)
: TypedNode<StmtNode, StmtNode::TYPE_SELECT>(pool),
: TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_SELECT>(pool)
{
}
public:
Firebird::string internalPrint(NodePrinter& printer) const override;
SelectNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) override;
void genBlr(DsqlCompilerScratch* dsqlScratch) override;
public:
NestConst<SelectExprNode> selectExpr;
NestConst<RseNode> rse;
TriState optimizeForFirstRows;
bool forUpdate = false;
bool withLock = false;
bool skipLocked = false;
};
class SelectMessageNode final : public TypedNode<StmtNode, StmtNode::TYPE_SELECT_MESSAGE>
{
public:
explicit SelectMessageNode(MemoryPool& pool)
: TypedNode<StmtNode, StmtNode::TYPE_SELECT_MESSAGE>(pool),
statements(pool)
{
}
@ -1330,21 +1353,25 @@ public:
public:
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual SelectNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual SelectNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual SelectNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual const StmtNode* execute(thread_db* tdbb, Request* request, ExeState* exeState) const;
Firebird::string internalPrint(NodePrinter& printer) const override;
SelectMessageNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) override
{
fb_assert(false);
return nullptr;
}
void genBlr(DsqlCompilerScratch* dsqlScratch) override
{
fb_assert(false);
}
SelectMessageNode* pass1(thread_db* tdbb, CompilerScratch* csb) override;
SelectMessageNode* pass2(thread_db* tdbb, CompilerScratch* csb) override;
const StmtNode* execute(thread_db* tdbb, Request* request, ExeState* exeState) const override;
public:
NestConst<SelectExprNode> dsqlExpr;
NestConst<RseNode> dsqlRse;
Firebird::Array<NestConst<StmtNode>> statements;
bool dsqlForUpdate = false;
bool dsqlWithLock = false;
bool dsqlSkipLocked = false;
TriState dsqlOptimizeForFirstRows;
};

View File

@ -5801,11 +5801,11 @@ select
: select_expr for_update_clause lock_clause optimize_clause
{
SelectNode* node = newNode<SelectNode>();
node->dsqlExpr = $1;
node->dsqlForUpdate = $2;
node->dsqlWithLock = $3.first;
node->dsqlSkipLocked = $3.second;
node->dsqlOptimizeForFirstRows = $4;
node->selectExpr = $1;
node->forUpdate = $2;
node->withLock = $3.first;
node->skipLocked = $3.second;
node->optimizeForFirstRows = $4;
$$ = node;
}
;

View File

@ -585,15 +585,15 @@ RseNode* PASS1_rse(DsqlCompilerScratch* dsqlScratch,
DEV_BLKCHK(dsqlScratch, dsql_type_req);
DEV_BLKCHK(input, dsql_type_nod);
const bool updateLock = select ? select->dsqlWithLock : false;
const bool skipLocked = select ? select->dsqlSkipLocked : false;
const bool updateLock = select ? select->withLock : false;
const bool skipLocked = select ? select->skipLocked : false;
dsqlScratch->scopeLevel++;
RseNode* node = pass1_rse(dsqlScratch, input, NULL, NULL, updateLock, skipLocked, 0);
dsqlScratch->scopeLevel--;
if (select)
node->firstRows = select->dsqlOptimizeForFirstRows;
node->firstRows = select->optimizeForFirstRows;
return node;
}

View File

@ -855,31 +855,24 @@ void EXE_send(thread_db* tdbb, Request* request, USHORT msg, ULONG length, const
if (!(request->req_flags & req_active))
ERR_post(Arg::Gds(isc_req_sync));
const StmtNode* message = NULL;
const StmtNode* node;
if (request->req_operation != Request::req_receive)
ERR_post(Arg::Gds(isc_req_sync));
node = request->req_message;
jrd_tra* transaction = request->req_transaction;
const SelectNode* selectNode;
const auto node = request->req_message;
const StmtNode* message = nullptr;
if (nodeIs<MessageNode>(node))
message = node;
else if ((selectNode = nodeAs<SelectNode>(node)))
else if (const auto* const selectMessageNode = nodeAs<SelectMessageNode>(node))
{
const NestConst<StmtNode>* ptr = selectNode->statements.begin();
for (const NestConst<StmtNode>* end = selectNode->statements.end(); ptr != end; ++ptr)
for (const auto statement : selectMessageNode->statements)
{
const ReceiveNode* receiveNode = nodeAs<ReceiveNode>(*ptr);
const auto receiveNode = nodeAs<ReceiveNode>(statement);
message = receiveNode->message;
if (nodeAs<MessageNode>(message)->messageNumber == msg)
{
request->req_next = *ptr;
request->req_next = statement;
break;
}
}
@ -887,7 +880,7 @@ void EXE_send(thread_db* tdbb, Request* request, USHORT msg, ULONG length, const
else
BUGCHECK(167); // msg 167 invalid SEND request
const Format* format = nodeAs<MessageNode>(message)->format;
const auto format = nodeAs<MessageNode>(message)->format;
if (msg != nodeAs<MessageNode>(message)->messageNumber)
ERR_post(Arg::Gds(isc_req_sync));
@ -897,7 +890,7 @@ void EXE_send(thread_db* tdbb, Request* request, USHORT msg, ULONG length, const
memcpy(request->getImpure<UCHAR>(message->impureOffset), buffer, length);
execute_looper(tdbb, request, transaction, request->req_next, Request::req_proceed);
execute_looper(tdbb, request, request->req_transaction, request->req_next, Request::req_proceed);
}