mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 22:03:03 +01:00
Fix up engine to work with multi-field foreign constraints again after nulls handing changes in unique indices
This commit is contained in:
parent
b8f96d8c16
commit
b68242f571
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 *,
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user