Skip to content

Commit 421a73a

Browse files
committed
Fixed #7651: Unable to find savepoint in insert with nested query and returning clause. Fixed also regression for #5613 regarding UPDATE OR INSERT.
1 parent 00bb8e4 commit 421a73a

File tree

2 files changed

+26
-21
lines changed

2 files changed

+26
-21
lines changed

src/dsql/StmtNodes.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7536,7 +7536,11 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
75367536
else
75377537
{
75387538
values = doDsqlPass(dsqlScratch, dsqlValues, false);
7539-
needSavePoint = SubSelectFinder::find(dsqlScratch->getPool(), values);
7539+
// If this INSERT belongs to some PSQL code block and has subqueries
7540+
// inside its VALUES part, signal the caller to create a savepoint frame.
7541+
// See bug #5613 (aka CORE-5337) for details.
7542+
needSavePoint = (dsqlScratch->flags & DsqlCompilerScratch::FLAG_BLOCK) &&
7543+
SubSelectFinder::find(dsqlScratch->getPool(), values);
75407544
}
75417545

75427546
// Process relation
@@ -7681,13 +7685,9 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
76817685
StmtNode* StoreNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
76827686
{
76837687
bool needSavePoint;
7684-
StmtNode* node = SavepointEncloseNode::make(dsqlScratch->getPool(), dsqlScratch,
7685-
internalDsqlPass(dsqlScratch, false, needSavePoint));
7688+
const auto node = internalDsqlPass(dsqlScratch, false, needSavePoint);
76867689

7687-
if (!needSavePoint || nodeIs<SavepointEncloseNode>(node))
7688-
return node;
7689-
7690-
return FB_NEW_POOL(dsqlScratch->getPool()) SavepointEncloseNode(dsqlScratch->getPool(), node);
7690+
return SavepointEncloseNode::make(dsqlScratch->getPool(), dsqlScratch, node, needSavePoint);
76917691
}
76927692

76937693
string StoreNode::internalPrint(NodePrinter& printer) const
@@ -8758,12 +8758,18 @@ DmlNode* SavepointEncloseNode::parse(thread_db* tdbb, MemoryPool& pool, Compiler
87588758
return node;
87598759
}
87608760

8761-
StmtNode* SavepointEncloseNode::make(MemoryPool& pool, DsqlCompilerScratch* dsqlScratch, StmtNode* node)
8761+
StmtNode* SavepointEncloseNode::make(MemoryPool& pool, DsqlCompilerScratch* dsqlScratch, StmtNode* node, bool force)
87628762
{
8763-
// Add savepoint wrapper around the statement having error handlers
8763+
// Add savepoint wrapper around the statement having error handlers, or if requested explicitly
87648764

8765-
return dsqlScratch->errorHandlers ?
8766-
FB_NEW_POOL(pool) SavepointEncloseNode(pool, node) : node;
8765+
if (dsqlScratch->errorHandlers || force)
8766+
{
8767+
// Ensure that savepoints are never created around a DSQL statement
8768+
fb_assert(dsqlScratch->flags & DsqlCompilerScratch::FLAG_BLOCK);
8769+
return FB_NEW_POOL(pool) SavepointEncloseNode(pool, node);
8770+
}
8771+
8772+
return node;
87678773
}
87688774

87698775
SavepointEncloseNode* SavepointEncloseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
@@ -9417,7 +9423,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
94179423
if (!returning)
94189424
dsqlScratch->getDsqlStatement()->setType(DsqlStatement::TYPE_INSERT);
94199425

9420-
return SavepointEncloseNode::make(dsqlScratch->getPool(), dsqlScratch, node);
9426+
return SavepointEncloseNode::make(dsqlScratch->getPool(), dsqlScratch, node, needSavePoint);
94219427
}
94229428

94239429
string UpdateOrInsertNode::internalPrint(NodePrinter& printer) const

src/dsql/StmtNodes.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,17 +1444,10 @@ class ReturnNode final : public TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_RETUR
14441444

14451445
class SavepointEncloseNode final : public TypedNode<StmtNode, StmtNode::TYPE_SAVEPOINT>
14461446
{
1447-
public:
1448-
explicit SavepointEncloseNode(MemoryPool& pool, StmtNode* stmt)
1449-
: TypedNode<StmtNode, StmtNode::TYPE_SAVEPOINT>(pool),
1450-
statement(stmt)
1451-
{
1452-
}
1453-
14541447
public:
14551448
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
14561449

1457-
static StmtNode* make(MemoryPool& pool, DsqlCompilerScratch* dsqlScratch, StmtNode* node);
1450+
static StmtNode* make(MemoryPool& pool, DsqlCompilerScratch* dsqlScratch, StmtNode* node, bool force = false);
14581451

14591452
virtual Firebird::string internalPrint(NodePrinter& printer) const;
14601453
virtual SavepointEncloseNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
@@ -1465,7 +1458,13 @@ class SavepointEncloseNode final : public TypedNode<StmtNode, StmtNode::TYPE_SAV
14651458

14661459
virtual const StmtNode* execute(thread_db* tdbb, Request* request, ExeState* exeState) const;
14671460

1468-
public:
1461+
private:
1462+
explicit SavepointEncloseNode(MemoryPool& pool, StmtNode* stmt)
1463+
: TypedNode<StmtNode, StmtNode::TYPE_SAVEPOINT>(pool),
1464+
statement(stmt)
1465+
{
1466+
}
1467+
14691468
NestConst<StmtNode> statement;
14701469
};
14711470

0 commit comments

Comments
 (0)