-
Notifications
You must be signed in to change notification settings - Fork 403
Description
Tarantool version: Tarantool 3.1.0-entrypoint-232-gc8d8c2e8ee (current master).
Bug description
Our float64 format doesn't allow values encoded as MP_FLOAT, only the ones encoded as MP_DOUBLE:
Lines 94 to 96 in c8d8c2e
| /* [FIELD_TYPE_FLOAT32] = */ 1U << MP_FLOAT, | |
| /* [FIELD_TYPE_FLOAT64] = */ 1U << MP_DOUBLE, | |
| }; |
At the same time, we have multiple places which optimize encoded float size, and encode doubles as MP_FLOAT to spare extra 4 bytes, when this doesn't affect the precision (a double is exactly representable by a float). Example:
tarantool/src/box/xrow_update_field.c
Lines 481 to 488 in c8d8c2e
| if (c <= FLT_MAX && c >= -FLT_MAX) { | |
| float fc = (float)c; | |
| if (c == (double)fc) { | |
| ret->type = XUPDATE_TYPE_FLOAT; | |
| ret->flt = fc; | |
| return 0; | |
| } | |
| } |
As a result, an update operation of a float64 field 100: update({key}, {{'+', 2, 100}}) may error like this:
---
- error: 'Tuple field 2 (value) type does not match one required by operation: expected
float64, got float'
...
And there's literally no way to perform an update with an integer result on a float64 column.
Steps to reproduce
Run a Tarantool instance interactively:
-- Step 1.
box.cfg{}
space = box.schema.space.create('test', {format = {{'id', 'unsigned'}, {'value', 'float64'}}})
_ = space:create_index('pk')
space:insert{1, require('ffi').new('float', 100)}
-- error: 'Tuple field 2 (value) type does not match one required by operation: expected
-- float64, got float'
space:insert{1, require('ffi').new('double', 100)} -- success.
space:fselect()
-- +-----+-----+
-- | id |value|
-- +-----+-----+
-- | 1 | 100 |
-- +-----+-----+
space:update({1}, {{'+', 2, 100}})
-- error: 'Tuple field 2 (value) type does not match one required by operation: expected
-- float64, got float'
space:update({1}, {{'+', 2, require('ffi').new('float', 100)}})
-- error: 'Tuple field 2 (value) type does not match one required by operation: expected
-- float64, got float'
space:update({1}, {{'+', 2, require('ffi').new('double', 100)}})
-- error: 'Tuple field 2 (value) type does not match one required by operation: expected
-- float64, got float'I think we should keep the MP_FLOAT optimization for results that fit into a single-precision float, and instead allow float64 to contain MP_FLOAT in addition to MP_DOUBLE.
Besides, it would fall in line with (u)int8/16/32/64, which allows any (u)int encoding.