mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:03:03 +01:00
Merge pull request #8202 from FirebirdSQL/work/system-triggers
Reimplement system triggers in C++/GDML code
This commit is contained in:
commit
16da398675
@ -31,6 +31,7 @@
|
||||
<ClCompile Include="..\..\..\gen\jrd\ini.cpp" />
|
||||
<ClCompile Include="..\..\..\gen\jrd\met.cpp" />
|
||||
<ClCompile Include="..\..\..\gen\jrd\scl.cpp" />
|
||||
<ClCompile Include="..\..\..\gen\jrd\SystemTriggers.cpp" />
|
||||
<ClCompile Include="..\..\..\gen\utilities\gstat\dba.cpp" />
|
||||
<ClCompile Include="..\..\..\src\dsql\AggNodes.cpp" />
|
||||
<ClCompile Include="..\..\..\src\dsql\BlrDebugWriter.cpp" />
|
||||
@ -350,6 +351,7 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\sys-packages\SqlPackage.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\SysFunction.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\SystemPackages.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\SystemTriggers.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\TempSpace.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\TimeZone.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\tpc_proto.h" />
|
||||
@ -390,6 +392,7 @@
|
||||
<None Include="..\..\..\src\jrd\ini.epp" />
|
||||
<None Include="..\..\..\src\jrd\met.epp" />
|
||||
<None Include="..\..\..\src\jrd\scl.epp" />
|
||||
<None Include="..\..\..\src\jrd\SystemTriggers.epp" />
|
||||
<None Include="..\..\..\src\utilities\gstat\dba.epp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
|
@ -423,6 +423,9 @@
|
||||
<ClCompile Include="..\..\..\gen\jrd\scl.cpp">
|
||||
<Filter>JRD files\GPRE cpp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\gen\jrd\SystemTriggers.cpp">
|
||||
<Filter>JRD files\GPRE cpp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\gen\jrd\dfw.cpp">
|
||||
<Filter>JRD files\GPRE cpp</Filter>
|
||||
</ClCompile>
|
||||
@ -1085,6 +1088,9 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\SystemPackages.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\SystemTriggers.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\Coercion.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
@ -1139,6 +1145,9 @@
|
||||
<None Include="..\..\..\src\jrd\scl.epp">
|
||||
<Filter>JRD files\GPRE files</Filter>
|
||||
</None>
|
||||
<None Include="..\..\..\src\jrd\SystemTriggers.epp">
|
||||
<Filter>JRD files\GPRE files</Filter>
|
||||
</None>
|
||||
<None Include="..\..\..\src\utilities\gstat\dba.epp">
|
||||
<Filter>Services</Filter>
|
||||
</None>
|
||||
@ -1146,4 +1155,4 @@
|
||||
<Filter>DSQL</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -65,7 +65,7 @@ goto :EOF
|
||||
@for %%i in (alice_meta) do @call :PREPROCESS alice %%i
|
||||
@for %%i in (metd, DdlNodes, PackageNodes) do @call :PREPROCESS dsql %%i -gds_cxx
|
||||
@for %%i in (gpre_meta) do @call :PREPROCESS gpre/std %%i
|
||||
@for %%i in (dfw, dpm, dyn_util, fun, grant, ini, met, scl, Function) do @call :PREPROCESS jrd %%i -gds_cxx
|
||||
@for %%i in (dfw, dpm, dyn_util, fun, grant, ini, met, scl, Function, SystemTriggers) do @call :PREPROCESS jrd %%i -gds_cxx
|
||||
@for %%i in (stats) do @call :PREPROCESS utilities %%i
|
||||
@goto :EOF
|
||||
|
||||
@ -78,7 +78,7 @@ goto :EOF
|
||||
@for %%i in (metd) do @call :PREPROCESS dsql %%i -gds_cxx
|
||||
@for %%i in (DdlNodes, PackageNodes) do @call :PREPROCESS dsql %%i -gds_cxx
|
||||
@for %%i in (gpre_meta) do @call :PREPROCESS gpre/std %%i
|
||||
@for %%i in (dfw, dpm, dyn_util, fun, grant, ini, met, scl, Function) do @call :PREPROCESS jrd %%i -gds_cxx
|
||||
@for %%i in (dfw, dpm, dyn_util, fun, grant, ini, met, scl, Function, SystemTriggers) do @call :PREPROCESS jrd %%i -gds_cxx
|
||||
@for %%i in (extract, isql, show) do @call :PREPROCESS isql %%i -ocxx
|
||||
@for %%i in (dba) do @call :PREPROCESS utilities/gstat %%i
|
||||
@for %%i in (stats) do @call :PREPROCESS utilities %%i
|
||||
|
@ -2781,7 +2781,7 @@ const StmtNode* EraseNode::erase(thread_db* tdbb, Request* request, WhichTrigger
|
||||
spPreTriggers.release();
|
||||
|
||||
// Handle post operation trigger.
|
||||
if (relation->rel_post_erase && whichTrig != PRE_TRIG)
|
||||
if ((relation->rel_post_erase || relation->isSystem()) && whichTrig != PRE_TRIG)
|
||||
{
|
||||
EXE_execute_triggers(tdbb, &relation->rel_post_erase, rpb, NULL, TRIGGER_DELETE, POST_TRIG);
|
||||
}
|
||||
@ -7848,7 +7848,7 @@ const StmtNode* ModifyNode::modify(thread_db* tdbb, Request* request, WhichTrigg
|
||||
newRpb->rpb_number = orgRpb->rpb_number;
|
||||
newRpb->rpb_number.setValid(true);
|
||||
|
||||
if (relation->rel_post_modify && whichTrig != PRE_TRIG)
|
||||
if ((relation->rel_post_modify || relation->isSystem()) && whichTrig != PRE_TRIG)
|
||||
{
|
||||
EXE_execute_triggers(tdbb, &relation->rel_post_modify, orgRpb, newRpb,
|
||||
TRIGGER_UPDATE, POST_TRIG);
|
||||
@ -8871,7 +8871,7 @@ const StmtNode* StoreNode::store(thread_db* tdbb, Request* request, WhichTrigger
|
||||
{
|
||||
SavepointChangeMarker scMarker(transaction);
|
||||
|
||||
if (relation && relation->rel_pre_store && whichTrig != POST_TRIG)
|
||||
if (relation && (relation->rel_pre_store || relation->isSystem()) && whichTrig != POST_TRIG)
|
||||
{
|
||||
EXE_execute_triggers(tdbb, &relation->rel_pre_store, NULL, rpb,
|
||||
TRIGGER_INSERT, PRE_TRIG);
|
||||
@ -8904,7 +8904,8 @@ const StmtNode* StoreNode::store(thread_db* tdbb, Request* request, WhichTrigger
|
||||
|
||||
rpb->rpb_number.setValid(true);
|
||||
|
||||
if (relation && relation->rel_post_store && whichTrig != PRE_TRIG)
|
||||
if (relation && (relation->rel_post_store || relation->isSystem()) &&
|
||||
relation->rel_post_store && whichTrig != PRE_TRIG)
|
||||
{
|
||||
EXE_execute_triggers(tdbb, &relation->rel_post_store, NULL, rpb,
|
||||
TRIGGER_INSERT, POST_TRIG);
|
||||
@ -11660,9 +11661,10 @@ static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs,
|
||||
FB_NEW_POOL(*tdbb->getTransaction()->tra_pool) traRpbList(*tdbb->getTransaction()->tra_pool);
|
||||
}
|
||||
|
||||
const auto relation = rpb->rpb_relation;
|
||||
const int rpblevel = tdbb->getTransaction()->tra_rpblist->PushRpb(rpb);
|
||||
|
||||
if (*trigs && whichTrig != StmtNode::POST_TRIG)
|
||||
if ((*trigs || relation->isSystem()) && whichTrig != StmtNode::POST_TRIG)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -265,6 +265,7 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb, JProvider* provider
|
||||
att_generators(*pool),
|
||||
att_internal(*pool),
|
||||
att_dyn_req(*pool),
|
||||
att_internal_cached_statements(*pool),
|
||||
att_dec_status(DecimalStatus::DEFAULT),
|
||||
att_charsets(*pool),
|
||||
att_charset_ids(*pool),
|
||||
@ -681,9 +682,15 @@ Request* Jrd::Attachment::findSystemRequest(thread_db* tdbb, USHORT id, USHORT w
|
||||
|
||||
//Database::CheckoutLockGuard guard(this, dbb_cmp_clone_mutex);
|
||||
|
||||
fb_assert(which == IRQ_REQUESTS || which == DYN_REQUESTS);
|
||||
fb_assert(which == IRQ_REQUESTS || which == DYN_REQUESTS || which == CACHED_REQUESTS);
|
||||
|
||||
Statement* statement = (which == IRQ_REQUESTS ? att_internal[id] : att_dyn_req[id]);
|
||||
if (which == CACHED_REQUESTS && id >= att_internal_cached_statements.getCount())
|
||||
att_internal_cached_statements.grow(id + 1);
|
||||
|
||||
Statement* statement =
|
||||
which == IRQ_REQUESTS ? att_internal[id] :
|
||||
which == DYN_REQUESTS ? att_dyn_req[id] :
|
||||
att_internal_cached_statements[id];
|
||||
|
||||
if (!statement)
|
||||
return NULL;
|
||||
|
@ -666,6 +666,7 @@ public:
|
||||
|
||||
Firebird::Array<Statement*> att_internal; // internal statements
|
||||
Firebird::Array<Statement*> att_dyn_req; // internal dyn statements
|
||||
Firebird::Array<Statement*> att_internal_cached_statements; // internal cached statements
|
||||
Firebird::ICryptKeyCallback* att_crypt_callback; // callback for DB crypt
|
||||
Firebird::DecimalStatus att_dec_status; // error handling and rounding
|
||||
|
||||
|
@ -626,8 +626,6 @@ RelationSourceNode* RelationSourceNode::parse(thread_db* tdbb, CompilerScratch*
|
||||
{
|
||||
MET_scan_relation(tdbb, node->relation);
|
||||
}
|
||||
else if (node->relation->rel_flags & REL_sys_triggers)
|
||||
MET_parse_sys_trigger(tdbb, node->relation);
|
||||
|
||||
// generate a stream for the relation reference, assuming it is a real reference
|
||||
|
||||
|
@ -393,11 +393,9 @@ const ULONG REL_deleted = 0x0004; // Relation known gonzo
|
||||
const ULONG REL_get_dependencies = 0x0008; // New relation needs dependencies during scan
|
||||
const ULONG REL_check_existence = 0x0010; // Existence lock released pending drop of relation
|
||||
const ULONG REL_blocking = 0x0020; // Blocking someone from dropping relation
|
||||
const ULONG REL_sys_triggers = 0x0040; // The relation has system triggers to compile
|
||||
const ULONG REL_sql_relation = 0x0080; // Relation defined as sql table
|
||||
const ULONG REL_check_partners = 0x0100; // Rescan primary dependencies and foreign references
|
||||
const ULONG REL_being_scanned = 0x0200; // relation scan in progress
|
||||
const ULONG REL_sys_trigs_being_loaded = 0x0400; // System triggers being loaded
|
||||
const ULONG REL_deleting = 0x0800; // relation delete in progress
|
||||
const ULONG REL_temp_tran = 0x1000; // relation is a GTT delete rows
|
||||
const ULONG REL_temp_conn = 0x2000; // relation is a GTT preserve rows
|
||||
|
1383
src/jrd/SystemTriggers.epp
Normal file
1383
src/jrd/SystemTriggers.epp
Normal file
File diff suppressed because it is too large
Load Diff
43
src/jrd/SystemTriggers.h
Normal file
43
src/jrd/SystemTriggers.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Adriano dos Santos Fernandes
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2024 Adriano dos Santos Fernandes <adrianosf@gmail.com>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#ifndef JRD_SYSTEM_TRIGGERS_H
|
||||
#define JRD_SYSTEM_TRIGGERS_H
|
||||
|
||||
#include "firebird.h"
|
||||
|
||||
namespace Jrd
|
||||
{
|
||||
class jrd_rel;
|
||||
class thread_db;
|
||||
class Record;
|
||||
} // namespace Jrd
|
||||
|
||||
namespace Jrd::SystemTriggers
|
||||
{
|
||||
void executeBeforeDeleteTriggers(thread_db* tdbb, jrd_rel* relation, Record* record);
|
||||
void executeAfterDeleteTriggers(thread_db* tdbb, jrd_rel* relation, Record* record);
|
||||
void executeBeforeInsertTriggers(thread_db* tdbb, jrd_rel* relation, Record* record);
|
||||
void executeBeforeUpdateTriggers(thread_db* tdbb, jrd_rel* relation, Record* orgRecord, Record* newRecord);
|
||||
} // namespace Jrd::SystemTriggers
|
||||
|
||||
#endif // JRD_SYSTEM_TRIGGERS_H
|
@ -6304,9 +6304,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_
|
||||
|
||||
// We have just loaded the triggers onto the local vector triggers.
|
||||
// It's now time to place them at their rightful place inside the relation block.
|
||||
|
||||
if (!(relation->rel_flags & REL_sys_trigs_being_loaded))
|
||||
relation->replaceTriggers(tdbb, triggers);
|
||||
relation->replaceTriggers(tdbb, triggers);
|
||||
|
||||
// in case somebody changed the view definition or a computed
|
||||
// field, reset the dependencies by deleting the current ones
|
||||
|
@ -71,6 +71,7 @@
|
||||
#include "../jrd/intl.h"
|
||||
#include "../jrd/sbm.h"
|
||||
#include "../jrd/blb.h"
|
||||
#include "../jrd/SystemTriggers.h"
|
||||
#include "firebird/impl/blr.h"
|
||||
#include "../dsql/ExprNodes.h"
|
||||
#include "../dsql/StmtNodes.h"
|
||||
@ -1294,18 +1295,57 @@ void EXE_execute_triggers(thread_db* tdbb,
|
||||
* if any blow up.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
const auto dbb = tdbb->getDatabase();
|
||||
const auto old_rec = old_rpb ? old_rpb->rpb_record : nullptr;
|
||||
const auto new_rec = new_rpb ? new_rpb->rpb_record : nullptr;
|
||||
|
||||
if (!(dbb->dbb_flags & DBB_creating) && (old_rpb || new_rpb))
|
||||
{
|
||||
if (const auto relation = old_rpb ? old_rpb->rpb_relation : new_rpb->rpb_relation;
|
||||
relation->rel_flags & REL_system)
|
||||
{
|
||||
switch (which_trig)
|
||||
{
|
||||
case StmtNode::PRE_TRIG:
|
||||
{
|
||||
switch (trigger_action)
|
||||
{
|
||||
case TriggerAction::TRIGGER_DELETE:
|
||||
SystemTriggers::executeBeforeDeleteTriggers(tdbb, relation, old_rec);
|
||||
break;
|
||||
|
||||
case TriggerAction::TRIGGER_UPDATE:
|
||||
SystemTriggers::executeBeforeUpdateTriggers(tdbb, relation, old_rec, new_rec);
|
||||
break;
|
||||
|
||||
case TriggerAction::TRIGGER_INSERT:
|
||||
SystemTriggers::executeBeforeInsertTriggers(tdbb, relation, new_rec);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case StmtNode::POST_TRIG:
|
||||
switch (trigger_action)
|
||||
{
|
||||
case TriggerAction::TRIGGER_DELETE:
|
||||
SystemTriggers::executeAfterDeleteTriggers(tdbb, relation, old_rec);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!*triggers || (*triggers)->isEmpty())
|
||||
return;
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Request* const request = tdbb->getRequest();
|
||||
jrd_tra* const transaction = request ? request->req_transaction : tdbb->getTransaction();
|
||||
|
||||
RefPtr<TrigVector> vector(*triggers);
|
||||
Record* const old_rec = old_rpb ? old_rpb->rpb_record : NULL;
|
||||
Record* const new_rec = new_rpb ? new_rpb->rpb_record : NULL;
|
||||
|
||||
AutoPtr<Record> null_rec;
|
||||
|
||||
const bool is_db_trigger = (!old_rec && !new_rec);
|
||||
@ -1868,15 +1908,6 @@ static void trigger_failure(thread_db* tdbb, Request* trigger)
|
||||
MET_trigger_msg(tdbb, msg, trigger->getStatement()->triggerName, trigger->req_label);
|
||||
if (msg.hasData())
|
||||
{
|
||||
if (trigger->getStatement()->flags & Statement::FLAG_SYS_TRIGGER)
|
||||
{
|
||||
ISC_STATUS code = PAR_symbol_to_gdscode(msg);
|
||||
if (code)
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_integ_fail) << Arg::Num(trigger->req_label) <<
|
||||
Arg::Gds(code));
|
||||
}
|
||||
}
|
||||
ERR_post(Arg::Gds(isc_integ_fail) << Arg::Num(trigger->req_label) <<
|
||||
Arg::Gds(isc_random) << Arg::Str(msg));
|
||||
}
|
||||
@ -1897,8 +1928,15 @@ void AutoCacheRequest::cacheRequest()
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Attachment* att = tdbb->getAttachment();
|
||||
|
||||
Statement** stmt = which == IRQ_REQUESTS ? &att->att_internal[id] :
|
||||
which == DYN_REQUESTS ? &att->att_dyn_req[id] : nullptr;
|
||||
if (which == CACHED_REQUESTS && id >= att->att_internal_cached_statements.getCount())
|
||||
att->att_internal_cached_statements.grow(id + 1);
|
||||
|
||||
Statement** stmt =
|
||||
which == IRQ_REQUESTS ? &att->att_internal[id] :
|
||||
which == DYN_REQUESTS ? &att->att_dyn_req[id] :
|
||||
which == CACHED_REQUESTS ? &att->att_internal_cached_statements[id] :
|
||||
nullptr;
|
||||
|
||||
if (!stmt)
|
||||
{
|
||||
fb_assert(false);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#define JRD_EXE_PROTO_H
|
||||
|
||||
#include "../jrd/cmp_proto.h"
|
||||
#include <atomic>
|
||||
|
||||
namespace Jrd {
|
||||
class Request;
|
||||
@ -58,6 +59,29 @@ void EXE_unwind(Jrd::thread_db*, Jrd::Request*);
|
||||
|
||||
namespace Jrd
|
||||
{
|
||||
class CachedRequestId
|
||||
{
|
||||
public:
|
||||
CachedRequestId()
|
||||
: id(generator++)
|
||||
{
|
||||
fb_assert(id <= MAX_USHORT);
|
||||
}
|
||||
|
||||
CachedRequestId(const CachedRequestId&) = delete;
|
||||
CachedRequestId& operator=(const CachedRequestId&) = delete;
|
||||
|
||||
public:
|
||||
USHORT getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned id;
|
||||
static inline std::atomic_uint generator;
|
||||
};
|
||||
|
||||
// ASF: To make this class MT-safe in SS for v3, it should be AutoCacheRequest::release job to
|
||||
// inform CMP that the request is available for subsequent usage.
|
||||
class AutoCacheRequest
|
||||
@ -70,6 +94,13 @@ namespace Jrd
|
||||
{
|
||||
}
|
||||
|
||||
AutoCacheRequest(thread_db* tdbb, const CachedRequestId& cachedRequestId)
|
||||
: id(cachedRequestId.getId()),
|
||||
which(CACHED_REQUESTS),
|
||||
request(tdbb->getAttachment()->findSystemRequest(tdbb, id, which))
|
||||
{
|
||||
}
|
||||
|
||||
AutoCacheRequest()
|
||||
: id(0),
|
||||
which(0),
|
||||
@ -92,6 +123,15 @@ namespace Jrd
|
||||
request = tdbb->getAttachment()->findSystemRequest(tdbb, id, which);
|
||||
}
|
||||
|
||||
void reset(thread_db* tdbb, const CachedRequestId& cachedRequestId)
|
||||
{
|
||||
release();
|
||||
|
||||
id = cachedRequestId.getId();
|
||||
which = CACHED_REQUESTS;
|
||||
request = tdbb->getAttachment()->findSystemRequest(tdbb, id, which);
|
||||
}
|
||||
|
||||
void compile(thread_db* tdbb, const UCHAR* blr, ULONG blrLength)
|
||||
{
|
||||
if (request)
|
||||
|
276
src/jrd/ini.epp
276
src/jrd/ini.epp
@ -79,134 +79,6 @@ namespace
|
||||
jrd_vtof(name.c_str(), field, sizeof(field));
|
||||
}
|
||||
|
||||
// This is the table used in defining triggers; note that
|
||||
// RDB$TRIGGER_0 was first changed to RDB$TRIGGER_7 to make it easier to
|
||||
// upgrade a database to support field-level grant. It has since been
|
||||
// changed to RDB$TRIGGER_9 to handle SQL security on relations whose
|
||||
// name is > 27 characters
|
||||
|
||||
const jrd_trg triggers[] =
|
||||
{
|
||||
{ "RDB$TRIGGER_1", (UCHAR) nam_user_privileges,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger3), trigger3,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_8", (UCHAR) nam_user_privileges,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger2), trigger2,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_9", (UCHAR) nam_user_privileges,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger1), trigger1,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_2", (UCHAR) nam_trgs,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger4), trigger4,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_3", (UCHAR) nam_trgs,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger4), trigger4,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_26", (UCHAR) nam_rel_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger26), trigger26,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_25", (UCHAR) nam_rel_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger25),
|
||||
trigger25, 0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_10", (UCHAR) nam_rel_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger10), trigger10,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_11", (UCHAR) nam_rel_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger11),
|
||||
trigger11, 0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_12", (UCHAR) nam_ref_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_STORE, sizeof(trigger12), trigger12,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_13", (UCHAR) nam_ref_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger13),
|
||||
trigger13, 0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_14", (UCHAR) nam_chk_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger14),
|
||||
trigger14, 0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_15", (UCHAR) nam_chk_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger15), trigger15,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_16", (UCHAR) nam_chk_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger16),
|
||||
trigger16, 0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_17", (UCHAR) nam_i_segments,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger17), trigger17,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_18", (UCHAR) nam_i_segments,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger18),
|
||||
trigger18, 0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_19", (UCHAR) nam_indices,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger19), trigger19,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_20", (UCHAR) nam_indices,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger20),
|
||||
trigger20, 0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_21", (UCHAR) nam_trgs,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger21), trigger21,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_22", (UCHAR) nam_trgs,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger22),
|
||||
trigger22, 0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_23", (UCHAR) nam_r_fields,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_ERASE, sizeof(trigger23), trigger23,
|
||||
0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_24", (UCHAR) nam_r_fields,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger24),
|
||||
trigger24, 0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_27", (UCHAR) nam_r_fields,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger27),
|
||||
trigger27, 0, ODS_8_0 },
|
||||
{ "RDB$TRIGGER_34", (UCHAR) nam_rel_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger34),
|
||||
trigger34, TRG_ignore_perm, ODS_8_1 },
|
||||
{ "RDB$TRIGGER_35", (UCHAR) nam_chk_constr,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.POST_ERASE, sizeof(trigger35),
|
||||
trigger35, TRG_ignore_perm, ODS_8_1 },
|
||||
{ "RDB$TRIGGER_36", (UCHAR) nam_fields,
|
||||
RDB$TRIGGERS.RDB$TRIGGER_TYPE.PRE_MODIFY, sizeof(trigger36),
|
||||
trigger36, 0, ODS_11_0 },
|
||||
{ 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
// this table is used in defining messages for system triggers
|
||||
|
||||
const trigger_msg trigger_messages[] =
|
||||
{
|
||||
{ "RDB$TRIGGER_9", 0, "grant_obj_notfound", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_9", 1, "grant_fld_notfound", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_9", 2, "grant_nopriv", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_9", 3, "nonsql_security_rel", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_9", 4, "nonsql_security_fld", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_9", 5, "grant_nopriv_on_base", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_1", 0, "existing_priv_mod", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_2", 0, "systrig_update", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_3", 0, "systrig_update", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_24", 1, "cnstrnt_fld_rename", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_23", 1, "cnstrnt_fld_del", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_22", 1, "check_trig_update", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_21", 1, "check_trig_del", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_20", 1, "integ_index_mod", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_20", 2, "integ_index_deactivate", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_20", 3, "integ_deactivate_primary", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_19", 1, "integ_index_del", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_18", 1, "integ_index_seg_mod", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_17", 1, "integ_index_seg_del", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_15", 1, "check_cnstrnt_del", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_14", 1, "check_cnstrnt_update", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_13", 1, "ref_cnstrnt_update", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_12", 1, "ref_cnstrnt_notfound", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_12", 2, "foreign_key_notfound", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_10", 1, "primary_key_ref", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_10", 2, "primary_key_notnull", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_25", 1, "rel_cnstrnt_update", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_26", 1, "constaint_on_view", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_26", 2, "invld_cnstrnt_type", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_26", 3, "primary_key_exists", ODS_8_0 },
|
||||
{ "RDB$TRIGGER_24", 2, "integ_index_seg_mod", ODS_11_0 },
|
||||
{ "RDB$TRIGGER_36", 1, "integ_index_seg_mod", ODS_11_0 },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
unsigned getLatestFormat(thread_db* tdbb, int relId, int maxFieldId)
|
||||
{
|
||||
const auto relation = MET_relation(tdbb, relId);
|
||||
@ -730,11 +602,9 @@ static void store_generator(thread_db*, const gen*, AutoRequest&, NonRelationSec
|
||||
static void store_global_field(thread_db*, const gfld*, AutoRequest&, NonRelationSecurity&);
|
||||
static void store_indices(thread_db*, USHORT = 0);
|
||||
static void store_intlnames(thread_db*, NonRelationSecurity&);
|
||||
static void store_message(thread_db*, const trigger_msg*, AutoRequest&);
|
||||
static void store_relation(thread_db*, int, const char*, int, int, AutoRequest&, RelationSecurity&);
|
||||
static void store_relation_field(thread_db*, int, const char*, const char*, const char*, int, AutoRequest&);
|
||||
static void store_packages(thread_db*, NonRelationSecurity&, USHORT = 0);
|
||||
static void store_trigger(thread_db*, const jrd_trg*, AutoRequest&);
|
||||
|
||||
|
||||
//
|
||||
@ -779,6 +649,8 @@ void INI_format(thread_db* tdbb, const string& charset)
|
||||
|
||||
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
|
||||
{
|
||||
const bool isVirtual = (relfld[RFLD_R_TYPE] == rel_virtual);
|
||||
bool needsRdbRuntime = false;
|
||||
int fieldId = 0;
|
||||
|
||||
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
|
||||
@ -790,6 +662,9 @@ void INI_format(thread_db* tdbb, const string& charset)
|
||||
const auto globalName = names[gfield->gfld_name];
|
||||
const auto updateFlag = fld[RFLD_F_UPDATE];
|
||||
|
||||
if (!isVirtual && (gfield->gfld_dflt_blr || !gfield->gfld_nullable))
|
||||
needsRdbRuntime = true;
|
||||
|
||||
store_relation_field(tdbb, fieldId, relName, fieldName, globalName,
|
||||
updateFlag, handle2);
|
||||
++fieldId;
|
||||
@ -800,6 +675,13 @@ void INI_format(thread_db* tdbb, const string& charset)
|
||||
const auto relType = relfld[RFLD_R_TYPE];
|
||||
|
||||
store_relation(tdbb, relId, relName, fieldId, relType, handle, relSec);
|
||||
|
||||
if (needsRdbRuntime)
|
||||
{
|
||||
dsc desc;
|
||||
desc.makeText(static_cast<USHORT>(strlen(relName)), CS_METADATA, (UCHAR*) relName);
|
||||
DFW_post_work(transaction, dfw_update_format, &desc, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -896,20 +778,6 @@ void INI_format(thread_db* tdbb, const string& charset)
|
||||
// Adjust the value of the hidden generator RDB$GENERATORS
|
||||
DPM_gen_id(tdbb, 0, true, FB_NELEM(generators) - 1);
|
||||
|
||||
// Store system-defined triggers
|
||||
|
||||
handle.reset();
|
||||
|
||||
for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger)
|
||||
store_trigger(tdbb, trigger, handle);
|
||||
|
||||
// Store trigger messages to go with triggers
|
||||
|
||||
handle.reset();
|
||||
|
||||
for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message)
|
||||
store_message(tdbb, message, handle);
|
||||
|
||||
// Create system packages
|
||||
|
||||
// Reset nonRelSec for package permissions, it should be its last usage in this function
|
||||
@ -952,22 +820,6 @@ void INI_format(thread_db* tdbb, const string& charset)
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Return the trigger flags for a system trigger
|
||||
//
|
||||
|
||||
USHORT INI_get_trig_flags(const MetaName& triggerName)
|
||||
{
|
||||
for (const jrd_trg* trig = triggers; trig->trg_length > 0; trig++)
|
||||
{
|
||||
if (triggerName == trig->trg_name)
|
||||
return trig->trg_flags;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Initialize in-memory meta data
|
||||
//
|
||||
@ -989,17 +841,6 @@ void INI_init(thread_db* tdbb)
|
||||
relation->rel_flags |= MET_get_rel_flags_from_TYPE(relfld[RFLD_R_TYPE]);
|
||||
relation->rel_name = names[relfld[RFLD_R_NAME]];
|
||||
|
||||
// Set a flag if their is a trigger on the relation. Later we may need to compile it.
|
||||
|
||||
for (const jrd_trg* trigger = triggers; trigger->trg_relation; trigger++)
|
||||
{
|
||||
if (relation->rel_name == names[trigger->trg_relation])
|
||||
{
|
||||
relation->rel_flags |= REL_sys_triggers;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
HalfStaticArray<const char*, 64> fieldNames;
|
||||
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
|
||||
{
|
||||
@ -1102,6 +943,30 @@ void INI_init(thread_db* tdbb)
|
||||
}
|
||||
|
||||
|
||||
// Rescan system relations that have fields with default values.
|
||||
void INI_init_sys_relations(thread_db* tdbb)
|
||||
{
|
||||
const int* fld;
|
||||
|
||||
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
|
||||
{
|
||||
jrd_rel* relation = MET_relation(tdbb, relfld[RFLD_R_ID]);
|
||||
bool needsRdbRuntime = false;
|
||||
|
||||
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
|
||||
{
|
||||
const auto* const gfield = &gfields[fld[RFLD_F_ID]];
|
||||
|
||||
if (!relation->isVirtual() && (gfield->gfld_dflt_blr || !gfield->gfld_nullable))
|
||||
needsRdbRuntime = true;
|
||||
}
|
||||
|
||||
if (needsRdbRuntime)
|
||||
MET_scan_relation(tdbb, relation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Load system objects into DSQL metadata cache
|
||||
//
|
||||
@ -1373,26 +1238,6 @@ void INI_upgrade(thread_db* tdbb)
|
||||
context = "indices";
|
||||
store_indices(tdbb, odsVersion);
|
||||
|
||||
// Create new system triggers and their trigger messages
|
||||
|
||||
context = "triggers";
|
||||
handle.reset();
|
||||
|
||||
for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger)
|
||||
{
|
||||
if (trigger->trg_ods_version > odsVersion)
|
||||
store_trigger(tdbb, trigger, handle);
|
||||
}
|
||||
|
||||
context = "trigger messages";
|
||||
handle.reset();
|
||||
|
||||
for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message)
|
||||
{
|
||||
if (message->trg_ods_version > odsVersion)
|
||||
store_message(tdbb, message, handle);
|
||||
}
|
||||
|
||||
// Create new system generators
|
||||
|
||||
context = "generators";
|
||||
@ -1944,22 +1789,6 @@ static void store_intlnames(thread_db* tdbb, NonRelationSecurity& security)
|
||||
}
|
||||
|
||||
|
||||
static void store_message(thread_db* tdbb, const trigger_msg* message, AutoRequest& handle)
|
||||
{
|
||||
const auto attachment = tdbb->getAttachment();
|
||||
const auto transaction = tdbb->getTransaction();
|
||||
|
||||
STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
|
||||
X IN RDB$TRIGGER_MESSAGES
|
||||
{
|
||||
PAD(message->trigmsg_name, X.RDB$TRIGGER_NAME);
|
||||
X.RDB$MESSAGE_NUMBER = message->trigmsg_number;
|
||||
PAD(message->trigmsg_text, X.RDB$MESSAGE);
|
||||
}
|
||||
END_STORE
|
||||
}
|
||||
|
||||
|
||||
static void store_relation(thread_db* tdbb,
|
||||
int relId,
|
||||
const char* relName,
|
||||
@ -2226,36 +2055,3 @@ static void store_packages(thread_db* tdbb, NonRelationSecurity& security, USHOR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, AutoRequest& handle)
|
||||
{
|
||||
const auto attachment = tdbb->getAttachment();
|
||||
const auto transaction = tdbb->getTransaction();
|
||||
|
||||
// Indicate that the relation format needs revising
|
||||
|
||||
const auto triggerName = names[trigger->trg_relation];
|
||||
|
||||
dsc desc;
|
||||
desc.makeText(static_cast<USHORT>(strlen(triggerName)), CS_METADATA,
|
||||
(UCHAR*) triggerName);
|
||||
DFW_post_work(transaction, dfw_update_format, &desc, 0);
|
||||
|
||||
// Store the trigger
|
||||
|
||||
STORE(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
|
||||
X IN RDB$TRIGGERS
|
||||
{
|
||||
PAD(trigger->trg_name, X.RDB$TRIGGER_NAME);
|
||||
PAD(names[trigger->trg_relation], X.RDB$RELATION_NAME);
|
||||
X.RDB$TRIGGER_SEQUENCE = 0;
|
||||
X.RDB$SYSTEM_FLAG = RDB_system;
|
||||
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
||||
X.RDB$TRIGGER_TYPE = trigger->trg_type;
|
||||
X.RDB$FLAGS = trigger->trg_flags;
|
||||
attachment->storeBinaryBlob(tdbb, transaction, &X.RDB$TRIGGER_BLR,
|
||||
ByteChunk(trigger->trg_blr, trigger->trg_length));
|
||||
}
|
||||
END_STORE
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ namespace Jrd {
|
||||
}
|
||||
|
||||
void INI_format(Jrd::thread_db*, const Firebird::string&);
|
||||
USHORT INI_get_trig_flags(const Jrd::MetaName&);
|
||||
void INI_init(Jrd::thread_db*);
|
||||
void INI_init_sys_relations(Jrd::thread_db*);
|
||||
void INI_init_dsql(Jrd::thread_db*, Jrd::dsql_dbb* database);
|
||||
Firebird::string INI_owner_privileges();
|
||||
void INI_upgrade(Jrd::thread_db*);
|
||||
|
@ -54,7 +54,6 @@ enum irq_type_t
|
||||
irq_l_funct_blr, // lookup function BLR and debug info
|
||||
irq_l_args, // lookup function arguments
|
||||
irq_s_triggers, // scan triggers
|
||||
irq_s_triggers2, // scan triggers
|
||||
irq_s_msgs, // search for message
|
||||
irq_grant1, // process grant option
|
||||
irq_grant2, // process grant option
|
||||
|
@ -955,15 +955,7 @@ void Trigger::release(thread_db* tdbb)
|
||||
{
|
||||
extTrigger.reset();
|
||||
|
||||
// dimitr: We should never release triggers created by MET_parse_sys_trigger().
|
||||
// System triggers do have BLR, but it's not stored inside the trigger object.
|
||||
// However, triggers backing RI constraints are also marked as system,
|
||||
// but they are loaded in a regular way and their BLR is present here.
|
||||
// This is why we cannot simply check for sysTrigger, sigh.
|
||||
|
||||
const bool sysTableTrigger = (blr.isEmpty() && engine.isEmpty());
|
||||
|
||||
if (sysTableTrigger || !statement || statement->isActive() || releaseInProgress)
|
||||
if (!statement || statement->isActive() || releaseInProgress)
|
||||
return;
|
||||
|
||||
AutoSetRestore<bool> autoProgressFlag(&releaseInProgress, true);
|
||||
@ -1904,6 +1896,8 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
|
||||
|
||||
PAG_attachment_id(tdbb);
|
||||
|
||||
INI_init_sys_relations(tdbb);
|
||||
|
||||
bool cleanupTransactions = false;
|
||||
|
||||
if (!options.dpb_verify && CCH_exclusive(tdbb, LCK_PW, LCK_NO_WAIT, NULL))
|
||||
|
@ -205,8 +205,10 @@ private:
|
||||
//
|
||||
// Flags to indicate normal internal requests vs. dyn internal requests
|
||||
//
|
||||
// IRQ_REQUESTS and DYN_REQUESTS are deprecated
|
||||
const int IRQ_REQUESTS = 1;
|
||||
const int DYN_REQUESTS = 2;
|
||||
const int CACHED_REQUESTS = 3;
|
||||
|
||||
|
||||
// Procedure block
|
||||
|
134
src/jrd/met.epp
134
src/jrd/met.epp
@ -1928,9 +1928,6 @@ void MET_load_trigger(thread_db* tdbb,
|
||||
|
||||
if (relation)
|
||||
{
|
||||
if (relation->rel_flags & REL_sys_trigs_being_loaded)
|
||||
return;
|
||||
|
||||
// No need to load table triggers for ReadOnly databases,
|
||||
// since INSERT/DELETE/UPDATE statements are not going to be allowed
|
||||
// hvlad: GTT with ON COMMIT DELETE ROWS clause is writable
|
||||
@ -3213,111 +3210,6 @@ DmlNode* MET_parse_blob(thread_db* tdbb,
|
||||
}
|
||||
|
||||
|
||||
void MET_parse_sys_trigger(thread_db* tdbb, jrd_rel* relation)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* M E T _ p a r s e _ s y s _ t r i g g e r
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Parse the blr for a system relation's triggers.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Attachment* attachment = tdbb->getAttachment();
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
relation->rel_flags &= ~REL_sys_triggers;
|
||||
|
||||
// Release any triggers in case of a rescan
|
||||
|
||||
relation->releaseTriggers(tdbb, true);
|
||||
|
||||
// No need to load triggers for ReadOnly databases, since
|
||||
// INSERT/DELETE/UPDATE statements are not going to be allowed
|
||||
// hvlad: GTT with ON COMMIT DELETE ROWS clause is writable
|
||||
|
||||
if (dbb->readOnly() && !(relation->rel_flags & REL_temp_tran))
|
||||
return;
|
||||
|
||||
relation->rel_flags |= REL_sys_trigs_being_loaded;
|
||||
|
||||
AutoCacheRequest request(tdbb, irq_s_triggers2, IRQ_REQUESTS);
|
||||
|
||||
FOR (REQUEST_HANDLE request)
|
||||
TRG IN RDB$TRIGGERS
|
||||
WITH TRG.RDB$RELATION_NAME = relation->rel_name.c_str()
|
||||
AND TRG.RDB$SYSTEM_FLAG = 1
|
||||
{
|
||||
const FB_UINT64 type = TRG.RDB$TRIGGER_TYPE;
|
||||
const USHORT trig_flags = TRG.RDB$FLAGS;
|
||||
const TEXT* name = TRG.RDB$TRIGGER_NAME;
|
||||
|
||||
TrigVector** ptr;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TRIGGER_PRE_STORE:
|
||||
ptr = &relation->rel_pre_store;
|
||||
break;
|
||||
case TRIGGER_POST_STORE:
|
||||
ptr = &relation->rel_post_store;
|
||||
break;
|
||||
case TRIGGER_PRE_MODIFY:
|
||||
ptr = &relation->rel_pre_modify;
|
||||
break;
|
||||
case TRIGGER_POST_MODIFY:
|
||||
ptr = &relation->rel_post_modify;
|
||||
break;
|
||||
case TRIGGER_PRE_ERASE:
|
||||
ptr = &relation->rel_pre_erase;
|
||||
break;
|
||||
case TRIGGER_POST_ERASE:
|
||||
ptr = &relation->rel_post_erase;
|
||||
break;
|
||||
default:
|
||||
ptr = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
blb* blob = blb::open(tdbb, attachment->getSysTransaction(), &TRG.RDB$TRIGGER_BLR);
|
||||
ULONG length = blob->blb_length + 10;
|
||||
HalfStaticArray<UCHAR, 128> blr;
|
||||
length = blob->BLB_get_data(tdbb, blr.getBuffer(length), length);
|
||||
|
||||
USHORT par_flags = (USHORT) ((trig_flags & TRG_ignore_perm) ? csb_ignore_perm : 0);
|
||||
if (type & 1)
|
||||
par_flags |= csb_pre_trigger;
|
||||
else
|
||||
par_flags |= csb_post_trigger;
|
||||
|
||||
Statement* statement = NULL;
|
||||
|
||||
{
|
||||
Jrd::ContextPoolHolder context(tdbb, attachment->createPool());
|
||||
PAR_blr(tdbb, relation, blr.begin(), length, NULL, NULL, &statement, true, par_flags);
|
||||
}
|
||||
|
||||
statement->triggerName = name;
|
||||
|
||||
statement->flags |= Statement::FLAG_SYS_TRIGGER | Statement::FLAG_INTERNAL;
|
||||
if (trig_flags & TRG_ignore_perm)
|
||||
statement->flags |= Statement::FLAG_IGNORE_PERM;
|
||||
|
||||
save_trigger_data(tdbb, ptr, relation, statement, NULL, NULL, NULL, type, true, 0, "",
|
||||
"", NULL, TriState());
|
||||
}
|
||||
}
|
||||
END_FOR
|
||||
|
||||
relation->rel_flags &= ~REL_sys_trigs_being_loaded;
|
||||
}
|
||||
|
||||
|
||||
void MET_post_existence(thread_db* tdbb, jrd_rel* relation)
|
||||
{
|
||||
/**************************************
|
||||
@ -3968,7 +3860,6 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Jrd::ContextPoolHolder context(tdbb, attachment->att_pool);
|
||||
bool dependencies = false;
|
||||
bool sys_triggers = false;
|
||||
|
||||
blb* blob = NULL;
|
||||
|
||||
@ -3985,8 +3876,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
|
||||
|
||||
relation->rel_flags |= REL_being_scanned;
|
||||
dependencies = (relation->rel_flags & REL_get_dependencies) ? true : false;
|
||||
sys_triggers = (relation->rel_flags & REL_sys_triggers) ? true : false;
|
||||
relation->rel_flags &= ~(REL_get_dependencies | REL_sys_triggers);
|
||||
relation->rel_flags &= ~REL_get_dependencies;
|
||||
|
||||
for (USHORT itr = 0; itr < TRIGGER_MAX; ++itr)
|
||||
triggers[itr] = NULL;
|
||||
@ -4274,17 +4164,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
|
||||
|
||||
// We have just loaded the triggers onto the local vector triggers.
|
||||
// It's now time to place them at their rightful place inside the relation block.
|
||||
|
||||
if (!(relation->rel_flags & REL_sys_trigs_being_loaded))
|
||||
{
|
||||
// if we are scanning a system relation during loading the system
|
||||
// triggers, (during parsing its blr actually), we must not release the
|
||||
// existing system triggers; because we have already set the
|
||||
// relation->rel_flag to not have REL_sys_trig, so these
|
||||
// system triggers will not get loaded again. This fixes bug 8149.
|
||||
|
||||
relation->replaceTriggers(tdbb, triggers);
|
||||
}
|
||||
relation->replaceTriggers(tdbb, triggers);
|
||||
|
||||
LCK_lock(tdbb, relation->rel_rescan_lock, LCK_SR, LCK_WAIT);
|
||||
relation->rel_flags &= ~REL_being_scanned;
|
||||
@ -4298,9 +4178,6 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
|
||||
if (dependencies) {
|
||||
relation->rel_flags |= REL_get_dependencies;
|
||||
}
|
||||
if (sys_triggers) {
|
||||
relation->rel_flags |= REL_sys_triggers;
|
||||
}
|
||||
if (blob)
|
||||
blob->BLB_close(tdbb);
|
||||
|
||||
@ -5305,7 +5182,7 @@ void MET_store_dependencies(thread_db* tdbb,
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
const Trigger* t = 0;
|
||||
const Trigger* t = nullptr;
|
||||
const bool checkTableScope =
|
||||
(dependency_type == obj_computed) ||
|
||||
(dependency_type == obj_trigger) && (dep_rel != 0) &&
|
||||
@ -5538,11 +5415,6 @@ static bool verify_TRG_ignore_perm(thread_db* tdbb, const MetaName& trig_name)
|
||||
SET_TDBB(tdbb);
|
||||
Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
// See if this is a system trigger, with the flag set as TRG_ignore_perm
|
||||
|
||||
if (INI_get_trig_flags(trig_name) & TRG_ignore_perm)
|
||||
return true;
|
||||
|
||||
// See if this is a RI trigger
|
||||
|
||||
AutoCacheRequest request(tdbb, irq_c_trg_perm, IRQ_REQUESTS);
|
||||
|
@ -118,7 +118,6 @@ Jrd::jrd_rel* MET_lookup_relation(Jrd::thread_db*, const Jrd::MetaName&);
|
||||
Jrd::jrd_rel* MET_lookup_relation_id(Jrd::thread_db*, SLONG, bool);
|
||||
Jrd::DmlNode* MET_parse_blob(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::bid*, Jrd::CompilerScratch**,
|
||||
Jrd::Statement**, bool, bool);
|
||||
void MET_parse_sys_trigger(Jrd::thread_db*, Jrd::jrd_rel*);
|
||||
void MET_post_existence(Jrd::thread_db*, Jrd::jrd_rel*);
|
||||
void MET_prepare(Jrd::thread_db*, Jrd::jrd_tra*, USHORT, const UCHAR*);
|
||||
Jrd::jrd_prc* MET_procedure(Jrd::thread_db*, USHORT, bool, USHORT);
|
||||
|
@ -242,6 +242,15 @@ int MOV_get_string(Jrd::thread_db* tdbb, const dsc* desc, UCHAR** address, vary*
|
||||
}
|
||||
|
||||
|
||||
void MOV_get_string(Jrd::thread_db* tdbb, const dsc* desc, string& str)
|
||||
{
|
||||
VaryStr<MAX_SQL_IDENTIFIER_SIZE> temp;
|
||||
const char* strPtr = NULL;
|
||||
const auto len = MOV_make_string(tdbb, desc, ttype_metadata, &strPtr, &temp, MAX_SQL_IDENTIFIER_SIZE);
|
||||
str.assign(strPtr, len);
|
||||
}
|
||||
|
||||
|
||||
GDS_DATE MOV_get_sql_date(const dsc* desc)
|
||||
{
|
||||
/**************************************
|
||||
|
@ -42,6 +42,7 @@ SQUAD MOV_get_quad(Jrd::thread_db*, const dsc*, SSHORT);
|
||||
SINT64 MOV_get_int64(Jrd::thread_db*, const dsc*, SSHORT);
|
||||
int MOV_get_string_ptr(Jrd::thread_db*, const dsc*, USHORT*, UCHAR**, vary*, USHORT);
|
||||
int MOV_get_string(Jrd::thread_db*, const dsc*, UCHAR**, vary*, USHORT);
|
||||
void MOV_get_string(Jrd::thread_db* tdbb, const dsc* desc, Firebird::string& str);
|
||||
GDS_DATE MOV_get_sql_date(const dsc*);
|
||||
GDS_TIME MOV_get_sql_time(const dsc*);
|
||||
ISC_TIME_TZ MOV_get_sql_time_tz(const dsc*);
|
||||
|
2008
src/jrd/trig.h
2008
src/jrd/trig.h
File diff suppressed because it is too large
Load Diff
@ -3363,6 +3363,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
|
||||
case rel_roles:
|
||||
case rel_ccon:
|
||||
case rel_pub_tables:
|
||||
case rel_priv:
|
||||
protect_system_table_delupd(tdbb, relation, "UPDATE");
|
||||
break;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user