[Tarantool-patches] [PATCH v1 1/2] box: introduce DOUBLE field type
imeevma at tarantool.org
imeevma at tarantool.org
Sat Dec 21 19:03:09 MSK 2019
This patch creates DOUBLE field type in Tarantool. The main
purpose of this field type is to add DOUBLE type to SQL.
Part of #3812
---
src/box/field_def.c | 28 ++++----
src/box/field_def.h | 1 +
src/box/tuple_compare.cc | 24 +++++++
test/engine/insert.result | 151 ++++++++++++++++++++++++++++++++++++++++++++
test/engine/insert.test.lua | 51 +++++++++++++++
5 files changed, 243 insertions(+), 12 deletions(-)
diff --git a/src/box/field_def.c b/src/box/field_def.c
index da766d5..fde4e5a 100644
--- a/src/box/field_def.c
+++ b/src/box/field_def.c
@@ -59,6 +59,7 @@ const uint32_t field_mp_type[] = {
/* [FIELD_TYPE_STRING] = */ 1U << MP_STR,
/* [FIELD_TYPE_NUMBER] = */ (1U << MP_UINT) | (1U << MP_INT) |
(1U << MP_FLOAT) | (1U << MP_DOUBLE),
+ /* [FIELD_TYPE_DOUBLE] = */ 1U << MP_DOUBLE,
/* [FIELD_TYPE_INTEGER] = */ (1U << MP_UINT) | (1U << MP_INT),
/* [FIELD_TYPE_BOOLEAN] = */ 1U << MP_BOOL,
/* [FIELD_TYPE_VARBINARY] = */ 1U << MP_BIN,
@@ -75,6 +76,7 @@ const uint32_t field_ext_type[] = {
/* [FIELD_TYPE_UNSIGNED] = */ 0,
/* [FIELD_TYPE_STRING] = */ 0,
/* [FIELD_TYPE_NUMBER] = */ 1U << MP_DECIMAL,
+ /* [FIELD_TYPE_DOUBLE] = */ 0,
/* [FIELD_TYPE_INTEGER] = */ 0,
/* [FIELD_TYPE_BOOLEAN] = */ 0,
/* [FIELD_TYPE_VARBINARY] = */ 0,
@@ -89,6 +91,7 @@ const char *field_type_strs[] = {
/* [FIELD_TYPE_UNSIGNED] = */ "unsigned",
/* [FIELD_TYPE_STRING] = */ "string",
/* [FIELD_TYPE_NUMBER] = */ "number",
+ /* [FIELD_TYPE_DOUBLE] = */ "double",
/* [FIELD_TYPE_INTEGER] = */ "integer",
/* [FIELD_TYPE_BOOLEAN] = */ "boolean",
/* [FIELD_TYPE_VARBINARY] = */"varbinary",
@@ -120,18 +123,19 @@ field_type_by_name_wrapper(const char *str, uint32_t len)
* values can be stored in the j type.
*/
static const bool field_type_compatibility[] = {
- /* ANY UNSIGNED STRING NUMBER INTEGER BOOLEAN VARBINARY SCALAR DECIMAL ARRAY MAP */
-/* ANY */ true, false, false, false, false, false, false, false, false, false, false,
-/* UNSIGNED */ true, true, false, true, true, false, false, true, false, false, false,
-/* STRING */ true, false, true, false, false, false, false, true, false, false, false,
-/* NUMBER */ true, false, false, true, false, false, false, true, false, false, false,
-/* INTEGER */ true, false, false, true, true, false, false, true, false, false, false,
-/* BOOLEAN */ true, false, false, false, false, true, false, true, false, false, false,
-/* VARBINARY*/ true, false, false, false, false, false, true, true, false, false, false,
-/* SCALAR */ true, false, false, false, false, false, false, true, false, false, false,
-/* DECIMAL */ true, false, false, true, false, false, false, true, true, false, false,
-/* ARRAY */ true, false, false, false, false, false, false, false, false, true, false,
-/* MAP */ true, false, false, false, false, false, false, false, false, false, true,
+ /* ANY UNSIGNED STRING NUMBER DOUBLE INTEGER BOOLEAN VARBINARY SCALAR DECIMAL ARRAY MAP */
+/* ANY */ true, false, false, false, false, false, false, false, false, false, false, false,
+/* UNSIGNED */ true, true, false, true, false, true, false, false, true, false, false, false,
+/* STRING */ true, false, true, false, false, false, false, false, true, false, false, false,
+/* NUMBER */ true, false, false, true, false, false, false, false, true, false, false, false,
+/* DOUBLE */ true, false, false, true, true, false, false, false, true, false, false, false,
+/* INTEGER */ true, false, false, true, false, true, false, false, true, false, false, false,
+/* BOOLEAN */ true, false, false, false, false, false, true, false, true, false, false, false,
+/* VARBINARY*/ true, false, false, false, false, false, false, true, true, false, false, false,
+/* SCALAR */ true, false, false, false, false, false, false, false, true, false, false, false,
+/* DECIMAL */ true, false, false, true, false, false, false, false, true, true, false, false,
+/* ARRAY */ true, false, false, false, false, false, false, false, false, false, true, false,
+/* MAP */ true, false, false, false, false, false, false, false, false, false, false, true,
};
bool
diff --git a/src/box/field_def.h b/src/box/field_def.h
index 49c2998..8e82369 100644
--- a/src/box/field_def.h
+++ b/src/box/field_def.h
@@ -54,6 +54,7 @@ enum field_type {
FIELD_TYPE_UNSIGNED,
FIELD_TYPE_STRING,
FIELD_TYPE_NUMBER,
+ FIELD_TYPE_DOUBLE,
FIELD_TYPE_INTEGER,
FIELD_TYPE_BOOLEAN,
FIELD_TYPE_VARBINARY,
diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc
index 9573ff1..3f8a0ce 100644
--- a/src/box/tuple_compare.cc
+++ b/src/box/tuple_compare.cc
@@ -122,6 +122,14 @@ mp_compare_bool(const char *field_a, const char *field_b)
}
static int
+mp_compare_double(const char *field_a, const char *field_b)
+{
+ double a_val = mp_decode_double(&field_a);
+ double b_val = mp_decode_double(&field_b);
+ return COMPARE_RESULT(a_val, b_val);
+}
+
+static int
mp_compare_integer_with_type(const char *field_a, enum mp_type a_type,
const char *field_b, enum mp_type b_type)
{
@@ -443,6 +451,8 @@ tuple_compare_field(const char *field_a, const char *field_b,
mp_typeof(*field_b));
case FIELD_TYPE_NUMBER:
return mp_compare_number(field_a, field_b);
+ case FIELD_TYPE_DOUBLE:
+ return mp_compare_double(field_a, field_b);
case FIELD_TYPE_BOOLEAN:
return mp_compare_bool(field_a, field_b);
case FIELD_TYPE_VARBINARY:
@@ -477,6 +487,8 @@ tuple_compare_field_with_type(const char *field_a, enum mp_type a_type,
case FIELD_TYPE_NUMBER:
return mp_compare_number_with_type(field_a, a_type,
field_b, b_type);
+ case FIELD_TYPE_DOUBLE:
+ return mp_compare_double(field_a, field_b);
case FIELD_TYPE_BOOLEAN:
return mp_compare_bool(field_a, field_b);
case FIELD_TYPE_VARBINARY:
@@ -1631,6 +1643,13 @@ field_hint_integer(const char *field)
}
static inline hint_t
+field_hint_double(const char *field)
+{
+ assert(mp_typeof(*field) == MP_DOUBLE);
+ return hint_double(mp_decode_double(&field));
+}
+
+static inline hint_t
field_hint_number(const char *field)
{
switch (mp_typeof(*field)) {
@@ -1753,6 +1772,8 @@ field_hint(const char *field, struct coll *coll)
return field_hint_integer(field);
case FIELD_TYPE_NUMBER:
return field_hint_number(field);
+ case FIELD_TYPE_DOUBLE:
+ return field_hint_double(field);
case FIELD_TYPE_STRING:
return field_hint_string(field, coll);
case FIELD_TYPE_VARBINARY:
@@ -1857,6 +1878,9 @@ key_def_set_hint_func(struct key_def *def)
case FIELD_TYPE_NUMBER:
key_def_set_hint_func<FIELD_TYPE_NUMBER>(def);
break;
+ case FIELD_TYPE_DOUBLE:
+ key_def_set_hint_func<FIELD_TYPE_DOUBLE>(def);
+ break;
case FIELD_TYPE_STRING:
key_def_set_hint_func<FIELD_TYPE_STRING>(def);
break;
diff --git a/test/engine/insert.result b/test/engine/insert.result
index 1015b6a..60c31a7 100644
--- a/test/engine/insert.result
+++ b/test/engine/insert.result
@@ -730,3 +730,154 @@ s:drop()
fiber = nil
---
...
+-- gh-3812: Make sure that DOUBLE field type works properly.
+ffi = require('ffi')
+---
+...
+s = box.schema.space.create('s', {format = {{'i', 'integer'}, {'d', 'double'}}})
+---
+...
+_ = s:create_index('ii')
+---
+...
+--
+-- If number of Lua type NUMBER is not integer, than it could be
+-- inserted in DOUBLE field.
+--
+s:insert({1, 1.1})
+---
+- [1, 1.1]
+...
+s:insert({2, 2.5})
+---
+- [2, 2.5]
+...
+s:insert({3, -3.0009})
+---
+- [3, -3.0009]
+...
+--
+-- Integers of Lua type NUMBER and CDATA of type int64 or uint64
+-- cannot be inserted into this field.
+--
+s:insert({4, 1})
+---
+- error: 'Tuple field 2 type does not match one required by operation: expected double'
+...
+s:insert({5, -9223372036854775800ULL})
+---
+- error: 'Tuple field 2 type does not match one required by operation: expected double'
+...
+s:insert({6, 18000000000000000000ULL})
+---
+- error: 'Tuple field 2 type does not match one required by operation: expected double'
+...
+--
+-- To insert an integer, we must cast it to a CDATA of type DOUBLE
+-- using ffi.cast(). Non-integers can also be inserted this way.
+--
+s:insert({7, ffi.cast('double', 1)})
+---
+- [7, 1]
+...
+s:insert({8, ffi.cast('double', -9223372036854775808)})
+---
+- [8, -9223372036854775808]
+...
+s:insert({9, ffi.cast('double', tonumber('123'))})
+---
+- [9, 123]
+...
+s:insert({10, ffi.cast('double', tonumber64('18000000000000000000'))})
+---
+- [10, 18000000000000000000]
+...
+s:insert({11, ffi.cast('double', 1.1)})
+---
+- [11, 1.1]
+...
+s:insert({12, ffi.cast('double', -3.0009)})
+---
+- [12, -3.0009]
+...
+s:select()
+---
+- - [1, 1.1]
+ - [2, 2.5]
+ - [3, -3.0009]
+ - [7, 1]
+ - [8, -9223372036854775808]
+ - [9, 123]
+ - [10, 18000000000000000000]
+ - [11, 1.1]
+ - [12, -3.0009]
+...
+-- The same rules apply to the key of this field:
+dd = s:create_index('dd', {unique = false, parts = {{2, 'double'}}})
+---
+...
+dd:select(1.1)
+---
+- - [1, 1.1]
+ - [11, 1.1]
+...
+dd:select(1)
+---
+- error: 'Supplied key type of part 0 does not match index part type: expected double'
+...
+dd:select(ffi.cast('double', 1))
+---
+- - [7, 1]
+...
+-- Make sure the comparisons work correctly.
+dd:select(1.1, {iterator = 'ge'})
+---
+- - [1, 1.1]
+ - [11, 1.1]
+ - [2, 2.5]
+ - [9, 123]
+ - [10, 18000000000000000000]
+...
+dd:select(1.1, {iterator = 'le'})
+---
+- - [11, 1.1]
+ - [1, 1.1]
+ - [7, 1]
+ - [12, -3.0009]
+ - [3, -3.0009]
+ - [8, -9223372036854775808]
+...
+dd:select(ffi.cast('double', 1.1), {iterator = 'gt'})
+---
+- - [2, 2.5]
+ - [9, 123]
+ - [10, 18000000000000000000]
+...
+dd:select(ffi.cast('double', 1.1), {iterator = 'lt'})
+---
+- - [7, 1]
+ - [12, -3.0009]
+ - [3, -3.0009]
+ - [8, -9223372036854775808]
+...
+dd:select(1.1, {iterator = 'all'})
+---
+- - [1, 1.1]
+ - [11, 1.1]
+ - [2, 2.5]
+ - [9, 123]
+ - [10, 18000000000000000000]
+...
+dd:select(1.1, {iterator = 'eq'})
+---
+- - [1, 1.1]
+ - [11, 1.1]
+...
+dd:select(1.1, {iterator = 'req'})
+---
+- - [11, 1.1]
+ - [1, 1.1]
+...
+s:drop()
+---
+...
diff --git a/test/engine/insert.test.lua b/test/engine/insert.test.lua
index 39b1501..a5d8a4c 100644
--- a/test/engine/insert.test.lua
+++ b/test/engine/insert.test.lua
@@ -123,3 +123,54 @@ s:select{}
s:drop()
fiber = nil
+-- gh-3812: Make sure that DOUBLE field type works properly.
+ffi = require('ffi')
+
+s = box.schema.space.create('s', {format = {{'i', 'integer'}, {'d', 'double'}}})
+_ = s:create_index('ii')
+
+--
+-- If number of Lua type NUMBER is not integer, than it could be
+-- inserted in DOUBLE field.
+--
+s:insert({1, 1.1})
+s:insert({2, 2.5})
+s:insert({3, -3.0009})
+
+--
+-- Integers of Lua type NUMBER and CDATA of type int64 or uint64
+-- cannot be inserted into this field.
+--
+s:insert({4, 1})
+s:insert({5, -9223372036854775800ULL})
+s:insert({6, 18000000000000000000ULL})
+
+--
+-- To insert an integer, we must cast it to a CDATA of type DOUBLE
+-- using ffi.cast(). Non-integers can also be inserted this way.
+--
+s:insert({7, ffi.cast('double', 1)})
+s:insert({8, ffi.cast('double', -9223372036854775808)})
+s:insert({9, ffi.cast('double', tonumber('123'))})
+s:insert({10, ffi.cast('double', tonumber64('18000000000000000000'))})
+s:insert({11, ffi.cast('double', 1.1)})
+s:insert({12, ffi.cast('double', -3.0009)})
+
+s:select()
+
+-- The same rules apply to the key of this field:
+dd = s:create_index('dd', {unique = false, parts = {{2, 'double'}}})
+dd:select(1.1)
+dd:select(1)
+dd:select(ffi.cast('double', 1))
+
+-- Make sure the comparisons work correctly.
+dd:select(1.1, {iterator = 'ge'})
+dd:select(1.1, {iterator = 'le'})
+dd:select(ffi.cast('double', 1.1), {iterator = 'gt'})
+dd:select(ffi.cast('double', 1.1), {iterator = 'lt'})
+dd:select(1.1, {iterator = 'all'})
+dd:select(1.1, {iterator = 'eq'})
+dd:select(1.1, {iterator = 'req'})
+
+s:drop()
--
2.7.4
More information about the Tarantool-patches
mailing list