Skip to content

Commit

Permalink
box, datetime: datetime comparison for indices
Browse files Browse the repository at this point in the history
* storage hints implemented for datetime_t values;
* proper comparison for indices of datetime type.

Part of tarantool#5941
Part of tarantool#5946
  • Loading branch information
tsafin committed Jul 27, 2021
1 parent e1961ba commit 46027f6
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 4 deletions.
18 changes: 18 additions & 0 deletions src/box/field_def.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,21 @@ field_type_by_name(const char *name, size_t len)
return FIELD_TYPE_ANY;
return field_type_MAX;
}

const bool field_type_index_allowed[] =
{
/* [FIELD_TYPE_ANY] = */ false,
/* [FIELD_TYPE_UNSIGNED] = */ true,
/* [FIELD_TYPE_STRING] = */ true,
/* [FIELD_TYPE_NUMBER] = */ true,
/* [FIELD_TYPE_DOUBLE] = */ true,
/* [FIELD_TYPE_INTEGER] = */ true,
/* [FIELD_TYPE_BOOLEAN] = */ true,
/* [FIELD_TYPE_VARBINARY]= */ true,
/* [FIELD_TYPE_SCALAR] = */ true,
/* [FIELD_TYPE_DECIMAL] = */ true,
/* [FIELD_TYPE_UUID] = */ true,
/* [FIELD_TYPE_ARRAY] = */ false,
/* [FIELD_TYPE_MAP] = */ false,
/* [FIELD_TYPE_DATETIME] = */ true,
};
3 changes: 3 additions & 0 deletions src/box/field_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ extern const uint32_t field_ext_type[];
extern const struct opt_def field_def_reg[];
extern const struct field_def field_def_default;

/** helper table for checking allowed indices for types */
extern const bool field_type_index_allowed[];

/**
* @brief Field definition
* Contains information about of one tuple field.
Expand Down
3 changes: 1 addition & 2 deletions src/box/memtx_space.c
Original file line number Diff line number Diff line change
Expand Up @@ -748,8 +748,7 @@ memtx_space_check_index_def(struct space *space, struct index_def *index_def)
/* Check that there are no ANY, ARRAY, MAP parts */
for (uint32_t i = 0; i < key_def->part_count; i++) {
struct key_part *part = &key_def->parts[i];
if (part->type <= FIELD_TYPE_ANY ||
part->type >= FIELD_TYPE_ARRAY) {
if (!field_type_index_allowed[part->type]) {
diag_set(ClientError, ER_MODIFY_INDEX,
index_def->name, space_name(space),
tt_sprintf("field type '%s' is not supported",
Expand Down
30 changes: 30 additions & 0 deletions src/box/tuple_compare.cc
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,8 @@ tuple_compare_field_with_type(const char *field_a, enum mp_type a_type,
field_b, b_type);
case FIELD_TYPE_UUID:
return mp_compare_uuid(field_a, field_b);
case FIELD_TYPE_DATETIME:
return mp_compare_datetime(field_a, field_b);
default:
unreachable();
return 0;
Expand Down Expand Up @@ -1630,6 +1632,18 @@ hint_uuid_raw(const char *data)
return hint_create(MP_CLASS_UUID, val);
}

static inline hint_t
hint_datetime(struct datetime_t *date)
{
/*
* Use at most HINT_VALUE_BITS from datetime
* seconds field as a hint value
*/
uint64_t val = (uint64_t)date->secs & HINT_VALUE_MAX;

return hint_create(MP_CLASS_DATETIME, val);
}

static inline uint64_t
hint_str_raw(const char *s, uint32_t len)
{
Expand Down Expand Up @@ -1761,6 +1775,17 @@ field_hint_uuid(const char *field)
return hint_uuid_raw(data);
}

static inline hint_t
field_hint_datetime(const char *field)
{
assert(mp_typeof(*field) == MP_EXT);
int8_t ext_type;
uint32_t len = mp_decode_extl(&field, &ext_type);
assert(ext_type == MP_DATETIME);
struct datetime_t date;
return hint_datetime(datetime_unpack(&field, len, &date));
}

static inline hint_t
field_hint_string(const char *field, struct coll *coll)
{
Expand Down Expand Up @@ -1849,6 +1874,8 @@ field_hint(const char *field, struct coll *coll)
return field_hint_decimal(field);
case FIELD_TYPE_UUID:
return field_hint_uuid(field);
case FIELD_TYPE_DATETIME:
return field_hint_datetime(field);
default:
unreachable();
}
Expand Down Expand Up @@ -1963,6 +1990,9 @@ key_def_set_hint_func(struct key_def *def)
case FIELD_TYPE_UUID:
key_def_set_hint_func<FIELD_TYPE_UUID>(def);
break;
case FIELD_TYPE_DATETIME:
key_def_set_hint_func<FIELD_TYPE_DATETIME>(def);
break;
default:
/* Invalid key definition. */
def->key_hint = NULL;
Expand Down
3 changes: 1 addition & 2 deletions src/box/vinyl.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,8 +662,7 @@ vinyl_space_check_index_def(struct space *space, struct index_def *index_def)
/* Check that there are no ANY, ARRAY, MAP parts */
for (uint32_t i = 0; i < key_def->part_count; i++) {
struct key_part *part = &key_def->parts[i];
if (part->type <= FIELD_TYPE_ANY ||
part->type >= FIELD_TYPE_ARRAY) {
if (!field_type_index_allowed[part->type]) {
diag_set(ClientError, ER_MODIFY_INDEX,
index_def->name, space_name(space),
tt_sprintf("field type '%s' is not supported",
Expand Down
77 changes: 77 additions & 0 deletions test/engine/datetime.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
-- test-run result file version 2
env = require('test_run')
| ---
| ...
test_run = env.new()
| ---
| ...
engine = test_run:get_cfg('engine')
| ---
| ...

date = require('datetime')
| ---
| ...

_ = box.schema.space.create('T', {engine = engine})
| ---
| ...
_ = box.space.T:create_index('pk', {parts={1,'datetime'}})
| ---
| ...

box.space.T:insert{date('1970-01-01')}\
box.space.T:insert{date('1970-01-02')}\
box.space.T:insert{date('1970-01-03')}\
box.space.T:insert{date('2000-01-01')}
| ---
| ...

o = box.space.T:select{}
| ---
| ...
assert(tostring(o[1][1]) == '1970-01-01T00:00Z')
| ---
| - true
| ...
assert(tostring(o[2][1]) == '1970-01-02T00:00Z')
| ---
| - true
| ...
assert(tostring(o[3][1]) == '1970-01-03T00:00Z')
| ---
| - true
| ...
assert(tostring(o[4][1]) == '2000-01-01T00:00Z')
| ---
| - true
| ...

for i = 1,16 do\
box.space.T:insert{date.now()}\
end
| ---
| ...

a = box.space.T:select{}
| ---
| ...
err = nil
| ---
| ...
for i = 1, #a - 1 do\
if tostring(a[i][1]) >= tostring(a[i+1][1]) then\
err = {a[i][1], a[i+1][1]}\
break\
end\
end
| ---
| ...

err
| ---
| - null
| ...
box.space.T:drop()
| ---
| ...
35 changes: 35 additions & 0 deletions test/engine/datetime.test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
env = require('test_run')
test_run = env.new()
engine = test_run:get_cfg('engine')

date = require('datetime')

_ = box.schema.space.create('T', {engine = engine})
_ = box.space.T:create_index('pk', {parts={1,'datetime'}})

box.space.T:insert{date('1970-01-01')}\
box.space.T:insert{date('1970-01-02')}\
box.space.T:insert{date('1970-01-03')}\
box.space.T:insert{date('2000-01-01')}

o = box.space.T:select{}
assert(tostring(o[1][1]) == '1970-01-01T00:00Z')
assert(tostring(o[2][1]) == '1970-01-02T00:00Z')
assert(tostring(o[3][1]) == '1970-01-03T00:00Z')
assert(tostring(o[4][1]) == '2000-01-01T00:00Z')

for i = 1,16 do\
box.space.T:insert{date.now()}\
end

a = box.space.T:select{}
err = nil
for i = 1, #a - 1 do\
if tostring(a[i][1]) >= tostring(a[i+1][1]) then\
err = {a[i][1], a[i+1][1]}\
break\
end\
end

err
box.space.T:drop()

0 comments on commit 46027f6

Please sign in to comment.