diff --git a/src/box/alter.cc b/src/box/alter.cc index d1d5002f5b7900379ac4cb7c80d44b372de8faf7..6187135588e0dae9f8fa2cecb9d76bd89af7c104 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -105,74 +105,66 @@ access_check_ddl(uint32_t owner_uid) } } +const char * +map_field_get(const char *map, const char *needle, int needle_type, + int map_field_no) +{ + if (map == NULL || mp_typeof(*map) != MP_MAP) { + tnt_raise(ClientError, ER_FIELD_TYPE, + map_field_no + INDEX_OFFSET, "map"); + } + uint32_t map_size = mp_decode_map(&map); + for (uint32_t i = 0; i < map_size; i++) { + const char *key; + uint32_t len; + if (mp_typeof(*map) != MP_STR) { + tnt_raise(ClientError, ER_FIELD_TYPE, + map_field_no + INDEX_OFFSET, + "map key type"); + } + key = mp_decode_str(&map, &len); + if (len != strlen(needle) || + strncasecmp(key, needle, len) != 0) { + + mp_next(&map); + continue; + } + if (mp_typeof(*map) != needle_type) { + tnt_raise(ClientError, ER_FIELD_TYPE, + map_field_no + INDEX_OFFSET, + "map value type"); + } + return map; + } + return NULL; +} /** Fill key_opts structure from opts field in tuple of space _index */ void -key_opts_create_from_field(struct key_opts *opts, const char *field) +key_opts_create_from_field(struct key_opts *opts, const char *map) { - key_opts_create(opts); - if (field == NULL) + *opts = key_opts_default; + if (map == NULL) return; - if (mp_typeof(*field) != MP_MAP) { - tnt_raise(ClientError, ER_FIELD_TYPE, INDEX_OPTS + INDEX_OFFSET, - "map"); - } - uint32_t map_size = mp_decode_map(&field); - for (uint32_t i = 0; i < map_size; i++) { - const char *key; + const char *field; + + if ((field = map_field_get(map, "unique", MP_BOOL, INDEX_OPTS))) + opts->is_unique = mp_decode_bool(&field); + if ((field = map_field_get(map, "dimension", MP_UINT, INDEX_OPTS))) + opts->dimension = mp_decode_uint(&field); + if ((field = map_field_get(map, "distance", MP_STR, INDEX_OPTS))) { uint32_t len; - if (mp_typeof(*field) != MP_STR) { + const char *distance = mp_decode_str(&field, &len); + distance = tuple_field_to_cstr(distance, len); + + enum rtree_index_distance_type distance_type = + STR2ENUM(rtree_index_distance_type, distance); + if (distance_type == rtree_index_distance_type_MAX) { tnt_raise(ClientError, - ER_FIELD_TYPE, INDEX_OPTS + INDEX_OFFSET, - "string"); - } - key = mp_decode_str(&field, &len); - if (len == strlen("unique") && - memcmp(key, "unique", len) == 0) { - if (mp_typeof(*field) != MP_BOOL) { - tnt_raise(ClientError, - ER_FIELD_TYPE, - INDEX_OPTS + INDEX_OFFSET, - "bool"); - } - opts->is_unique = mp_decode_bool(&field); - } else if (len == strlen("dimension") && - memcmp(key, "dimension", len) == 0) { - if (mp_typeof(*field) != MP_UINT) { - tnt_raise(ClientError, - ER_FIELD_TYPE, - INDEX_OPTS + INDEX_OFFSET, - "unsigned"); - } - opts->dimension = mp_decode_uint(&field); - } else if (len == strlen("distance") && - memcmp(key, "distance", len) == 0) { - if (mp_typeof(*field) != MP_STR) { - tnt_raise(ClientError, - ER_FIELD_TYPE, - INDEX_OPTS + INDEX_OFFSET, - "unsigned"); - } - const char *str_distance; - uint32_t distance_len; - str_distance = mp_decode_str(&field, &distance_len); - if (distance_len == strlen("euclid") && - memcmp(str_distance, "euclid", - distance_len) == 0) { - opts->distance = EUCLID; - } else if (distance_len == strlen("manhattan") && - memcmp(str_distance, "manhattan", - distance_len) == 0) { - opts->distance = MANHATTAN; - } else { - tnt_raise(ClientError, - ER_FIELD_TYPE, - INDEX_OPTS + INDEX_OFFSET, - "string euclid/manhattan"); - } - } else { - mp_next(&field); + ER_UNKNOWN_RTREE_INDEX_DISTANCE_TYPE, + distance); } + opts->distance = distance_type; } } @@ -208,10 +200,16 @@ key_def_new_from_tuple(struct tuple *tuple) part_count = mp_decode_array(&parts); } else { /* 1.6.5 _index space structure */ - key_opts_create(&opts); + opts = key_opts_default; opts.is_unique = tuple_field_u32(tuple, INDEX_165_IS_UNIQUE); part_count = tuple_field_u32(tuple, INDEX_165_PART_COUNT); } + /** + * XXX this is an ugly clutch in absence of Lua-level + * index-type specific defaults. + */ + if (opts.dimension == 0 && type == RTREE) + opts.dimension = 2; key_def = key_def_new(id, index_id, name, type, &opts, part_count); auto scoped_guard = make_scoped_guard([=] { key_def_delete(key_def); }); diff --git a/src/box/errcode.h b/src/box/errcode.h index 13a776a7242f59cba8fcc84c4f939ec0f5041597..57008e1b1f1405ed50fac53c4c0732f0d91b762d 100644 --- a/src/box/errcode.h +++ b/src/box/errcode.h @@ -156,6 +156,7 @@ struct errcode_record { /*100 */_(ER_FUNCTION_LANGUAGE, 2, "Unsupported language '%s' specified for function '%s'") \ /*101 */_(ER_RTREE_RECT, 2, "RTree: %s must be an array with %u (point) or %u (rectangle/box) numeric coordinates") \ /*102 */_(ER_PROC_C, 2, "%s") \ + /*103 */_(ER_UNKNOWN_RTREE_INDEX_DISTANCE_TYPE, 2, "Unknown RTREE index distance type %s") \ /* * !IMPORTANT! Please follow instructions at start of the file diff --git a/src/box/key_def.cc b/src/box/key_def.cc index 1b42d5ceb0492d83a8ae70080f6b2f9ff6f1621b..c898674434005151c77de2c412ee3f642c544352 100644 --- a/src/box/key_def.cc +++ b/src/box/key_def.cc @@ -36,7 +36,8 @@ const char *field_type_strs[] = {"UNKNOWN", "NUM", "STR", "ARRAY", "NUMBER", ""}; STRS(index_type, ENUM_INDEX_TYPE); -STRS(distance_type, ENUM_DISTANCE_TYPE); + +const char *rtree_index_distance_type_strs[] = { "EUCLID", "MANHATTAN" }; const char *func_language_strs[] = {"LUA", "C"}; @@ -48,6 +49,10 @@ const uint32_t key_mp_type[] = { /* [NUMBER] = */ (1U << MP_UINT) | (1U << MP_INT) | (1U << MP_FLOAT) | (1U << MP_DOUBLE), }; +const struct key_opts key_opts_default = { + true, 0, RTREE_INDEX_DISTANCE_TYPE_EUCLID +}; + enum schema_object_type schema_object_type(const char *name) { diff --git a/src/box/key_def.h b/src/box/key_def.h index 9c76a48c0abc60f85d4dc16d23737a319dbf62a9..c9e6e74976b4dcec197c9ac8420a44d7ddc83910 100644 --- a/src/box/key_def.h +++ b/src/box/key_def.h @@ -99,12 +99,14 @@ field_type_maxlen(enum field_type type) ENUM(index_type, ENUM_INDEX_TYPE); extern const char *index_type_strs[]; -#define ENUM_DISTANCE_TYPE(_) \ - _(EUCLID, 0) /* Euclid distance, sqrt(dx*dx + dy*dy) */ \ - _(MANHATTAN, 1) /* Manhattan distance, fabs(dx) + fabs(dy) */ \ - -ENUM(distance_type, ENUM_DISTANCE_TYPE); -extern const char *distance_type_strs[]; +enum rtree_index_distance_type { + /* Euclid distance, sqrt(dx*dx + dy*dy) */ + RTREE_INDEX_DISTANCE_TYPE_EUCLID, + /* Manhattan distance, fabs(dx) + fabs(dy) */ + RTREE_INDEX_DISTANCE_TYPE_MANHATTAN, + rtree_index_distance_type_MAX +}; +extern const char *rtree_index_distance_type_strs[]; /** Descriptor of a single part in a multipart key. */ struct key_part { @@ -126,16 +128,10 @@ struct key_opts { /** * RTREE distance type. */ - distance_type distance; + enum rtree_index_distance_type distance; }; -static inline void -key_opts_create(struct key_opts *opts) -{ - opts->is_unique = true; - opts->dimension = 2; - opts->distance = EUCLID; -} +extern const struct key_opts key_opts_default; static inline int key_opts_cmp(const struct key_opts *o1, const struct key_opts *o2) diff --git a/src/box/memtx_rtree.cc b/src/box/memtx_rtree.cc index 1cdda13d9fd827889579eb716ab3c5c49f6cd288..6c773d89e61b90c09aa7c2170c02aa519ef81282 100644 --- a/src/box/memtx_rtree.cc +++ b/src/box/memtx_rtree.cc @@ -163,8 +163,8 @@ MemtxRTree::MemtxRTree(struct key_def *key_def) } memtx_index_arena_init(); - assert((int)RTREE_EUCLID == (int)EUCLID); - assert((int)RTREE_MANHATTAN == (int)MANHATTAN); + assert((int)RTREE_EUCLID == (int)RTREE_INDEX_DISTANCE_TYPE_EUCLID); + assert((int)RTREE_MANHATTAN == (int)RTREE_INDEX_DISTANCE_TYPE_MANHATTAN); enum rtree_distance_type distance_type = (enum rtree_distance_type)(int)key_def->opts.distance; rtree_init(&m_tree, m_dimension, MEMTX_EXTENT_SIZE, diff --git a/src/box/schema.cc b/src/box/schema.cc index 0aea928ebe3e3be3711f39fa5ac87a6fb514b7e3..c6133cad13c12c3959acddc1ca636078564aab91 100644 --- a/src/box/schema.cc +++ b/src/box/schema.cc @@ -250,9 +250,7 @@ schema_init() struct space_def def = { BOX_SCHEMA_ID, ADMIN, 0, "_schema", "memtx", false }; - struct key_opts opts = { true /* is_unique */, - 0 /* dimension */, - EUCLID /* distance */}; + struct key_opts opts = key_opts_default; struct key_def *key_def = key_def_new(def.id, 0 /* index id */, "primary", /* name */ diff --git a/src/box/sophia_engine.cc b/src/box/sophia_engine.cc index 9a004ded9d907c65f1ec50c424acb69942715928..a70423b6aa351fe5e6da2e43d09ae2c14c30861f 100644 --- a/src/box/sophia_engine.cc +++ b/src/box/sophia_engine.cc @@ -320,9 +320,7 @@ sophia_join_key_def(void *env, void *db) uint32_t id = sp_getint(db, "id"); uint32_t count = sp_getint(db, "key-count"); struct key_def *key_def; - struct key_opts key_opts = { true /* is_unique */, - 0 /* dimension */, - EUCLID /* distance */ }; + struct key_opts key_opts = key_opts_default; key_def = key_def_new(id, 0, "sophia_join", TREE, &key_opts, count); int i = 0; while (i < count) { diff --git a/src/box/tuple.cc b/src/box/tuple.cc index 25836fde3ca7d2daf4a2bb9743e9df65954b5a8f..6aa2f2df5ec7dfd81ee9141cca9e4fd639636aa2 100644 --- a/src/box/tuple.cc +++ b/src/box/tuple.cc @@ -365,11 +365,15 @@ tuple_next(struct tuple_iterator *it) extern inline uint32_t tuple_next_u32(struct tuple_iterator *it); -static const char * +const char * tuple_field_to_cstr(const char *field, uint32_t len) { - static __thread char buf[256]; - len = MIN(len, sizeof(buf) - 1); + enum { MAX_STR_BUFS = 3, MAX_BUF_LEN = 256 }; + static __thread char bufs[MAX_STR_BUFS][MAX_BUF_LEN]; + static __thread int i = 0; + char *buf = bufs[i]; + i = (i + 1) % MAX_STR_BUFS; + len = MIN(len, MAX_BUF_LEN - 1); memcpy(buf, field, len); buf[len] = '\0'; return buf; diff --git a/src/box/tuple.h b/src/box/tuple.h index 315f6eb410d853d31908cfa9bb678a7b27ce784d..98396201365543f3c9ed78658a66a7c9f6547828 100644 --- a/src/box/tuple.h +++ b/src/box/tuple.h @@ -390,6 +390,10 @@ tuple_field_num(const struct tuple* tuple, uint32_t field_no) const char * tuple_field_cstr(struct tuple *tuple, uint32_t i); +/** Helper method for the above function. */ +const char * +tuple_field_to_cstr(const char *field, uint32_t len); + /** * @brief Tuple Interator */ diff --git a/test/box/misc.result b/test/box/misc.result index 0a4bd84df56668356e4478b72fc3fdfbbecf6c08..03daae50f2ebdc57bdd98d77c9b7104cbb3c87d3 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -250,6 +250,7 @@ t; - 'box.error.CREATE_FUNCTION : 50' - 'box.error.SOPHIA : 60' - 'box.error.NO_SUCH_INDEX : 35' + - 'box.error.UNKNOWN_RTREE_INDEX_DISTANCE_TYPE : 103' - 'box.error.TUPLE_IS_TOO_LONG : 27' - 'box.error.UNKNOWN_SERVER : 62' - 'box.error.FUNCTION_EXISTS : 52'