From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 9662446970E for ; Sat, 21 Dec 2019 19:03:10 +0300 (MSK) From: imeevma@tarantool.org Date: Sat, 21 Dec 2019 19:03:09 +0300 Message-Id: <6faa3090e13cd9317baf619aa17716251c7faa27.1576944064.git.imeevma@gmail.com> In-Reply-To: References: Subject: [Tarantool-patches] [PATCH v1 1/2] box: introduce DOUBLE field type List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: v.shpilevoy@tarantool.org Cc: tarantool-patches@dev.tarantool.org 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(def); break; + case FIELD_TYPE_DOUBLE: + key_def_set_hint_func(def); + break; case FIELD_TYPE_STRING: key_def_set_hint_func(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