From b68242f571d98ab109b80871141a3ec55370eec2 Mon Sep 17 00:00:00 2001 From: skidder Date: Sun, 9 Mar 2003 21:07:29 +0000 Subject: [PATCH] Fix up engine to work with multi-field foreign constraints again after nulls handing changes in unique indices --- src/jrd/btr.cpp | 12 +++++++----- src/jrd/btr.h | 5 +++++ src/jrd/btr_proto.h | 2 +- src/jrd/idx.cpp | 31 ++++++++++++++++++++----------- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 9ad1dfa7bb..06c4369801 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -24,7 +24,7 @@ * */ /* -$Id: btr.cpp,v 1.25 2003-03-05 11:23:08 dimitr Exp $ +$Id: btr.cpp,v 1.26 2003-03-09 21:07:27 skidder Exp $ */ #include "firebird.h" @@ -929,7 +929,7 @@ void BTR_insert(TDBB tdbb, WIN * root_window, IIB * insertion) } -IDX_E BTR_key(TDBB tdbb, JRD_REL relation, REC record, IDX * idx, KEY * key, bool * null_unique) +IDX_E BTR_key(TDBB tdbb, JRD_REL relation, REC record, IDX * idx, KEY * key, idx_null_state * null_state) { /************************************** * @@ -1052,9 +1052,11 @@ IDX_E BTR_key(TDBB tdbb, JRD_REL relation, REC record, IDX * idx, KEY * key, boo if (idx->idx_flags & idx_descending) complement_key(key); - if (null_unique) { - // dimitr: TRUE, if all segments of the unique index are NULL - *null_unique = (missing_unique_segments == idx->idx_count); + 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; diff --git a/src/jrd/btr.h b/src/jrd/btr.h index 77abdd7dcd..7773d0aa40 100644 --- a/src/jrd/btr.h +++ b/src/jrd/btr.h @@ -37,6 +37,11 @@ #define MAX_IDX 64 /* that should be plenty of indexes */ #define MAX_KEY 256 +enum idx_null_state { + idx_nulls_none, + idx_nulls_some, + idx_nulls_all +}; /* Index descriptor block -- used to hold info from index root page */ diff --git a/src/jrd/btr_proto.h b/src/jrd/btr_proto.h index 1395eabab2..1693521511 100644 --- a/src/jrd/btr_proto.h +++ b/src/jrd/btr_proto.h @@ -48,7 +48,7 @@ extern struct btr *BTR_find_page(struct tdbb *, struct irb *, struct win *, extern SLONG BTR_get_quad(const SCHAR*); extern void BTR_insert(struct tdbb *, struct win *, struct iib *); extern enum idx_e BTR_key(struct tdbb *, struct jrd_rel *, struct rec *, - struct idx *, struct key *, bool *); + struct idx *, struct key *, idx_null_state *); extern USHORT BTR_key_length(struct jrd_rel *, struct idx *); extern struct btn *BTR_last_node(struct btr *, struct exp *, struct btx **); extern struct btr *BTR_left_handoff(struct tdbb *, struct win *, struct btr *, diff --git a/src/jrd/idx.cpp b/src/jrd/idx.cpp index bebea19ab2..60bf7c2e5c 100644 --- a/src/jrd/idx.cpp +++ b/src/jrd/idx.cpp @@ -309,21 +309,27 @@ void IDX_create_index( while (stack) { record = (REC) LLS_POP(&stack); - bool null_unique = false; /* 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_unique); + result = BTR_key(tdbb, relation, record, idx, &key, &null_state); idx->idx_flags &= ~idx_unique; + } + else { + result = BTR_key(tdbb, relation, record, idx, &key, &null_state); } - if (!null_unique) { + if (null_state != idx_nulls_none) { + result = idx_e_ok; + } + else { result = check_partner_index(tdbb, relation, record, transaction, idx, @@ -333,8 +339,9 @@ void IDX_create_index( } if (result == idx_e_ok) { - BTR_key(tdbb, relation, record, idx, &key, &null_unique); - if (null_unique) { + idx_null_state null_state; + BTR_key(tdbb, relation, record, idx, &key, &null_state); + if (null_state == idx_nulls_all) { // first null key is not a duplicate if (null_duplicates) ifl_data.ifl_duplicates--; @@ -935,6 +942,8 @@ static IDX_E check_duplicates( /* check the values of the fields in the record being inserted with the record retrieved -- for unique indexes the insertion index and the record index are the same, but for foreign keys they are different */ + + bool all_nulls = true; for (i = 0; i < insertion_idx->idx_count; i++) { field_id = insertion_idx->idx_rpt[i].idx_field; @@ -948,12 +957,12 @@ static IDX_E check_duplicates( field_id = record_idx->idx_rpt[i].idx_field; flag_2 = EVL_field(relation_2, record, field_id, &desc2); - // dimitr: stop if the fields are not-null and equal - if (flag && flag_2 && MOV_compare(&desc1, &desc2) == 0) + if (flag != flag_2 || MOV_compare(&desc1, &desc2) != 0) break; + all_nulls = all_nulls && !flag && !flag_2; } - if (i < insertion_idx->idx_count) { + if (i >= insertion_idx->idx_count && !all_nulls) { result = idx_e_duplicate; break; } @@ -1289,13 +1298,13 @@ static IDX_E insert_key( /* find out if there is a null segment by faking uniqueness -- if there is one, don't bother to check the primary key */ - bool null_unique; + idx_null_state null_state; idx->idx_flags |= idx_unique; CCH_FETCH(tdbb, window_ptr, LCK_read, pag_root); - result = BTR_key(tdbb, relation, record, idx, &key, &null_unique); + result = BTR_key(tdbb, relation, record, idx, &key, &null_state); CCH_RELEASE(tdbb, window_ptr); idx->idx_flags &= ~idx_unique; - if (!null_unique) { + if (null_state == idx_nulls_none) { result = check_foreign_key(tdbb, record, insertion->iib_relation, transaction, idx, bad_relation, bad_index);