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

Generate savepoint around blr_store for non-cursor INSERT's (INSERT INTO ... VALUES (...) ) with sub-select in VALUES list.

It fixes bug CORE-5337 : The subquery in the insert list expressions ignore the changes made earlier in the same executable block.
Note, existing procedures and triggers should be recompiled to have new BLR code.
This commit is contained in:
hvlad 2016-09-25 23:46:45 +03:00
parent 58dafb5ba2
commit d5ff6d82c2
2 changed files with 24 additions and 6 deletions

View File

@ -5329,7 +5329,8 @@ StmtNode* MergeNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
store->dsqlFields = notMatched->fields;
store->dsqlValues = notMatched->values;
thisIf->trueAction = store = store->internalDsqlPass(dsqlScratch, false)->as<StoreNode>();
bool needSavePoint; // unused
thisIf->trueAction = store = store->internalDsqlPass(dsqlScratch, false, needSavePoint)->as<StoreNode>();
fb_assert(store);
if (notMatched->condition)
@ -6436,7 +6437,7 @@ DmlNode* StoreNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* cs
return node;
}
StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, bool updateOrInsert)
StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, bool updateOrInsert, bool& needSavePoint)
{
thread_db* tdbb = JRD_get_thread_data(); // necessary?
DsqlContextStack::AutoRestore autoContext(*dsqlScratch->context);
@ -6460,9 +6461,13 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, bool upd
RseNode* rse = PASS1_rse(dsqlScratch, selExpr, false);
node->dsqlRse = rse;
values = rse->dsqlSelectList;
needSavePoint = false;
}
else
{
values = doDsqlPass(dsqlScratch, dsqlValues, false);
needSavePoint = SubSelectFinder::find(values);
}
// Process relation
@ -6598,7 +6603,14 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, bool upd
StmtNode* StoreNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
return SavepointEncloseNode::make(getPool(), dsqlScratch, internalDsqlPass(dsqlScratch, false));
bool needSavePoint;
StmtNode* node = SavepointEncloseNode::make(getPool(), dsqlScratch,
internalDsqlPass(dsqlScratch, false, needSavePoint));
if (!needSavePoint || node->is<SavepointEncloseNode>())
return node;
return FB_NEW SavepointEncloseNode(getPool(), node);
}
string StoreNode::internalPrint(NodePrinter& printer) const
@ -7979,13 +7991,15 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
const MetaName& relation_name = relation->as<RelationSourceNode>()->dsqlName;
MetaName base_name = relation_name;
bool needSavePoint;
// Build the INSERT node.
StoreNode* insert = FB_NEW_POOL(pool) StoreNode(pool);
insert->dsqlRelation = relation;
insert->dsqlFields = fields;
insert->dsqlValues = values;
insert->dsqlReturning = returning;
insert = insert->internalDsqlPass(dsqlScratch, true)->as<StoreNode>();
insert = insert->internalDsqlPass(dsqlScratch, true, needSavePoint)->as<StoreNode>();
fb_assert(insert);
dsql_ctx* context = insert->dsqlRelation->dsqlContext;
@ -8165,7 +8179,11 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
if (!returning)
dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_INSERT);
return SavepointEncloseNode::make(getPool(), dsqlScratch, list);
StmtNode* ret = SavepointEncloseNode::make(getPool(), dsqlScratch, list);
if (!needSavePoint || ret->is<SavepointEncloseNode>())
return ret;
return FB_NEW SavepointEncloseNode(getPool(), ret);
}
string UpdateOrInsertNode::internalPrint(NodePrinter& printer) const

View File

@ -1244,7 +1244,7 @@ public:
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
virtual Firebird::string internalPrint(NodePrinter& printer) const;
StmtNode* internalDsqlPass(DsqlCompilerScratch* dsqlScratch, bool updateOrInsert);
StmtNode* internalDsqlPass(DsqlCompilerScratch* dsqlScratch, bool updateOrInsert, bool& needSavePoint);
virtual StmtNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual StoreNode* pass1(thread_db* tdbb, CompilerScratch* csb);