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

Reworked PR #7426. This fixes the crash during second invocation of external trigger. Using a temporary vector is a bad idea because it owns the trigger object but external triggers store a back pointer to Jrd::Trigger, thus implying it being persistent.

This commit is contained in:
Dmitry Yemanov 2023-11-08 21:44:42 +03:00
parent fbb16e854a
commit beabce06e9
2 changed files with 25 additions and 49 deletions

View File

@ -552,58 +552,19 @@ void EXE_execute_db_triggers(thread_db* tdbb, jrd_tra* transaction, TriggerActio
// Execute DDL triggers.
void EXE_execute_ddl_triggers(thread_db* tdbb, jrd_tra* transaction, bool preTriggers, int action)
{
Jrd::Attachment* attachment = tdbb->getAttachment();
const auto attachment = tdbb->getAttachment();
// Our caller verifies (ATT_no_db_triggers) if DDL triggers should not run.
// Our caller verifies (ATT_no_db_triggers) if DDL triggers should not run
if (attachment->att_ddl_triggers)
{
TrigVector triggers;
TrigVector* triggersPtr = &triggers;
HalfStaticArray<Trigger*, 4> cachedTriggers;
AutoSetRestore2<jrd_tra*, thread_db> tempTrans(tdbb,
&thread_db::getTransaction,
&thread_db::setTransaction,
transaction);
for (auto& trigger : *attachment->att_ddl_triggers)
{
const auto type = trigger.type & ~TRIGGER_TYPE_MASK;
const bool preTrigger = ((type & 1) == 0);
if ((type & (1LL << action)) && (preTriggers == preTrigger))
{
triggers.add() = trigger;
cachedTriggers.add(&trigger);
}
}
if (triggers.hasData())
{
FbLocalStatus tempStatus;
jrd_tra* const oldTransaction = tdbb->getTransaction();
tdbb->setTransaction(transaction);
try
{
EXE_execute_triggers(tdbb, &triggersPtr, NULL, NULL, TRIGGER_DDL,
preTriggers ? StmtNode::PRE_TRIG : StmtNode::POST_TRIG);
}
catch (const Exception& ex)
{
ex.stuffException(&tempStatus);
}
tdbb->setTransaction(oldTransaction);
// Triggers could be compiled inside EXE_execute_triggers(),
// so ensure the new pointers are copied back to the cache
fb_assert(triggers.getCount() == cachedTriggers.getCount());
for (unsigned i = 0; i < triggers.getCount(); i++)
{
*cachedTriggers[i] = triggers[i];
triggers[i].extTrigger = nullptr; // avoid deletion inside d'tor
}
tempStatus.check();
}
EXE_execute_triggers(tdbb, &attachment->att_ddl_triggers, NULL, NULL, TRIGGER_DDL,
preTriggers ? StmtNode::PRE_TRIG : StmtNode::POST_TRIG, action);
}
}
@ -1135,7 +1096,8 @@ void EXE_execute_triggers(thread_db* tdbb,
record_param* old_rpb,
record_param* new_rpb,
TriggerAction trigger_action,
StmtNode::WhichTrigger which_trig)
StmtNode::WhichTrigger which_trig,
int ddl_action)
{
/**************************************
*
@ -1188,6 +1150,20 @@ void EXE_execute_triggers(thread_db* tdbb,
{
for (TrigVector::iterator ptr = vector->begin(); ptr != vector->end(); ++ptr)
{
if (trigger_action == TRIGGER_DDL && ddl_action)
{
// Skip triggers not matching our action
fb_assert(which_trig == StmtNode::PRE_TRIG || which_trig == StmtNode::POST_TRIG);
const bool preTriggers = (which_trig == StmtNode::PRE_TRIG);
const auto type = ptr->type & ~TRIGGER_TYPE_MASK;
const bool preTrigger = ((type & 1) == 0);
if (!(type & (1LL << ddl_action)) || preTriggers != preTrigger)
continue;
}
ptr->compile(tdbb);
trigger = ptr->statement->findRequest(tdbb);

View File

@ -46,7 +46,7 @@ const Jrd::StmtNode* EXE_looper(Jrd::thread_db* tdbb, Jrd::Request* request,
const Jrd::StmtNode* in_node);
void EXE_execute_triggers(Jrd::thread_db*, Jrd::TrigVector**, Jrd::record_param*, Jrd::record_param*,
enum TriggerAction, Jrd::StmtNode::WhichTrigger);
enum TriggerAction, Jrd::StmtNode::WhichTrigger, int = 0);
void EXE_receive(Jrd::thread_db*, Jrd::Request*, USHORT, ULONG, void*, bool = false);
void EXE_release(Jrd::thread_db*, Jrd::Request*);