15.02.2022 14:41, Dimitry Sibiryakov wrote:

Is "stored keys independent of the declared scale" a really useful and used feature?

That's a separate but also good question. Double precision keys allow independence of both precision (within its range) and scale. AFAIU, the idea was to allow changing column data types between FLOAT/DOUBLE/SMALLINT/INT and between different NUMERIC/DECIMAL precisions/scales without rebuilding the index (i.e. keys in the old and new formats may co-exist).

But then surprises start to appear.

First of all, it does not work this way. We rebuild an index every time a column's data type is changed, regardless of the old/new precision and scale. Even if the field is altered to the same data type. And AFAIK, it's not something we changed in Firebird, the original IB6 code already worked this way.

Second, co-existence of keys in the old and new formats is also buggy now, see below.

recreate table t_scale (col1 numeric(5, 2), col2 numeric(5, 2));
create index t_scale_i1 on t_scale(col1);
create index t_scale_i2 on t_scale(col2);
commit;

insert into t_scale values (1.23, 1.23);
commit;

select * from t_scale;

        COL1         COL2
============ ============
        1.23         1.23

select * from t_scale where col1 = 1.23;

        COL1         COL2
============ ============
        1.23         1.23

select * from t_scale where col2 = 1.23;

        COL1         COL2
============ ============
        1.23         1.23

alter table t_scale alter col1 type numeric(6, 3);
alter table t_scale alter col2 type numeric(5, 1);
commit;

select * from t_scale;

        COL1         COL2
============ ============
       1.230          1.2

select * from t_scale where col1 = 1.23;

        COL1         COL2
============ ============
       1.230          1.2

select * from t_scale where col1 = 1.230;

        COL1         COL2
============ ============
       1.230          1.2

-- so far so good

select * from t_scale where col2 = 1.2;

-- NOTHING! WTF?

select * from t_scale where col2 = 1.23;

-- ALSO NOTHING!

We cannot access the existing value via the index anymore. This happens because (even after index rebuild) the stored key belongs to the old format, i.e. 1.23. It cannot be matched while searching for 1.2. It is matched while searching for 1.23, but then the record is read, its stored value 1.23 (old format) is converted into 1.2 (new format) and then re-compared with 1.23 thus being false again.

I can think of two ways to proceed:

1) Keep rebuilding the index every time the type is changed. Cast all column values into the new format before storing keys into the index. Forget about being scale-independent, pick the scale from the latest table format (and store BIGINTs or all exact numerics as integers without scale, as you suggest).

2) Prohibit decreasing the scale. Avoid rebuilding the indices unless really necessary (idx_itype is changed). Consider it a good thing (tm).

Maybe there may be other options, I didn't think deeply about this.


Dmitry


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel

Reply via email to