mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 04:43:03 +01:00
1. Allow to create FK constraints without exclusive database locking
2. Fix 'partner index not found' error when one process dropped FK and another trying to delete master record 3. misc changes in vio.cpp
This commit is contained in:
parent
e2c905c769
commit
0bc1c4bf49
@ -2393,6 +2393,10 @@ void CMP_shutdown_database(thread_db* tdbb)
|
||||
relation->rel_flags |= REL_check_existence;
|
||||
relation->rel_use_count = 0;
|
||||
}
|
||||
if (relation->rel_partners_lock) {
|
||||
LCK_release(tdbb, relation->rel_partners_lock);
|
||||
relation->rel_flags |= REL_check_partners;
|
||||
}
|
||||
for (IndexLock* index = relation->rel_index_locks; index;
|
||||
index = index->idl_next)
|
||||
{
|
||||
|
245
src/jrd/dfw.epp
245
src/jrd/dfw.epp
@ -98,6 +98,7 @@
|
||||
#include "../jrd/pag_proto.h"
|
||||
#include "../jrd/pcmet_proto.h"
|
||||
#include "../jrd/os/pio_proto.h"
|
||||
#include "../jrd/rlck_proto.h"
|
||||
#include "../jrd/sch_proto.h"
|
||||
#include "../jrd/scl_proto.h"
|
||||
#include "../jrd/sdw_proto.h"
|
||||
@ -166,6 +167,9 @@ static bool add_difference(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||
static bool delete_difference(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||
static bool begin_backup(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||
static bool end_backup(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||
static Lock* protect_relation(thread_db*, jrd_tra*, jrd_rel*, bool&);
|
||||
static void release_protect_lock(thread_db*, jrd_tra*, Lock*);
|
||||
static void check_partners(thread_db*, const USHORT);
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
@ -1511,7 +1515,6 @@ static bool create_index( thread_db* tdbb,
|
||||
END_FOR;
|
||||
|
||||
CMP_release(tdbb, handle);
|
||||
CCH_release_exclusive(tdbb);
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
@ -1705,69 +1708,96 @@ static bool create_index( thread_db* tdbb,
|
||||
|
||||
/* Actually create the index */
|
||||
|
||||
Lock *relationLock = NULL, *partnerLock = NULL;
|
||||
bool releaseRelationLock = false, releasePartnerLock = false;
|
||||
partner_relation = NULL;
|
||||
if (idx.idx_flags & idx_foreign)
|
||||
try
|
||||
{
|
||||
/* Get an exclusive lock on the database if the index being
|
||||
defined enforces a foreign key constraint. This will prevent
|
||||
the constraint from being violated during index construction. */
|
||||
|
||||
if (MET_lookup_partner(tdbb, relation, &idx, work->dfw_name.c_str()) &&
|
||||
(partner_relation =
|
||||
MET_lookup_relation_id( tdbb,
|
||||
idx.idx_primary_relation,
|
||||
true)) &&
|
||||
!CCH_exclusive(tdbb, LCK_EX, LCK_NO_WAIT))
|
||||
if (idx.idx_flags & idx_foreign)
|
||||
{
|
||||
ERR_post(isc_no_meta_update,
|
||||
isc_arg_gds, isc_obj_in_use,
|
||||
isc_arg_string, partner_relation->rel_name.c_str(),
|
||||
0);
|
||||
|
||||
/* CVC: Currently, the server doesn't enforce FK creation more than at DYN level.
|
||||
If DYN is bypassed, then FK creation succeeds and operation will fail at run-time.
|
||||
The aim is to check REFERENCES at DDL time instead of DML time and behave accordingly
|
||||
to ANSI SQL rules for REFERENCES rights.
|
||||
For testing purposes, I'm calling SCL_check_index, although most of the DFW ops are
|
||||
carried using internal metadata structures that are refreshed from system tables. */
|
||||
|
||||
if (partner_relation)
|
||||
if (MET_lookup_partner(tdbb, relation, &idx, work->dfw_name.c_str()) &&
|
||||
(partner_relation =
|
||||
MET_lookup_relation_id(tdbb, idx.idx_primary_relation, true)) )
|
||||
{
|
||||
/* Don't bother if the master's owner is the same than the detail's owner.
|
||||
If both tables aren't defined in the same session, partner_relation->rel_owner_name
|
||||
won't be loaded hence, we need to be careful about null pointers. */
|
||||
|
||||
if (relation->rel_owner_name.length() == 0 ||
|
||||
partner_relation->rel_owner_name.length() == 0 ||
|
||||
relation->rel_owner_name != partner_relation->rel_owner_name)
|
||||
// Get an protected_read lock on the both relations if the index being
|
||||
// defined enforces a foreign key constraint. This will prevent
|
||||
// the constraint from being violated during index construction.
|
||||
|
||||
relationLock = protect_relation(tdbb, transaction, relation, releaseRelationLock);
|
||||
partnerLock = protect_relation(tdbb, transaction, partner_relation, releasePartnerLock);
|
||||
|
||||
int bad_segment;
|
||||
if (!IDX_check_master_types(tdbb, idx, partner_relation, bad_segment))
|
||||
{
|
||||
SCL_check_index(tdbb, partner_relation->rel_name, idx.idx_id + 1, SCL_sql_references);
|
||||
ERR_post(isc_no_meta_update,
|
||||
isc_arg_gds, isc_partner_idx_incompat_type,
|
||||
isc_arg_number, bad_segment + 1,
|
||||
0);
|
||||
}
|
||||
|
||||
/* hvlad: this code was never called but i preserve it for Claudio review and decision
|
||||
|
||||
// CVC: Currently, the server doesn't enforce FK creation more than at DYN level.
|
||||
// If DYN is bypassed, then FK creation succeeds and operation will fail at run-time.
|
||||
// The aim is to check REFERENCES at DDL time instead of DML time and behave accordingly
|
||||
// to ANSI SQL rules for REFERENCES rights.
|
||||
// For testing purposes, I'm calling SCL_check_index, although most of the DFW ops are
|
||||
// carried using internal metadata structures that are refreshed from system tables.
|
||||
|
||||
if (partner_relation)
|
||||
{
|
||||
// Don't bother if the master's owner is the same than the detail's owner.
|
||||
// If both tables aren't defined in the same session, partner_relation->rel_owner_name
|
||||
// won't be loaded hence, we need to be careful about null pointers.
|
||||
|
||||
if (relation->rel_owner_name.length() == 0 ||
|
||||
partner_relation->rel_owner_name.length() == 0 ||
|
||||
relation->rel_owner_name != partner_relation->rel_owner_name)
|
||||
{
|
||||
SCL_check_index(tdbb, partner_relation->rel_name, idx.idx_id + 1, SCL_sql_references);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
int bad_segment;
|
||||
if (!IDX_check_master_types(tdbb, idx, partner_relation, bad_segment))
|
||||
|
||||
fb_assert(work->dfw_id == dbb->dbb_max_idx);
|
||||
SelectivityList selectivity(*tdbb->getDefaultPool());
|
||||
IDX_create_index(tdbb, relation, &idx, work->dfw_name.c_str(),
|
||||
&work->dfw_id, transaction, selectivity);
|
||||
fb_assert(work->dfw_id == idx.idx_id);
|
||||
DFW_update_index(work->dfw_name.c_str(), idx.idx_id, selectivity);
|
||||
|
||||
if (partner_relation)
|
||||
{
|
||||
ERR_post(isc_no_meta_update,
|
||||
isc_arg_gds, isc_partner_idx_incompat_type,
|
||||
isc_arg_number, bad_segment + 1,
|
||||
0);
|
||||
relation->rel_flags |= REL_check_partners;
|
||||
|
||||
// signal to other processes about new constraint
|
||||
LCK_convert_non_blocking(tdbb, relation->rel_partners_lock, LCK_EX, LCK_WAIT);
|
||||
LCK_release(tdbb, relation->rel_partners_lock);
|
||||
|
||||
if (relation != partner_relation) {
|
||||
partner_relation->rel_flags |= REL_check_partners;
|
||||
LCK_convert_non_blocking(tdbb, partner_relation->rel_partners_lock, LCK_EX, LCK_WAIT);
|
||||
LCK_release(tdbb, partner_relation->rel_partners_lock);
|
||||
}
|
||||
}
|
||||
if (relationLock && releaseRelationLock) {
|
||||
release_protect_lock(tdbb, transaction, relationLock);
|
||||
}
|
||||
if (partnerLock && releasePartnerLock) {
|
||||
release_protect_lock(tdbb, transaction, partnerLock);
|
||||
}
|
||||
}
|
||||
|
||||
fb_assert(work->dfw_id == dbb->dbb_max_idx);
|
||||
SelectivityList selectivity(*tdbb->getDefaultPool());
|
||||
IDX_create_index(tdbb, relation, &idx, work->dfw_name.c_str(),
|
||||
&work->dfw_id, transaction, selectivity);
|
||||
fb_assert(work->dfw_id == idx.idx_id);
|
||||
DFW_update_index(work->dfw_name.c_str(), idx.idx_id, selectivity);
|
||||
|
||||
if (partner_relation)
|
||||
catch(const std::exception&)
|
||||
{
|
||||
relation->rel_flags |= REL_check_partners;
|
||||
partner_relation->rel_flags |= REL_check_partners;
|
||||
CCH_release_exclusive(tdbb);
|
||||
if (relationLock && releaseRelationLock) {
|
||||
release_protect_lock(tdbb, transaction, relationLock);
|
||||
}
|
||||
if (partnerLock && releasePartnerLock) {
|
||||
release_protect_lock(tdbb, transaction, partnerLock);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -2304,6 +2334,34 @@ static bool delete_global(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
}
|
||||
|
||||
|
||||
static void check_partners(thread_db* tdbb, const USHORT rel_id)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* c h e c k _ p a r t n e r s
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Signal other processes to check partners of relation rel_id
|
||||
* Used when FK index was dropped
|
||||
*
|
||||
**************************************/
|
||||
const Database* dbb = tdbb->tdbb_database;
|
||||
vec* relations = dbb->dbb_relations;
|
||||
|
||||
fb_assert(relations);
|
||||
fb_assert(rel_id < relations->count());
|
||||
|
||||
jrd_rel *relation = (jrd_rel*) (*relations)[rel_id];
|
||||
fb_assert(relation);
|
||||
|
||||
LCK_lock_non_blocking(tdbb, relation->rel_partners_lock, LCK_EX, LCK_WAIT);
|
||||
LCK_release(tdbb, relation->rel_partners_lock);
|
||||
relation->rel_flags |= REL_check_partners;
|
||||
}
|
||||
|
||||
|
||||
static bool delete_index(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
jrd_tra* transaction)
|
||||
{
|
||||
@ -2389,7 +2447,22 @@ static bool delete_index(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
work->dfw_name,
|
||||
obj_expression_index);
|
||||
}
|
||||
MET_update_partners(tdbb);
|
||||
|
||||
// if index was bound to deleted FK constraint
|
||||
// then work->dfw_args was set in VIO_erase
|
||||
if (work->dfw_args) {
|
||||
if (work->dfw_args->dfw_id) {
|
||||
check_partners(tdbb, relation->rel_id);
|
||||
if (relation->rel_id != work->dfw_args->dfw_id) {
|
||||
check_partners(tdbb, work->dfw_args->dfw_id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// partner relation was not found in VIO_erase
|
||||
// we must check partners of all relations in database
|
||||
MET_update_partners(tdbb);
|
||||
}
|
||||
}
|
||||
|
||||
if (index)
|
||||
{
|
||||
@ -2792,6 +2865,9 @@ static bool delete_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
if (relation->rel_existence_lock) {
|
||||
LCK_release(tdbb, relation->rel_existence_lock);
|
||||
}
|
||||
if (relation->rel_partners_lock) {
|
||||
LCK_release(tdbb, relation->rel_partners_lock);
|
||||
}
|
||||
request = NULL;
|
||||
|
||||
FOR(REQUEST_HANDLE request) X IN RDB$FORMATS WITH
|
||||
@ -4157,6 +4233,50 @@ static void put_summary_blob(blb* blob, RSR_T type, bid* blob_id)
|
||||
}
|
||||
|
||||
|
||||
static Lock* protect_relation(thread_db* tdbb, jrd_tra* transaction, jrd_rel* relation, bool& releaseLock)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p r o t e c t _ r e l a t i o n
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Lock relation with protected_read level or raise existing relation lock
|
||||
* to this level to ensure nobody can write to this relation.
|
||||
* Used when new FK index to be build.
|
||||
* releaseLock set to true if there was no existing lock before
|
||||
*
|
||||
**************************************/
|
||||
Lock* relLock = RLCK_transaction_relation_lock(transaction, relation);
|
||||
|
||||
releaseLock = (relLock->lck_logical == LCK_none);
|
||||
|
||||
bool inUse = false;
|
||||
|
||||
if (!releaseLock) {
|
||||
if ( (relLock->lck_logical < LCK_PR) &&
|
||||
!LCK_convert_non_blocking(tdbb, relLock, LCK_PR, transaction->getLockWait()) ) {
|
||||
inUse = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( !LCK_lock_non_blocking(tdbb, relLock, LCK_PR, transaction->getLockWait()) ) {
|
||||
inUse = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (inUse ) {
|
||||
ERR_post(isc_no_meta_update,
|
||||
isc_arg_gds, isc_obj_in_use,
|
||||
isc_arg_string, relation->rel_name.c_str(),
|
||||
0);
|
||||
}
|
||||
|
||||
return relLock;
|
||||
}
|
||||
|
||||
|
||||
static void put_summary_record(blb* blob,
|
||||
RSR_T type,
|
||||
const UCHAR* data,
|
||||
@ -4203,6 +4323,25 @@ static void put_summary_record(blb* blob,
|
||||
}
|
||||
|
||||
|
||||
static void release_protect_lock(thread_db* tdbb, jrd_tra* transaction, Lock* relLock)
|
||||
{
|
||||
vec* vector = transaction->tra_relation_locks;
|
||||
if (vector) {
|
||||
vec::iterator lock = vector->begin();
|
||||
for (ULONG i = 0; i < vector->count();
|
||||
i++, lock++)
|
||||
{
|
||||
if ((Lock*)*lock == relLock)
|
||||
{
|
||||
LCK_release(tdbb, relLock);
|
||||
*lock = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool scan_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
jrd_tra* transaction)
|
||||
{
|
||||
|
@ -744,6 +744,7 @@ public:
|
||||
Lock* rel_existence_lock; /* existence lock, if any */
|
||||
Lock* rel_interest_lock; /* interest lock to ensure compatibility of relation and record locks */
|
||||
Lock* rel_record_locking; /* lock to start record locking on relation */
|
||||
Lock* rel_partners_lock; /* partners lock */
|
||||
|
||||
ULONG rel_explicit_locks; /* count of records explicitly locked in relation */
|
||||
ULONG rel_read_locks; /* count of records read locked in relation (implicit or explicit) */
|
||||
|
@ -535,6 +535,7 @@ SLONG LCK_get_owner_handle(thread_db* tdbb, enum lck_t lock_type)
|
||||
case LCK_database:
|
||||
case LCK_bdb:
|
||||
case LCK_rel_exist:
|
||||
case LCK_rel_partners:
|
||||
case LCK_idx_exist:
|
||||
case LCK_shadow:
|
||||
case LCK_retaining:
|
||||
|
@ -52,7 +52,8 @@ enum lck_t {
|
||||
LCK_update_shadow, /* shadow update sync lock */
|
||||
LCK_backup_state, /* Lock to synchronize for objects depending on backup status */
|
||||
LCK_backup_alloc, /* Lock for page allocation table in backup spare file */
|
||||
LCK_backup_database /* Lock to protect writing to database file */
|
||||
LCK_backup_database, /* Lock to protect writing to database file */
|
||||
LCK_rel_partners /* Relation partners lock */
|
||||
};
|
||||
|
||||
/* Lock owner types */
|
||||
|
@ -117,6 +117,7 @@ using namespace Jrd;
|
||||
|
||||
static int blocking_ast_procedure(void*);
|
||||
static int blocking_ast_relation(void*);
|
||||
static int partners_ast_relation(void*);
|
||||
static void get_trigger(thread_db*, jrd_rel*, bid*, trig_vec**, const TEXT*, UCHAR, bool, USHORT);
|
||||
static bool get_type(thread_db*, SSHORT*, const UCHAR*, const TEXT*);
|
||||
static void lookup_view_contexts(thread_db*, jrd_rel*);
|
||||
@ -209,6 +210,10 @@ void MET_update_partners(thread_db* tdbb)
|
||||
if (!relation) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// signal other processes
|
||||
LCK_lock_non_blocking(tdbb, relation->rel_partners_lock, LCK_EX, LCK_WAIT);
|
||||
LCK_release(tdbb, relation->rel_partners_lock);
|
||||
relation->rel_flags |= REL_check_partners;
|
||||
}
|
||||
}
|
||||
@ -1963,6 +1968,7 @@ bool MET_lookup_partner(thread_db* tdbb,
|
||||
if (!REQUEST(irq_foreign2))
|
||||
REQUEST(irq_foreign2) = request;
|
||||
|
||||
LCK_lock(tdbb, relation->rel_partners_lock, LCK_SR, LCK_WAIT);
|
||||
relation->rel_flags &= ~REL_check_partners;
|
||||
}
|
||||
|
||||
@ -2237,6 +2243,11 @@ jrd_rel* MET_lookup_relation(thread_db* tdbb, const Firebird::MetaName& name)
|
||||
|
||||
if (relation->rel_name == name)
|
||||
{
|
||||
if (relation->rel_flags & REL_check_partners)
|
||||
{
|
||||
LCK_lock(tdbb, relation->rel_partners_lock,
|
||||
LCK_SR, LCK_WAIT);
|
||||
}
|
||||
if (relation->rel_flags & REL_check_existence)
|
||||
{
|
||||
check_relation = relation;
|
||||
@ -2282,7 +2293,9 @@ jrd_rel* MET_lookup_relation(thread_db* tdbb, const Firebird::MetaName& name)
|
||||
check_relation->rel_flags &= ~REL_check_existence;
|
||||
if (check_relation != relation) {
|
||||
LCK_release(tdbb, check_relation->rel_existence_lock);
|
||||
LCK_release(tdbb, check_relation->rel_partners_lock);
|
||||
check_relation->rel_flags |= REL_deleted;
|
||||
check_relation->rel_flags &= ~REL_check_partners;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2325,14 +2338,21 @@ jrd_rel* MET_lookup_relation_id(thread_db* tdbb, SLONG id, bool return_deleted)
|
||||
return relation;
|
||||
return NULL;
|
||||
}
|
||||
else if (relation->rel_flags & REL_check_existence)
|
||||
{
|
||||
check_relation = relation;
|
||||
LCK_lock(tdbb, check_relation->rel_existence_lock, LCK_SR, LCK_WAIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
return relation;
|
||||
if (relation->rel_flags & REL_check_partners)
|
||||
{
|
||||
LCK_lock(tdbb, relation->rel_partners_lock, LCK_SR, LCK_WAIT);
|
||||
}
|
||||
if (relation->rel_flags & REL_check_existence)
|
||||
{
|
||||
check_relation = relation;
|
||||
LCK_lock(tdbb, check_relation->rel_existence_lock, LCK_SR, LCK_WAIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
return relation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2360,7 +2380,9 @@ jrd_rel* MET_lookup_relation_id(thread_db* tdbb, SLONG id, bool return_deleted)
|
||||
check_relation->rel_flags &= ~REL_check_existence;
|
||||
if (check_relation != relation) {
|
||||
LCK_release(tdbb, check_relation->rel_existence_lock);
|
||||
LCK_release(tdbb, check_relation->rel_partners_lock);
|
||||
check_relation->rel_flags |= REL_deleted;
|
||||
check_relation->rel_flags &= ~REL_check_partners;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2922,11 +2944,25 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id)
|
||||
(*vector)[id] = relation;
|
||||
relation->rel_id = id;
|
||||
|
||||
{
|
||||
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
|
||||
relation->rel_partners_lock = lock;
|
||||
lock->lck_parent = dbb->dbb_lock;
|
||||
lock->lck_dbb = dbb;
|
||||
lock->lck_key.lck_long = relation->rel_id;
|
||||
lock->lck_length = sizeof(lock->lck_key.lck_long);
|
||||
lock->lck_type = LCK_rel_partners;
|
||||
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
|
||||
lock->lck_object = relation;
|
||||
lock->lck_ast = partners_ast_relation;
|
||||
}
|
||||
|
||||
// This should check system flag instead.
|
||||
if (relation->rel_id <= max_sys_rel) {
|
||||
return relation;
|
||||
}
|
||||
|
||||
{
|
||||
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
|
||||
relation->rel_existence_lock = lock;
|
||||
lock->lck_parent = dbb->dbb_lock;
|
||||
@ -2937,6 +2973,7 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id)
|
||||
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
|
||||
lock->lck_object = relation;
|
||||
lock->lck_ast = blocking_ast_relation;
|
||||
}
|
||||
|
||||
relation->rel_flags |= (REL_check_existence | REL_check_partners);
|
||||
return relation;
|
||||
@ -3777,6 +3814,35 @@ static int blocking_ast_relation(void* ast_object)
|
||||
}
|
||||
|
||||
|
||||
static int partners_ast_relation(void* ast_object)
|
||||
{
|
||||
jrd_rel* relation = static_cast<jrd_rel*>(ast_object);
|
||||
thread_db thd_context, *tdbb;
|
||||
|
||||
/* Since this routine will be called asynchronously, we must establish
|
||||
a thread context. */
|
||||
|
||||
JRD_set_thread_data(tdbb, thd_context);
|
||||
|
||||
fb_assert(relation->rel_partners_lock);
|
||||
|
||||
tdbb->tdbb_database = relation->rel_partners_lock->lck_dbb;
|
||||
tdbb->tdbb_attachment = relation->rel_partners_lock->lck_attachment;
|
||||
tdbb->tdbb_quantum = QUANTUM;
|
||||
tdbb->tdbb_request = NULL;
|
||||
tdbb->tdbb_transaction = NULL;
|
||||
Jrd::ContextPoolHolder context(tdbb, 0);
|
||||
|
||||
relation->rel_flags |= REL_check_partners;
|
||||
LCK_release(tdbb, relation->rel_partners_lock);
|
||||
|
||||
/* Restore the prior thread context */
|
||||
|
||||
JRD_restore_thread_data();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void get_trigger(thread_db* tdbb, jrd_rel* relation,
|
||||
bid* blob_id, trig_vec** ptr,
|
||||
const TEXT* name, UCHAR type,
|
||||
|
@ -69,6 +69,7 @@
|
||||
#endif
|
||||
#include "../jrd/all_proto.h"
|
||||
#include "../jrd/blb_proto.h"
|
||||
#include "../jrd/btr_proto.h"
|
||||
#include "../jrd/cch_proto.h"
|
||||
#include "../jrd/dbg_proto.h"
|
||||
#include "../jrd/dfw_proto.h"
|
||||
@ -1267,9 +1268,10 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
|
||||
if (!(transaction->tra_flags & TRA_system))
|
||||
{
|
||||
const jrd_rel* r2;
|
||||
jrd_rel* r2;
|
||||
const jrd_prc* procedure;
|
||||
USHORT id;
|
||||
DeferredWork* work;
|
||||
|
||||
switch ((RIDS) relation->rel_id)
|
||||
{
|
||||
@ -1323,12 +1325,40 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
if ( (id = MOV_get_long(&desc2, 0)) ) {
|
||||
if (EVL_field(0, rpb->rpb_record, f_idx_exp_blr, &desc2))
|
||||
{
|
||||
DFW_post_work(transaction, dfw_delete_expression_index,
|
||||
work = DFW_post_work(transaction, dfw_delete_expression_index,
|
||||
&desc, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DFW_post_work(transaction, dfw_delete_index, &desc, id);
|
||||
work = DFW_post_work(transaction, dfw_delete_index, &desc, id);
|
||||
}
|
||||
}
|
||||
|
||||
// get partner relation for FK index
|
||||
if (EVL_field(0, rpb->rpb_record, f_idx_foreign, &desc2))
|
||||
{
|
||||
MOV_get_metadata_str(&desc, relation_name, sizeof(relation_name));
|
||||
|
||||
DSC desc3;
|
||||
EVL_field(0, rpb->rpb_record, f_idx_name, &desc3);
|
||||
|
||||
SqlIdentifier idx_name;
|
||||
MOV_get_metadata_str(&desc3, idx_name, sizeof(idx_name));
|
||||
|
||||
jrd_rel *partner;
|
||||
index_desc idx;
|
||||
|
||||
if ((r2 = MET_lookup_relation(tdbb, relation_name)) &&
|
||||
(BTR_lookup(tdbb, r2, id-1, &idx) == FB_SUCCESS) &&
|
||||
(MET_lookup_partner(tdbb, r2, &idx, idx_name)) &&
|
||||
(partner = MET_lookup_relation_id(tdbb, idx.idx_primary_relation, false)) )
|
||||
{
|
||||
DFW_post_work_arg(transaction, work, 0, partner->rel_id);
|
||||
}
|
||||
else { // can't find partner relation - impossible ?
|
||||
// add empty argument to let DFW know dropping
|
||||
// index was bound with FK
|
||||
DFW_post_work_arg(transaction, work, 0, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -3798,8 +3828,7 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
|
||||
|
||||
//hvlad: skip system relations
|
||||
vec* vector = dbb->dbb_relations;
|
||||
for (ULONG id = USER_DEF_REL_INIT_ID; vector && id < vector->count(); ++id) {
|
||||
|
||||
for (ULONG id = 0; vector && id < vector->count(); ++id) {
|
||||
relation = (jrd_rel*) (*vector)[id];
|
||||
RelationGarbage *relGarbage =
|
||||
relation ? (RelationGarbage*)relation->rel_garbage : NULL;
|
||||
@ -3808,7 +3837,7 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
|
||||
!(relation->rel_flags & (REL_deleted | REL_deleting | REL_system)))
|
||||
{
|
||||
if (relGarbage) {
|
||||
relGarbage->getGarbage(dbb->dbb_oldest_snapshot,
|
||||
relGarbage->getGarbage(dbb->dbb_oldest_snapshot,
|
||||
&relation->rel_gc_bitmap);
|
||||
}
|
||||
|
||||
@ -3883,7 +3912,7 @@ rel_exit:
|
||||
relation->rel_gc_bitmap = 0;
|
||||
}
|
||||
else {
|
||||
/* Otherwise release bitmap segments that have been cleared. */
|
||||
// Otherwise release bitmap segments that have been cleared.
|
||||
while (relation->rel_gc_bitmap->getNext())
|
||||
{
|
||||
; // do nothing
|
||||
@ -5073,7 +5102,8 @@ void RelationGarbage::getGarbage(const SLONG oldest_snapshot, PageBitmap **sbm)
|
||||
*sbm = garbage.bm;
|
||||
garbage.bm = bm_tran;
|
||||
}
|
||||
delete garbage.bm;
|
||||
if (garbage.bm)
|
||||
delete garbage.bm;
|
||||
|
||||
// Need to cast zero to exact type because literal zero means null pointer
|
||||
array.remove(static_cast<size_t>(0));
|
||||
|
Loading…
Reference in New Issue
Block a user