[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