mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 21:23:04 +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;
|
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 class
|
||||||
|
|
||||||
IndexExpression::IndexExpression(thread_db* tdbb, index_desc* idx)
|
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)
|
dsc* BTR_eval_expression(thread_db* tdbb, index_desc* idx, Record* record)
|
||||||
{
|
{
|
||||||
return IndexExpression(tdbb, idx).evaluate(record);
|
return IndexExpression(tdbb, idx).evaluate(record);
|
||||||
|
@ -343,12 +343,14 @@ public:
|
|||||||
|
|
||||||
~IndexCondition();
|
~IndexCondition();
|
||||||
|
|
||||||
bool evaluate(Record* record) const;
|
Firebird::TriState check(Record* record, idx_e* errCode = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
thread_db* const m_tdbb;
|
thread_db* const m_tdbb;
|
||||||
BoolExprNode* m_condition = nullptr;
|
BoolExprNode* m_condition = nullptr;
|
||||||
Request* m_request = nullptr;
|
Request* m_request = nullptr;
|
||||||
|
|
||||||
|
bool evaluate(Record* record) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IndexExpression
|
class IndexExpression
|
||||||
|
@ -34,7 +34,6 @@ void BTR_complement_key(Jrd::temporary_key*);
|
|||||||
void BTR_create(Jrd::thread_db*, Jrd::IndexCreation&, Jrd::SelectivityList&);
|
void BTR_create(Jrd::thread_db*, Jrd::IndexCreation&, Jrd::SelectivityList&);
|
||||||
bool BTR_delete_index(Jrd::thread_db*, Jrd::win*, USHORT);
|
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_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*);
|
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*);
|
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);
|
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())
|
while (!m_stop && stack.hasData())
|
||||||
{
|
{
|
||||||
Record* record = stack.pop();
|
Record* record = stack.pop();
|
||||||
|
idx_e result = idx_e_ok;
|
||||||
|
|
||||||
if (!condition.evaluate(record))
|
const auto checkResult = condition.check(record, &result);
|
||||||
continue;
|
|
||||||
|
|
||||||
auto result = key.compose(record);
|
|
||||||
|
|
||||||
if (result == idx_e_ok)
|
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();
|
if (isPrimary && key->key_nulls != 0)
|
||||||
fb_assert(key_null_segment < idx->idx_count);
|
{
|
||||||
const auto bad_id = idx->idx_rpt[key_null_segment].idx_field;
|
const auto key_null_segment = key.getNullSegment();
|
||||||
const jrd_fld *bad_fld = MET_get_field(relation, bad_id);
|
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) <<
|
ERR_post(Arg::Gds(isc_not_valid) << Arg::Str(bad_fld->fld_name) <<
|
||||||
Arg::Str(NULL_STRING_MARK));
|
Arg::Str(NULL_STRING_MARK));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If foreign key index is being defined, make sure foreign
|
// If foreign key index is being defined, make sure foreign
|
||||||
// key definition will not be violated
|
// key definition will not be violated
|
||||||
|
|
||||||
if (isForeign && key->key_nulls == 0)
|
if (isForeign && key->key_nulls == 0)
|
||||||
{
|
{
|
||||||
result = check_partner_index(tdbb, relation, record, transaction, idx,
|
result = check_partner_index(tdbb, relation, record, transaction, idx,
|
||||||
partner_relation, partner_index_id);
|
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();
|
Record* const rec1 = stack1.object();
|
||||||
|
|
||||||
if (!condition.evaluate(rec1))
|
if (!condition.check(rec1).asBool())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (const auto result = key1.compose(rec1))
|
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))
|
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);
|
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;
|
AutoIndexExpression expression;
|
||||||
IndexKey newKey(tdbb, new_rpb->rpb_relation, &idx, expression), orgKey(newKey);
|
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))
|
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);
|
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;
|
AutoIndexExpression expression;
|
||||||
IndexKey key(tdbb, rpb->rpb_relation, &idx, 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)
|
if (!getInfo.m_condition)
|
||||||
getInfo.m_condition = FB_NEW_POOL(*pool) IndexCondition(vdr_tdbb, &getInfo.m_desc);
|
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);
|
RBM_SET(pool, &getInfo.m_recs, recno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user