Skip to content

Commit 20a62e1

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 347281f commit 20a62e1

File tree

2 files changed

+120
-3
lines changed

2 files changed

+120
-3
lines changed

src/tarantool_schema.c

+96-3
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);
@@ -329,12 +353,76 @@ decode_index_parts_166(struct schema_field_value *parts, uint32_t part_count,
329353
uint32_t len;
330354
const char *str = mp_decode_str(data, &len);
331355
part->field_type = field_type_by_name(str, len);
356+
if (part->field_type == field_type_MAX)
357+
return -1;
332358

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

357445
if (mp_typeof(**tuple) == MP_ARRAY) {
446+
/* Base coding format is used. */
358447
return decode_index_parts_166(index_string->index_parts,
359448
part_count, tuple);
449+
} else {
450+
/* Extended coding format is used. */
451+
return decode_index_parts(index_string->index_parts,
452+
part_count, tuple);
360453
}
361454

362455
error:

test/shared/box.lua

+24
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)