@@ -178,11 +178,11 @@ namespace
178178 m_savepoint.rollback ();
179179 }
180180
181- private:
182181 // Prohibit unwanted creation/copying
183182 CondSavepointAndMarker (const CondSavepointAndMarker&) = delete ;
184183 CondSavepointAndMarker& operator =(const CondSavepointAndMarker&) = delete ;
185184
185+ private:
186186 AutoSavePoint m_savepoint;
187187 Savepoint::ChangeMarker m_marker;
188188 };
@@ -2273,9 +2273,9 @@ const StmtNode* DeclareVariableNode::execute(thread_db* tdbb, Request* request,
22732273// --------------------
22742274
22752275
2276- static RegisterNode<EraseNode> regEraseNode ({blr_erase});
2276+ static RegisterNode<EraseNode> regEraseNode ({blr_erase, blr_erase2 });
22772277
2278- DmlNode* EraseNode::parse (thread_db* /* tdbb*/ , MemoryPool& pool, CompilerScratch* csb, const UCHAR /* blrOp*/ )
2278+ DmlNode* EraseNode::parse (thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp)
22792279{
22802280 const USHORT n = csb->csb_blr_reader .getByte ();
22812281
@@ -2288,6 +2288,9 @@ DmlNode* EraseNode::parse(thread_db* /*tdbb*/, MemoryPool& pool, CompilerScratch
22882288 if (csb->csb_blr_reader .peekByte () == blr_marks)
22892289 node->marks |= PAR_marks (csb);
22902290
2291+ if (blrOp == blr_erase2)
2292+ node->returningStatement = PAR_parse_stmt (tdbb, csb);
2293+
22912294 return node;
22922295}
22932296
@@ -2385,6 +2388,7 @@ string EraseNode::internalPrint(NodePrinter& printer) const
23852388 NODE_PRINT (printer, dsqlSkipLocked);
23862389 NODE_PRINT (printer, statement);
23872390 NODE_PRINT (printer, subStatement);
2391+ NODE_PRINT (printer, returningStatement);
23882392 NODE_PRINT (printer, stream);
23892393 NODE_PRINT (printer, marks);
23902394
@@ -2397,11 +2401,14 @@ void EraseNode::genBlr(DsqlCompilerScratch* dsqlScratch)
23972401{
23982402 std::optional<USHORT> tableNumber;
23992403
2404+ const bool skipLocked = dsqlRse && dsqlRse->hasSkipLocked ();
2405+
24002406 if (dsqlReturning && !dsqlScratch->isPsql ())
24012407 {
24022408 if (dsqlCursorName.isEmpty ())
24032409 {
2404- dsqlScratch->appendUChar (blr_begin);
2410+ if (!skipLocked)
2411+ dsqlScratch->appendUChar (blr_begin);
24052412
24062413 tableNumber = dsqlScratch->localTableNumber ++;
24072414 dsqlGenReturningLocalTableDecl (dsqlScratch, tableNumber.value ());
@@ -2422,28 +2429,31 @@ void EraseNode::genBlr(DsqlCompilerScratch* dsqlScratch)
24222429
24232430 const auto * context = dsqlContext ? dsqlContext : dsqlRelation->dsqlContext ;
24242431
2425- if (dsqlReturning)
2432+ if (dsqlReturning && !skipLocked )
24262433 {
24272434 dsqlScratch->appendUChar (blr_begin);
2435+ dsqlGenReturning (dsqlScratch, dsqlReturning, tableNumber);
24282436 }
24292437
2430- dsqlScratch->appendUChar (blr_erase);
2438+ dsqlScratch->appendUChar (dsqlReturning && skipLocked ? blr_erase2 : blr_erase);
24312439 GEN_stuff_context (dsqlScratch, context);
24322440
24332441 if (marks)
24342442 dsqlScratch->putBlrMarkers (marks);
24352443
24362444 if (dsqlReturning)
24372445 {
2438- dsqlGenReturning (dsqlScratch, dsqlReturning, tableNumber);
2439-
2440- dsqlScratch->appendUChar (blr_end);
2446+ if (!skipLocked)
2447+ dsqlScratch->appendUChar (blr_end);
2448+ else
2449+ dsqlGenReturning (dsqlScratch, dsqlReturning, tableNumber);
24412450
24422451 if (!dsqlScratch->isPsql () && dsqlCursorName.isEmpty ())
24432452 {
24442453 dsqlGenReturningLocalTableCursor (dsqlScratch, dsqlReturning, tableNumber.value ());
24452454
2446- dsqlScratch->appendUChar (blr_end);
2455+ if (!skipLocked)
2456+ dsqlScratch->appendUChar (blr_end);
24472457 }
24482458 }
24492459}
@@ -2455,6 +2465,9 @@ EraseNode* EraseNode::pass1(thread_db* tdbb, CompilerScratch* csb)
24552465 doPass1 (tdbb, csb, statement.getAddress ());
24562466 doPass1 (tdbb, csb, subStatement.getAddress ());
24572467
2468+ AutoSetRestore<bool > autoReturningExpr (&csb->csb_returning_expr , true );
2469+ doPass1 (tdbb, csb, returningStatement.getAddress ());
2470+
24582471 return this ;
24592472}
24602473
@@ -2571,6 +2584,7 @@ void EraseNode::pass1Erase(thread_db* tdbb, CompilerScratch* csb, EraseNode* nod
25712584EraseNode* EraseNode::pass2 (thread_db* tdbb, CompilerScratch* csb)
25722585{
25732586 doPass2 (tdbb, csb, statement.getAddress (), this );
2587+ doPass2 (tdbb, csb, returningStatement.getAddress (), this );
25742588 doPass2 (tdbb, csb, subStatement.getAddress (), this );
25752589
25762590 const jrd_rel* const relation = csb->csb_rpt [stream].csb_relation ;
@@ -2649,6 +2663,8 @@ const StmtNode* EraseNode::execute(thread_db* tdbb, Request* request, ExeState*
26492663// Perform erase operation.
26502664const StmtNode* EraseNode::erase (thread_db* tdbb, Request* request, WhichTrigger whichTrig) const
26512665{
2666+ impure_state* impure = request->getImpure <impure_state>(impureOffset);
2667+
26522668 jrd_tra* transaction = request->req_transaction ;
26532669 record_param* rpb = &request->req_rpb [stream];
26542670 jrd_rel* relation = rpb->rpb_relation ;
@@ -2674,6 +2690,12 @@ const StmtNode* EraseNode::erase(thread_db* tdbb, Request* request, WhichTrigger
26742690 }
26752691
26762692 case Request::req_return:
2693+ if (impure->sta_state == 1 )
2694+ {
2695+ impure->sta_state = 0 ;
2696+ rpb->rpb_number .setValid (false );
2697+ return parentStmt;
2698+ }
26772699 break ;
26782700
26792701 default :
@@ -2735,9 +2757,9 @@ const StmtNode* EraseNode::erase(thread_db* tdbb, Request* request, WhichTrigger
27352757
27362758 if (!VIO_erase (tdbb, rpb, transaction))
27372759 {
2738- // Record was not deleted, flow control should be passed to the
2739- // parent ForNode. Note, If RETURNING clause was specified, then
2740- // parent node is CompoundStmtNode, not ForNode. If\when this
2760+ // Record was not deleted, flow control should be passed to the parent
2761+ // ForNode. Note, If RETURNING clause was specified and SKIP LOCKED was
2762+ // not, then parent node is CompoundStmtNode, not ForNode. If\when this
27412763 // will be changed, the code below should be changed accordingly.
27422764
27432765 if (skipLocked)
@@ -2789,6 +2811,13 @@ const StmtNode* EraseNode::erase(thread_db* tdbb, Request* request, WhichTrigger
27892811 }
27902812 }
27912813
2814+ if (returningStatement)
2815+ {
2816+ impure->sta_state = 1 ;
2817+ request->req_operation = Request::req_evaluate;
2818+ return returningStatement;
2819+ }
2820+
27922821 rpb->rpb_number .setValid (false );
27932822
27942823 return parentStmt;
@@ -7774,7 +7803,7 @@ const StmtNode* ModifyNode::modify(thread_db* tdbb, Request* request, WhichTrigg
77747803
77757804 SavepointChangeMarker scMarker (transaction);
77767805
7777- // Prepare to undo changed by PRE-triggers if record is locked by another
7806+ // Prepare to undo changes by PRE-triggers if record is locked by another
77787807 // transaction and update should be skipped.
77797808 const bool skipLocked = orgRpb->rpb_stream_flags & RPB_s_skipLocked;
77807809 CondSavepointAndMarker spPreTriggers (tdbb, transaction,
0 commit comments