mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:43:02 +01:00
Ensure pages are properly released after exception raised during partial index condition check, see #7998
This commit is contained in:
parent
f4e725f3af
commit
c40fe4e181
@ -422,6 +422,30 @@ bool IndexCondition::evaluate(Record* record) const
|
||||
return result;
|
||||
}
|
||||
|
||||
TriState IndexCondition::check(Record* record, idx_e* errCode)
|
||||
{
|
||||
TriState result;
|
||||
|
||||
try
|
||||
{
|
||||
result = evaluate(record);
|
||||
|
||||
if (errCode)
|
||||
*errCode = idx_e_ok;
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
if (errCode)
|
||||
{
|
||||
*errCode = idx_e_conversion;
|
||||
ex.stuffException(m_tdbb->tdbb_status_vector);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// IndexExpression class
|
||||
|
||||
IndexExpression::IndexExpression(thread_db* tdbb, index_desc* idx)
|
||||
@ -1014,12 +1038,6 @@ bool BTR_description(thread_db* tdbb, jrd_rel* relation, index_root_page* root,
|
||||
}
|
||||
|
||||
|
||||
bool BTR_check_condition(thread_db* tdbb, index_desc* idx, Record* record)
|
||||
{
|
||||
return IndexCondition(tdbb, idx).evaluate(record);
|
||||
}
|
||||
|
||||
|
||||
dsc* BTR_eval_expression(thread_db* tdbb, index_desc* idx, Record* record)
|
||||
{
|
||||
return IndexExpression(tdbb, idx).evaluate(record);
|
||||
|
@ -343,12 +343,14 @@ public:
|
||||
|
||||
~IndexCondition();
|
||||
|
||||
bool evaluate(Record* record) const;
|
||||
Firebird::TriState check(Record* record, idx_e* errCode = nullptr);
|
||||
|
||||
private:
|
||||
thread_db* const m_tdbb;
|
||||
BoolExprNode* m_condition = nullptr;
|
||||
Request* m_request = nullptr;
|
||||
|
||||
bool evaluate(Record* record) const;
|
||||
};
|
||||
|
||||
class IndexExpression
|
||||
|
@ -34,7 +34,6 @@ void BTR_complement_key(Jrd::temporary_key*);
|
||||
void BTR_create(Jrd::thread_db*, Jrd::IndexCreation&, Jrd::SelectivityList&);
|
||||
bool BTR_delete_index(Jrd::thread_db*, Jrd::win*, USHORT);
|
||||
bool BTR_description(Jrd::thread_db*, Jrd::jrd_rel*, Ods::index_root_page*, Jrd::index_desc*, USHORT);
|
||||
bool BTR_check_condition(Jrd::thread_db*, Jrd::index_desc*, Jrd::Record*);
|
||||
dsc* BTR_eval_expression(Jrd::thread_db*, Jrd::index_desc*, Jrd::Record*);
|
||||
void BTR_evaluate(Jrd::thread_db*, const Jrd::IndexRetrieval*, Jrd::RecordBitmap**, Jrd::RecordBitmap*);
|
||||
UCHAR* BTR_find_leaf(Ods::btree_page*, Jrd::temporary_key*, UCHAR*, USHORT*, bool, int);
|
||||
|
@ -628,32 +628,39 @@ bool IndexCreateTask::handler(WorkItem& _item)
|
||||
while (!m_stop && stack.hasData())
|
||||
{
|
||||
Record* record = stack.pop();
|
||||
idx_e result = idx_e_ok;
|
||||
|
||||
if (!condition.evaluate(record))
|
||||
continue;
|
||||
|
||||
auto result = key.compose(record);
|
||||
const auto checkResult = condition.check(record, &result);
|
||||
|
||||
if (result == idx_e_ok)
|
||||
{
|
||||
if (isPrimary && key->key_nulls != 0)
|
||||
fb_assert(checkResult.isAssigned());
|
||||
if (!checkResult.asBool())
|
||||
continue;
|
||||
|
||||
result = key.compose(record);
|
||||
|
||||
if (result == idx_e_ok)
|
||||
{
|
||||
const auto key_null_segment = key.getNullSegment();
|
||||
fb_assert(key_null_segment < idx->idx_count);
|
||||
const auto bad_id = idx->idx_rpt[key_null_segment].idx_field;
|
||||
const jrd_fld *bad_fld = MET_get_field(relation, bad_id);
|
||||
if (isPrimary && key->key_nulls != 0)
|
||||
{
|
||||
const auto key_null_segment = key.getNullSegment();
|
||||
fb_assert(key_null_segment < idx->idx_count);
|
||||
const auto bad_id = idx->idx_rpt[key_null_segment].idx_field;
|
||||
const jrd_fld *bad_fld = MET_get_field(relation, bad_id);
|
||||
|
||||
ERR_post(Arg::Gds(isc_not_valid) << Arg::Str(bad_fld->fld_name) <<
|
||||
Arg::Str(NULL_STRING_MARK));
|
||||
}
|
||||
ERR_post(Arg::Gds(isc_not_valid) << Arg::Str(bad_fld->fld_name) <<
|
||||
Arg::Str(NULL_STRING_MARK));
|
||||
}
|
||||
|
||||
// If foreign key index is being defined, make sure foreign
|
||||
// key definition will not be violated
|
||||
// If foreign key index is being defined, make sure foreign
|
||||
// key definition will not be violated
|
||||
|
||||
if (isForeign && key->key_nulls == 0)
|
||||
{
|
||||
result = check_partner_index(tdbb, relation, record, transaction, idx,
|
||||
partner_relation, partner_index_id);
|
||||
if (isForeign && key->key_nulls == 0)
|
||||
{
|
||||
result = check_partner_index(tdbb, relation, record, transaction, idx,
|
||||
partner_relation, partner_index_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1167,7 +1174,7 @@ void IDX_garbage_collect(thread_db* tdbb, record_param* rpb, RecordStack& going,
|
||||
{
|
||||
Record* const rec1 = stack1.object();
|
||||
|
||||
if (!condition.evaluate(rec1))
|
||||
if (!condition.check(rec1).asBool())
|
||||
continue;
|
||||
|
||||
if (const auto result = key1.compose(rec1))
|
||||
@ -1275,11 +1282,21 @@ void IDX_modify(thread_db* tdbb,
|
||||
|
||||
while (BTR_next_index(tdbb, org_rpb->rpb_relation, transaction, &idx, &window))
|
||||
{
|
||||
if (!BTR_check_condition(tdbb, &idx, new_rpb->rpb_record))
|
||||
continue;
|
||||
|
||||
IndexErrorContext context(new_rpb->rpb_relation, &idx);
|
||||
idx_e error_code;
|
||||
idx_e error_code = idx_e_ok;
|
||||
|
||||
IndexCondition condition(tdbb, &idx);
|
||||
const auto checkResult = condition.check(new_rpb->rpb_record, &error_code);
|
||||
|
||||
if (error_code)
|
||||
{
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
context.raise(tdbb, error_code, new_rpb->rpb_record);
|
||||
}
|
||||
|
||||
fb_assert(checkResult.isAssigned());
|
||||
if (!checkResult.asBool())
|
||||
continue;
|
||||
|
||||
AutoIndexExpression expression;
|
||||
IndexKey newKey(tdbb, new_rpb->rpb_relation, &idx, expression), orgKey(newKey);
|
||||
@ -1504,11 +1521,21 @@ void IDX_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
|
||||
while (BTR_next_index(tdbb, rpb->rpb_relation, transaction, &idx, &window))
|
||||
{
|
||||
if (!BTR_check_condition(tdbb, &idx, rpb->rpb_record))
|
||||
continue;
|
||||
|
||||
IndexErrorContext context(rpb->rpb_relation, &idx);
|
||||
idx_e error_code;
|
||||
idx_e error_code = idx_e_ok;
|
||||
|
||||
IndexCondition condition(tdbb, &idx);
|
||||
const auto checkResult = condition.check(rpb->rpb_record, &error_code);
|
||||
|
||||
if (error_code)
|
||||
{
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
context.raise(tdbb, error_code, rpb->rpb_record);
|
||||
}
|
||||
|
||||
fb_assert(checkResult.isAssigned());
|
||||
if (!checkResult.asBool())
|
||||
continue;
|
||||
|
||||
AutoIndexExpression expression;
|
||||
IndexKey key(tdbb, rpb->rpb_relation, &idx, expression);
|
||||
|
@ -1903,7 +1903,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
|
||||
if (!getInfo.m_condition)
|
||||
getInfo.m_condition = FB_NEW_POOL(*pool) IndexCondition(vdr_tdbb, &getInfo.m_desc);
|
||||
|
||||
if (getInfo.m_condition->evaluate(rpb.rpb_record))
|
||||
if (getInfo.m_condition->check(rpb.rpb_record).asBool())
|
||||
RBM_SET(pool, &getInfo.m_recs, recno);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user