8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:40:38 +01:00

Simplified the code and reworked the NULL validation logic.

This commit is contained in:
dimitr 2013-05-06 12:34:20 +00:00
parent f2fcd26b7e
commit af97c12801
5 changed files with 135 additions and 188 deletions

View File

@ -183,7 +183,7 @@ static UCHAR* find_node_start_point(btree_page*, temporary_key*, UCHAR*, USHORT*
static UCHAR* find_area_start_point(btree_page*, const temporary_key*, UCHAR*,
USHORT*, bool, bool, RecordNumber = NO_VALUE);
static ULONG find_page(btree_page*, const temporary_key*, UCHAR, RecordNumber = NO_VALUE,
static ULONG find_page(btree_page*, const temporary_key*, const index_desc*, RecordNumber = NO_VALUE,
bool = false);
static contents garbage_collect(thread_db*, WIN*, ULONG);
@ -865,7 +865,7 @@ btree_page* BTR_find_page(thread_db* tdbb,
while (true)
{
const temporary_key* tkey = ignoreNulls ? &firstNotNullKey : lower;
const ULONG number = find_page(page, tkey, idx->idx_flags,
const ULONG number = find_page(page, tkey, idx,
NO_VALUE, (retrieval->irb_generic & (irb_starting | irb_partial)));
if (number != END_BUCKET)
{
@ -1057,7 +1057,7 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion)
idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* idx,
temporary_key* key, idx_null_state* null_state, const bool fuzzy, USHORT count)
temporary_key* key, const bool fuzzy, USHORT count)
{
/**************************************
*
@ -1077,8 +1077,6 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id
temp.key_length = 0;
DSC desc;
DSC* desc_ptr;
//SSHORT stuff_count;
int missing_unique_segments = 0;
SET_TDBB(tdbb);
const Database* dbb = tdbb->getDatabase();
@ -1086,8 +1084,13 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id
idx_e result = idx_e_ok;
index_desc::idx_repeat* tail = idx->idx_rpt;
key->key_flags = key_all_nulls;
key->key_null_segment = 0;
key->key_flags = 0;
key->key_nulls = 0;
const bool descending = (idx->idx_flags & idx_descending);
if (!count)
count = idx->idx_count;
try {
@ -1126,17 +1129,12 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id
}
}
if (isNull && (idx->idx_flags & idx_unique)) {
missing_unique_segments++;
}
if (isNull)
key->key_nulls = 1;
key->key_flags |= key_empty;
if (!isNull)
key->key_flags &= ~key_all_nulls;
compress(tdbb, desc_ptr, key, tail->idx_itype, isNull,
(idx->idx_flags & idx_descending), keyType);
compress(tdbb, desc_ptr, key, tail->idx_itype, isNull, descending, keyType);
}
else
{
@ -1145,23 +1143,18 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id
temp.key_flags |= key_empty;
for (USHORT n = 0; n < count; n++, tail++)
{
for (; stuff_count; --stuff_count) {
for (; stuff_count; --stuff_count)
*p++ = 0;
}
desc_ptr = &desc;
// In order to "map a null to a default" value (in EVL_field()),
// the relation block is referenced.
// Reference: Bug 10116, 10424
const bool isNull = !EVL_field(relation, record, tail->idx_field, desc_ptr);
if (isNull && (idx->idx_flags & idx_unique))
{
if (missing_unique_segments++ == 0) {
key->key_null_segment = n;
}
}
if (!isNull)
if (isNull)
key->key_nulls |= 1 << n;
else
{
if (!(relation->rel_flags & REL_system) && // UNICODE_FSS_HACK
desc_ptr->dsc_dtype == dtype_text)
@ -1169,12 +1162,9 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id
// That's necessary for NO-PAD collations.
INTL_adjust_text_descriptor(tdbb, desc_ptr);
}
key->key_flags &= ~key_all_nulls;
}
compress(tdbb, desc_ptr, &temp, tail->idx_itype, isNull,
(idx->idx_flags & idx_descending), keyType);
compress(tdbb, desc_ptr, &temp, tail->idx_itype, isNull, descending, keyType);
if (temp.key_length)
{
@ -1196,25 +1186,18 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id
stuff_count = STUFF_COUNT;
}
}
key->key_length = (p - key->key_data);
if (temp.key_flags & key_empty) {
if (temp.key_flags & key_empty)
key->key_flags |= key_empty;
}
}
if (key->key_length >= dbb->getMaxIndexKeyLength()) {
if (key->key_length >= dbb->getMaxIndexKeyLength())
result = idx_e_keytoobig;
}
if (idx->idx_flags & idx_descending) {
if (descending)
BTR_complement_key(key);
}
if (null_state)
{
*null_state = !missing_unique_segments ? idx_nulls_none :
(missing_unique_segments == idx->idx_count) ? idx_nulls_all : idx_nulls_some;
}
return result;
@ -1227,12 +1210,6 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id
}
}
idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* idx,
temporary_key* key, idx_null_state* null_state, const bool fuzzy)
{
return BTR_key(tdbb, relation, record, idx, key, null_state, fuzzy, idx->idx_count);
}
USHORT BTR_key_length(thread_db* tdbb, jrd_rel* relation, index_desc* idx)
{
@ -1421,28 +1398,27 @@ idx_e BTR_make_key(thread_db* tdbb,
idx_e result = idx_e_ok;
key->key_flags = key_all_nulls;
key->key_null_segment = 0;
key->key_flags = 0;
key->key_nulls = 0;
const bool descending = (idx->idx_flags & idx_descending);
const index_desc::idx_repeat* tail = idx->idx_rpt;
const USHORT keyType = fuzzy ?
INTL_KEY_PARTIAL :
((idx->idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT);
INTL_KEY_PARTIAL : ((idx->idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT);
// If the index is a single segment index, don't sweat the compound
// stuff.
// If the index is a single segment index, don't sweat the compound stuff
if (idx->idx_count == 1)
{
bool isNull;
const dsc* desc = eval(tdbb, *exprs, &temp_desc, &isNull);
key->key_flags |= key_empty;
if (!isNull)
key->key_flags &= ~key_all_nulls;
if (isNull)
key->key_nulls = 1;
compress(tdbb, desc, key, tail->idx_itype, isNull,
(idx->idx_flags & idx_descending), keyType);
compress(tdbb, desc, key, tail->idx_itype, isNull, descending, keyType);
if (fuzzy && (key->key_flags & key_empty))
key->key_length = 0;
@ -1456,18 +1432,16 @@ idx_e BTR_make_key(thread_db* tdbb,
USHORT n = 0;
for (; n < count; n++, tail++)
{
for (; stuff_count; --stuff_count) {
for (; stuff_count; --stuff_count)
*p++ = 0;
}
bool isNull;
const dsc* desc = eval(tdbb, *exprs++, &temp_desc, &isNull);
if (!isNull) {
key->key_flags &= ~key_all_nulls;
}
compress(tdbb, desc, &temp, tail->idx_itype, isNull,
(idx->idx_flags & idx_descending),
if (isNull)
key->key_nulls |= 1 << n;
compress(tdbb, desc, &temp, tail->idx_itype, isNull, descending,
(n == count - 1 ?
keyType : ((idx->idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)));
@ -1513,14 +1487,14 @@ idx_e BTR_make_key(thread_db* tdbb,
if (key->key_length >= dbb->getMaxIndexKeyLength())
result = idx_e_keytoobig;
if (idx->idx_flags & idx_descending)
if (descending)
BTR_complement_key(key);
return result;
}
void BTR_make_null_key(thread_db* tdbb, index_desc* idx, temporary_key* key)
void BTR_make_null_key(thread_db* tdbb, const index_desc* idx, temporary_key* key)
{
/**************************************
*
@ -1547,19 +1521,21 @@ void BTR_make_null_key(thread_db* tdbb, index_desc* idx, temporary_key* key)
temp.key_length = 0;
SET_TDBB(tdbb);
//const Database* dbb = tdbb->getDatabase();
fb_assert(idx != NULL);
fb_assert(key != NULL);
key->key_flags = key_all_nulls;
key->key_flags = 0;
key->key_nulls = (1 << idx->idx_count) - 1;
index_desc::idx_repeat* tail = idx->idx_rpt;
const bool descending = (idx->idx_flags & idx_descending);
// If the index is a single segment index, don't sweat the compound
// stuff.
if ((idx->idx_count == 1) || (idx->idx_flags & idx_expressn)) {
compress(tdbb, &null_desc, key, tail->idx_itype, true, (idx->idx_flags & idx_descending), false);
const index_desc::idx_repeat* tail = idx->idx_rpt;
// If the index is a single segment index, don't sweat the compound stuff
if ((idx->idx_count == 1) || (idx->idx_flags & idx_expressn))
{
compress(tdbb, &null_desc, key, tail->idx_itype, true, descending, false);
}
else
{
@ -1567,14 +1543,13 @@ void BTR_make_null_key(thread_db* tdbb, index_desc* idx, temporary_key* key)
UCHAR* p = key->key_data;
SSHORT stuff_count = 0;
temp.key_flags |= key_empty;
for (USHORT n = 0; n < idx->idx_count; n++, tail++)
{
for (; stuff_count; --stuff_count) {
for (; stuff_count; --stuff_count)
*p++ = 0;
}
compress(tdbb, &null_desc, &temp, tail->idx_itype, true,
(idx->idx_flags & idx_descending), false);
compress(tdbb, &null_desc, &temp, tail->idx_itype, true, descending, false);
if (temp.key_length)
{
@ -1596,15 +1571,15 @@ void BTR_make_null_key(thread_db* tdbb, index_desc* idx, temporary_key* key)
stuff_count = STUFF_COUNT;
}
}
key->key_length = (p - key->key_data);
if (temp.key_flags & key_empty) {
if (temp.key_flags & key_empty)
key->key_flags |= key_empty;
}
}
if (idx->idx_flags & idx_descending) {
if (descending)
BTR_complement_key(key);
}
}
@ -2205,7 +2180,7 @@ static ULONG add_node(thread_db* tdbb,
ULONG page;
while (true)
{
page = find_page(bucket, insertion->iib_key, insertion->iib_descriptor->idx_flags,
page = find_page(bucket, insertion->iib_key, insertion->iib_descriptor,
insertion->iib_number);
if (page != END_BUCKET) {
break;
@ -2331,7 +2306,7 @@ static void compress(thread_db* tdbb,
if (isNull)
{
UCHAR pad = 0;
const UCHAR pad = 0;
key->key_flags &= ~key_empty;
// AB: NULL should be threated as lowest value possible.
// Therefore don't complement pad when we have an ascending index.
@ -4192,7 +4167,7 @@ static UCHAR* find_area_start_point(btree_page* bucket, const temporary_key* key
static ULONG find_page(btree_page* bucket, const temporary_key* key,
UCHAR idx_flags, RecordNumber find_record_number,
const index_desc* idx, RecordNumber find_record_number,
bool retrieval)
{
/**************************************
@ -4212,15 +4187,16 @@ static ULONG find_page(btree_page* bucket, const temporary_key* key,
const bool leafPage = (bucket->btr_level == 0);
bool firstPass = true;
const bool descending = (idx_flags & idx_descending);
const UCHAR* const endPointer = (UCHAR*)bucket + bucket->btr_length;
const bool validateDuplicates =
((idx_flags & idx_unique) && !(key->key_flags & key_all_nulls)) ||
(idx_flags & idx_primary);
const bool descending = (idx->idx_flags & idx_descending);
const bool primary = (idx->idx_flags & idx_primary);
const bool unique = (idx->idx_flags & idx_unique);
const bool key_all_nulls = (key->key_nulls == (1 << idx->idx_count) - 1);
const bool validateDuplicates = (unique && !key_all_nulls) || primary;
if (validateDuplicates) {
if (validateDuplicates)
find_record_number = NO_VALUE;
}
const UCHAR* const endPointer = (UCHAR*) bucket + bucket->btr_length;
USHORT prefix = 0; // last computed prefix against processed node
@ -5020,11 +4996,13 @@ static ULONG insert_node(thread_db* tdbb,
btree_page* bucket = (btree_page*) window->win_buffer;
temporary_key* key = insertion->iib_key;
const bool unique = (insertion->iib_descriptor->idx_flags & idx_unique);
const bool primary = (insertion->iib_descriptor->idx_flags & idx_primary);
const index_desc* const idx = insertion->iib_descriptor;
const bool unique = (idx->idx_flags & idx_unique);
const bool primary = (idx->idx_flags & idx_primary);
const bool key_all_nulls = (key->key_nulls == (1 << idx->idx_count) - 1);
const bool leafPage = (bucket->btr_level == 0);
// hvlad: don't check unique index if key has only null values
const bool validateDuplicates = (unique && !(key->key_flags & key_all_nulls)) || primary;
const bool validateDuplicates = (unique && !key_all_nulls) || primary;
USHORT prefix = 0;
RecordNumber newRecordNumber;
if (leafPage) {
@ -5035,7 +5013,7 @@ static ULONG insert_node(thread_db* tdbb,
}
// For checking on duplicate nodes we should find the first matching key.
UCHAR* pointer = find_node_start_point(bucket, key, 0, &prefix,
insertion->iib_descriptor->idx_flags & idx_descending,
idx->idx_flags & idx_descending,
false, true, validateDuplicates ? NO_VALUE : newRecordNumber);
if (!pointer) {
return NO_VALUE_PAGE;
@ -5605,10 +5583,7 @@ static ULONG insert_node(thread_db* tdbb,
// place (in order of record numbers).
temporary_key nullKey;
nullKey.key_length = 0;
nullKey.key_flags = 0;
nullKey.key_null_segment = 0;
BTR_make_null_key(tdbb, insertion->iib_descriptor, &nullKey);
BTR_make_null_key(tdbb, idx, &nullKey);
if (new_key->key_length == nullKey.key_length &&
memcmp(new_key->key_data, nullKey.key_data, nullKey.key_length) == 0)
@ -5720,7 +5695,7 @@ static contents remove_node(thread_db* tdbb, index_insertion* insertion, WIN* wi
while (true)
{
const ULONG number = find_page(page, insertion->iib_key, idx->idx_flags, insertion->iib_number);
const ULONG number = find_page(page, insertion->iib_key, idx, insertion->iib_number);
// we should always find the node, but let's make sure
if (number == END_LEVEL)
@ -5783,16 +5758,17 @@ static contents remove_leaf_node(thread_db* tdbb, index_insertion* insertion, WI
btree_page* page = (btree_page*) window->win_buffer;
temporary_key* key = insertion->iib_key;
const UCHAR idx_flags = insertion->iib_descriptor->idx_flags;
const bool validateDuplicates =
((idx_flags & idx_unique) && !(key->key_flags & key_all_nulls)) ||
(idx_flags & idx_primary);
const index_desc* const idx = insertion->iib_descriptor;
const bool primary = (idx->idx_flags & idx_primary);
const bool unique = (idx->idx_flags & idx_unique);
const bool key_all_nulls = (key->key_nulls == (1 << idx->idx_count) - 1);
const bool validateDuplicates = (unique && !key_all_nulls) || primary;
// Look for the first node with the value to be removed.
UCHAR* pointer;
USHORT prefix;
while (!(pointer = find_node_start_point(page, key, 0, &prefix,
insertion->iib_descriptor->idx_flags & idx_descending,
idx->idx_flags & idx_descending,
false, false,
validateDuplicates ? NO_VALUE : insertion->iib_number)))
{

View File

@ -48,12 +48,6 @@ struct temporary_key;
class jrd_tra;
class BtrPageGCLock;
enum idx_null_state {
idx_nulls_none,
idx_nulls_some,
idx_nulls_all
};
// Index descriptor block -- used to hold info from index root page
struct index_desc
@ -145,7 +139,6 @@ struct index_insertion
// these flags are for the key_flags
const int key_empty = 1; // Key contains empty data / empty string
const int key_all_nulls = 2; // All key fields are nulls
// Temporary key block
@ -154,16 +147,8 @@ struct temporary_key
USHORT key_length;
UCHAR key_data[MAX_KEY + 1];
UCHAR key_flags;
USHORT key_null_segment; // index of first encountered null segment.
// Evaluated in BTR_key only and used in IDX_create_index for better
// error diagnostics
// AB: I don't see the use of multiplying with 2 anymore.
//UCHAR key_data[MAX_KEY * 2];
// This needs to be on a SHORT boundary.
// This is because key_data is complemented as
// (SSHORT *) if value is negative.
// See compress() (JRD/btr.cpp) for more details
USHORT key_nulls; // bitmap of encountered null segments,
// USHORT is enought to store MAX_INDEX_SEGMENTS bits
};

View File

@ -33,7 +33,6 @@ USHORT BTR_all(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::IndexDescAlloc**, Jrd::Relat
void BTR_complement_key(Jrd::temporary_key*);
void BTR_create(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*, USHORT, Firebird::AutoPtr<Jrd::Sort>&, Jrd::SelectivityList&);
bool BTR_delete_index(Jrd::thread_db*, Jrd::win*, USHORT);
//USHORT BTR_delete_node(Jrd::thread_db*, Ods::btree_page*, USHORT);
bool BTR_description(Jrd::thread_db*, Jrd::jrd_rel*, Ods::index_root_page*, Jrd::index_desc*, USHORT);
DSC* BTR_eval_expression(Jrd::thread_db*, Jrd::index_desc*, Jrd::Record*, bool&);
void BTR_evaluate(Jrd::thread_db*, const Jrd::IndexRetrieval*, Jrd::RecordBitmap**, Jrd::RecordBitmap*);
@ -42,15 +41,13 @@ Ods::btree_page* BTR_find_page(Jrd::thread_db*, const Jrd::IndexRetrieval*, Jrd:
Jrd::temporary_key*, Jrd::temporary_key*);
void BTR_insert(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*);
Jrd::idx_e BTR_key(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::Record*, Jrd::index_desc*, Jrd::temporary_key*,
Jrd::idx_null_state*, const bool, USHORT);
Jrd::idx_e BTR_key(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::Record*, Jrd::index_desc*, Jrd::temporary_key*,
Jrd::idx_null_state*, const bool);
const bool, USHORT = 0);
USHORT BTR_key_length(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*);
Ods::btree_page* BTR_left_handoff(Jrd::thread_db*, Jrd::win*, Ods::btree_page*, SSHORT);
USHORT BTR_lookup(Jrd::thread_db*, Jrd::jrd_rel*, USHORT, Jrd::index_desc*, Jrd::RelationPages*);
Jrd::idx_e BTR_make_key(Jrd::thread_db*, USHORT, const Jrd::ValueExprNode* const*, const Jrd::index_desc*,
Jrd::temporary_key*, bool);
void BTR_make_null_key(Jrd::thread_db*, Jrd::index_desc*, Jrd::temporary_key*);
void BTR_make_null_key(Jrd::thread_db*, const Jrd::index_desc*, Jrd::temporary_key*);
bool BTR_next_index(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::jrd_tra*, Jrd::index_desc*, Jrd::win*);
void BTR_remove(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*);
void BTR_reserve_slot(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::jrd_tra*, Jrd::index_desc*);

View File

@ -89,6 +89,20 @@ static bool key_equal(const temporary_key*, const temporary_key*);
static void release_index_block(thread_db*, IndexBlock*);
static void signal_index_deletion(thread_db*, jrd_rel*, USHORT);
inline USHORT getNullSegment(const temporary_key& key)
{
USHORT nulls = key.key_nulls;
for (USHORT i = 0; nulls; i++)
{
if (nulls & 1)
return i;
nulls >>= 1;
}
return MAX_USHORT;
}
void IDX_check_access(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view, jrd_rel* relation)
{
@ -263,6 +277,7 @@ void IDX_create_index(thread_db* tdbb,
const bool isDescending = (idx->idx_flags & idx_descending);
const bool isPrimary = (idx->idx_flags & idx_primary);
const bool isForeign = (idx->idx_flags & idx_foreign);
// hvlad: in ODS11 empty string and NULL values can have the same binary
// representation in index keys. BTR can distinguish it by the key_length
@ -289,8 +304,6 @@ void IDX_create_index(thread_db* tdbb,
ifl_data.ifl_duplicates = 0;
ifl_data.ifl_key_length = key_length;
bool key_is_null = false;
sort_key_def key_desc[2];
// Key sort description
key_desc[0].skd_dtype = SKD_bytes;
@ -314,7 +327,7 @@ void IDX_create_index(thread_db* tdbb,
jrd_rel* partner_relation = NULL;
USHORT partner_index_id = 0;
if (idx->idx_flags & idx_foreign)
if (isForeign)
{
if (!MET_lookup_partner(tdbb, relation, idx, index_name)) {
BUGCHECK(173); // msg 173 referenced index description not found
@ -372,52 +385,28 @@ void IDX_create_index(thread_db* tdbb,
{
Record* record = stack.pop();
// If foreign key index is being defined, make sure foreign
// key definition will not be violated
if (idx->idx_flags & idx_foreign)
{
idx_null_state null_state;
// find out if there is a null segment by faking uniqueness --
// if there is one, don't bother to check the primary key
if (!(idx->idx_flags & idx_unique))
{
idx->idx_flags |= idx_unique;
result = BTR_key(tdbb, relation, record, idx, &key, &null_state, false);
idx->idx_flags &= ~idx_unique;
}
else
{
result = BTR_key(tdbb, relation, record, idx, &key, &null_state, false);
}
if (result == idx_e_ok && null_state == idx_nulls_none)
{
result = check_partner_index(tdbb, relation, record, transaction, idx,
partner_relation, partner_index_id);
}
}
result = BTR_key(tdbb, relation, record, idx, &key, false);
if (result == idx_e_ok)
{
idx_null_state null_state;
result = BTR_key(tdbb, relation, record, idx, &key, &null_state, false);
if (result == idx_e_ok)
if (isPrimary && key.key_nulls != 0)
{
if (isPrimary && null_state != idx_nulls_none)
{
fb_assert(key.key_null_segment < idx->idx_count);
const USHORT key_null_segment = getNullSegment(key);
fb_assert(key_null_segment < idx->idx_count);
const USHORT bad_id = idx->idx_rpt[key_null_segment].idx_field;
const jrd_fld *bad_fld = MET_get_field(relation, bad_id);
const USHORT bad_id = idx->idx_rpt[key.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
key_is_null = (null_state == idx_nulls_all);
if (isForeign && key.key_nulls == 0)
{
result = check_partner_index(tdbb, relation, record, transaction, idx,
partner_relation, partner_index_id);
}
}
@ -466,19 +455,23 @@ void IDX_create_index(thread_db* tdbb,
USHORT l = key.key_length;
if (nullIndLen) {
if (nullIndLen)
*p++ = (key.key_length == 0) ? 0 : 1;
}
if (l > 0)
{
memcpy(p, key.key_data, l);
p += l;
}
if ( (l = key_length - nullIndLen - key.key_length) )
{
memset(p, pad, l);
p += l;
}
const bool key_is_null = (key.key_nulls == (1 << idx->idx_count) - 1);
index_sort_record* isr = (index_sort_record*) p;
isr->isr_record_number = primary.rpb_number.getValue();
isr->isr_key_length = key.key_length;
@ -717,7 +710,7 @@ void IDX_garbage_collect(thread_db* tdbb, record_param* rpb, RecordStack& going,
{
Record* rec1 = stack1.object();
idx_e result = BTR_key(tdbb, rpb->rpb_relation, rec1, &idx, &key1, 0, false);
idx_e result = BTR_key(tdbb, rpb->rpb_relation, rec1, &idx, &key1, false);
if (result != idx_e_ok)
{
CCH_RELEASE(tdbb, &window);
@ -731,7 +724,7 @@ void IDX_garbage_collect(thread_db* tdbb, record_param* rpb, RecordStack& going,
{
Record* rec2 = stack2.object();
result = BTR_key(tdbb, rpb->rpb_relation, rec2, &idx, &key2, 0, false);
result = BTR_key(tdbb, rpb->rpb_relation, rec2, &idx, &key2, false);
if (result != idx_e_ok)
{
CCH_RELEASE(tdbb, &window);
@ -751,7 +744,7 @@ void IDX_garbage_collect(thread_db* tdbb, record_param* rpb, RecordStack& going,
{
Record* rec3 = stack3.object();
result = BTR_key(tdbb, rpb->rpb_relation, rec3, &idx, &key2, 0, false);
result = BTR_key(tdbb, rpb->rpb_relation, rec3, &idx, &key2, false);
if (result != idx_e_ok)
{
CCH_RELEASE(tdbb, &window);
@ -821,9 +814,9 @@ idx_e IDX_modify(thread_db* tdbb,
*bad_index = idx.idx_id;
*bad_relation = new_rpb->rpb_relation;
if ((error_code =
BTR_key(tdbb, new_rpb->rpb_relation, new_rpb->rpb_record, &idx, &key1, 0, false)) ||
BTR_key(tdbb, new_rpb->rpb_relation, new_rpb->rpb_record, &idx, &key1, false)) ||
(error_code =
BTR_key(tdbb, org_rpb->rpb_relation, org_rpb->rpb_record, &idx, &key2, 0, false)))
BTR_key(tdbb, org_rpb->rpb_relation, org_rpb->rpb_record, &idx, &key2, false)))
{
CCH_RELEASE(tdbb, &window);
break;
@ -892,9 +885,9 @@ idx_e IDX_modify_check_constraints(thread_db* tdbb,
*bad_index = idx.idx_id;
*bad_relation = new_rpb->rpb_relation;
if ((error_code =
BTR_key(tdbb, new_rpb->rpb_relation, new_rpb->rpb_record, &idx, &key1, 0, false)) ||
BTR_key(tdbb, new_rpb->rpb_relation, new_rpb->rpb_record, &idx, &key1, false)) ||
(error_code =
BTR_key(tdbb, org_rpb->rpb_relation, org_rpb->rpb_record, &idx, &key2, 0, false)))
BTR_key(tdbb, org_rpb->rpb_relation, org_rpb->rpb_record, &idx, &key2, false)))
{
CCH_RELEASE(tdbb, &window);
break;
@ -972,7 +965,7 @@ idx_e IDX_store(thread_db* tdbb, record_param* rpb,
{
*bad_index = idx.idx_id;
*bad_relation = rpb->rpb_relation;
if ( (error_code = BTR_key(tdbb, rpb->rpb_relation, rpb->rpb_record, &idx, &key, 0, false)) )
if ( (error_code = BTR_key(tdbb, rpb->rpb_relation, rpb->rpb_record, &idx, &key, false)) )
{
CCH_RELEASE(tdbb, &window);
break;
@ -1276,7 +1269,7 @@ static idx_e check_partner_index(thread_db* tdbb,
// tmpIndex.idx_flags |= idx_unique;
tmpIndex.idx_flags = (tmpIndex.idx_flags & ~idx_unique) | (partner_idx.idx_flags & idx_unique);
temporary_key key;
result = BTR_key(tdbb, relation, record, &tmpIndex, &key, 0, starting, segment);
result = BTR_key(tdbb, relation, record, &tmpIndex, &key, starting, segment);
CCH_RELEASE(tdbb, &window);
// now check for current duplicates
@ -1469,17 +1462,13 @@ static idx_e insert_key(thread_db* tdbb,
// check for an insert into the corresponding primary key index
if (idx->idx_flags & idx_foreign)
{
// find out if there is a null segment by faking uniqueness --
// if there is one, don't bother to check the primary key
idx->idx_flags |= idx_unique;
// Find out if there is a null segment. If there is one,
// don't bother to check the primary key.
CCH_FETCH(tdbb, window_ptr, LCK_read, pag_root);
temporary_key key;
idx_null_state null_state;
result = BTR_key(tdbb, relation, record, idx, &key, &null_state, false);
result = BTR_key(tdbb, relation, record, idx, &key, false);
CCH_RELEASE(tdbb, window_ptr);
idx->idx_flags &= ~idx_unique;
if (result == idx_e_ok && null_state == idx_nulls_none)
if (result == idx_e_ok && key.key_nulls == 0)
{
result = check_foreign_key(tdbb, record, insertion->iib_relation,
transaction, idx, bad_relation, bad_index);

View File

@ -211,7 +211,7 @@ bool IndexTableScan::getRecord(thread_db* tdbb) const
temporary_key value;
const idx_e result =
BTR_key(tdbb, rpb->rpb_relation, rpb->rpb_record, idx, &value, 0, false);
BTR_key(tdbb, rpb->rpb_relation, rpb->rpb_record, idx, &value, false);
if (result != idx_e_ok)
ERR_duplicate_error(result, rpb->rpb_relation, idx->idx_id);