Skip to content

Commit acdfa0f

Browse files
committed
schema: add support new _index system space format
After tarantool-1.7.5-153-g1651fc9be the new _index format was introduced. We should support it to fetch a schema from a tarantool-1.7.5.153+ instance. When an index parts do not use parameters except name and type the index info is stored in the old format in _index system space. When an index part uses is_nullable or collation parameter, then the new format will be used. Close #151
1 parent c2a464e commit acdfa0f

File tree

2 files changed

+116
-3
lines changed

2 files changed

+116
-3
lines changed

src/tarantool_schema.c

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,17 @@ strnindex(const char **haystack, const char *needle, uint32_t len, uint32_t hmax
230230
return hmax;
231231
}
232232

233+
/**
234+
* Strict compare a null-terminated string with a length specified
235+
* string.
236+
*/
237+
static inline bool
238+
strncmp_strict(const char *str, size_t str_len, const char *str_null_term)
239+
{
240+
return (strncmp(str, str_null_term, str_len) == 0 &&
241+
strlen(str_null_term) == str_len);
242+
}
243+
233244
static enum field_type
234245
field_type_by_name(const char *name, size_t len)
235246
{
@@ -275,6 +286,18 @@ parse_schema_space_value_value(struct schema_field_value *fld,
275286
return -1;
276287
}
277288

289+
/**
290+
* Initialization value.
291+
*/
292+
static const struct schema_field_value field_val_def = {
293+
.field_number = 0,
294+
.field_name_len = 0,
295+
.field_name = NULL,
296+
.field_type = field_type_MAX,
297+
.coll_id = COLL_NONE,
298+
.is_nullable = false
299+
};
300+
278301
static int
279302
parse_schema_space_value(struct schema_space_value *space_string,
280303
const char **tuple) {
@@ -314,6 +337,7 @@ decode_index_parts_166(struct schema_field_value *parts, uint32_t part_count,
314337
{
315338
for (uint32_t i = 0; i < part_count; ++i) {
316339
struct schema_field_value *part = &parts[i];
340+
*part = field_val_def;
317341
if (mp_typeof(**data) != MP_ARRAY)
318342
return -1;
319343
uint32_t item_count = mp_decode_array(data);
@@ -332,9 +356,69 @@ decode_index_parts_166(struct schema_field_value *parts, uint32_t part_count,
332356

333357
for (uint32_t j = 2; j < item_count; ++j)
334358
mp_next(data);
335-
/* Set default values. */
336-
part->is_nullable = false;
337-
part->coll_id = COLL_NONE;
359+
}
360+
return 0;
361+
}
362+
363+
static int
364+
decode_index_part(struct schema_field_value *part, uint32_t map_size,
365+
const char **data)
366+
{
367+
*part = field_val_def;
368+
for (uint32_t i = 0; i < map_size; ++i) {
369+
if (mp_typeof(**data) != MP_STR)
370+
return -1;
371+
372+
uint32_t k_len;
373+
const char *key = mp_decode_str(data, &k_len);
374+
if (strncmp_strict(key, k_len, "type")) {
375+
if (mp_typeof(**data) != MP_STR)
376+
return -1;
377+
uint32_t v_len;
378+
const char *val = mp_decode_str(data, &v_len);
379+
part->field_type = field_type_by_name(val, v_len);
380+
} else if (strncmp_strict(key, k_len, "field")) {
381+
if (mp_typeof(**data) != MP_UINT)
382+
return -1;
383+
part->field_number = mp_decode_uint(data);
384+
} else if (strncmp_strict(key, k_len, "collation")) {
385+
if (mp_typeof(**data) != MP_UINT)
386+
return -1;
387+
part->coll_id = mp_decode_uint(data);
388+
} else if (strncmp_strict(key, k_len, "is_nullable")) {
389+
if (mp_typeof(**data) != MP_BOOL)
390+
return -1;
391+
part->is_nullable = mp_decode_bool(data);
392+
} else {
393+
mp_next(data);
394+
}
395+
}
396+
397+
/* Collation is reasonable only for string and scalar parts. */
398+
if (part->coll_id != COLL_NONE &&
399+
part->field_type != FIELD_TYPE_STRING &&
400+
part->field_type != FIELD_TYPE_SCALAR) {
401+
return -1;
402+
}
403+
404+
return 0;
405+
}
406+
407+
/**
408+
* Decode parts array from tuple field.
409+
*/
410+
static int
411+
decode_index_parts(struct schema_field_value *parts, uint32_t part_count,
412+
const char **data)
413+
{
414+
for (uint32_t i = 0; i < part_count; ++i) {
415+
struct schema_field_value *part = &parts[i];
416+
if (mp_typeof(**data) != MP_MAP)
417+
return -1;
418+
419+
uint32_t map_size = mp_decode_map(data);
420+
if (decode_index_part(part, map_size, data) != 0)
421+
return -1;
338422
}
339423
return 0;
340424
}
@@ -355,8 +439,13 @@ parse_schema_index_value(struct schema_index_value *index_string,
355439
sizeof(struct schema_field_value));
356440

357441
if (mp_typeof(**tuple) == MP_ARRAY) {
442+
/* Base coding format is used. */
358443
return decode_index_parts_166(index_string->index_parts,
359444
part_count, tuple);
445+
} else {
446+
/* Extended coding format is used. */
447+
return decode_index_parts(index_string->index_parts,
448+
part_count, tuple);
360449
}
361450

362451
error:

test/shared/box.lua

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,30 @@ box.once('initialization', function()
134134
local tuple = yaml.decode(yml)[1]
135135
tuple[1] = "12345"
136136
box.space._schema:insert(tuple)
137+
138+
-- gh-151: Support new _index system space format
139+
-- After tarantool-1.7.5-153-g1651fc9be the new _index format
140+
-- was introduced. When an index part uses is_nullable or
141+
-- collation parameter, then the new format will be used.
142+
if tarantool_version_at_least(1, 7, 6, 0) then
143+
local test_new_format = box.schema.space.create('test_new_format', {
144+
format = {
145+
{type = compat.unsigned, name = 'f1'},
146+
{type = compat.unsigned, name = 'f2', is_nullable = true},
147+
{type = compat.string, name = 'f3'},
148+
}
149+
})
150+
151+
test_new_format:create_index('primary', {
152+
parts = {{1, compat.unsigned}}
153+
})
154+
test_new_format:create_index('secondary', {
155+
parts = {
156+
{2, compat.unsigned, is_nullable = true},
157+
{3, compat.string, collation = 'unicode_ci'}
158+
}
159+
})
160+
end
137161
end)
138162

139163
function test_1()

0 commit comments

Comments
 (0)