Skip to content

Support new _index format #164

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ dist: xenial

language: php

# gh-151: disable tarantoo-2.2 due to lack of support the new
# _index format.
#
# Disable tarantool-1.6 and 1.7 on php 7.1-7.4, because
# php-7.[1-4]-cli docker images are based on Debian Buster, but we
# have no tarantool-1.[6-7] packages for this distribution.
Expand All @@ -23,8 +20,8 @@ jobs:
env: TARANTOOL_VERSION=1.10
- php: 7.0
env: TARANTOOL_VERSION=2.1
# - php: 7.0
# env: TARANTOOL_VERSION=2.2
- php: 7.0
env: TARANTOOL_VERSION=2.2
- php: 7.0
env: TARANTOOL_VERSION=2.3
- php: 7.0
Expand All @@ -40,8 +37,8 @@ jobs:
env: TARANTOOL_VERSION=1.10
- php: 7.1
env: TARANTOOL_VERSION=2.1
# - php: 7.1
# env: TARANTOOL_VERSION=2.2
- php: 7.1
env: TARANTOOL_VERSION=2.2
- php: 7.1
env: TARANTOOL_VERSION=2.3
- php: 7.1
Expand All @@ -58,7 +55,7 @@ jobs:
- php: 7.2
env: TARANTOOL_VERSION=2.1
# - php: 7.2
# env: TARANTOOL_VERSION=2.2
env: TARANTOOL_VERSION=2.2
- php: 7.2
env: TARANTOOL_VERSION=2.3
- php: 7.2
Expand All @@ -75,7 +72,7 @@ jobs:
- php: 7.3
env: TARANTOOL_VERSION=2.1
# - php: 7.3
# env: TARANTOOL_VERSION=2.2
env: TARANTOOL_VERSION=2.2
- php: 7.3
env: TARANTOOL_VERSION=2.3
- php: 7.3
Expand All @@ -92,7 +89,7 @@ jobs:
- php: 7.4
env: TARANTOOL_VERSION=2.1
# - php: 7.4
# env: TARANTOOL_VERSION=2.2
env: TARANTOOL_VERSION=2.2
- php: 7.4
env: TARANTOOL_VERSION=2.3
- php: 7.4
Expand Down
2 changes: 2 additions & 0 deletions config.m4
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
dnl config.m4 for extension tarantool
dnl set C compiler to C99 mode
AC_PROG_CC_C99
PHP_ARG_ENABLE(tarantool, for tarantool support,
[ --enable-tarantool Enable tarantool support])

Expand Down
229 changes: 191 additions & 38 deletions src/tarantool_schema.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ schema_index_value_free(const struct schema_index_value *val) {
}
}

static inline void
static void
schema_index_free(struct mh_schema_index_t *schema) {
int pos = 0;
mh_int_t index_slot = 0;
Expand Down Expand Up @@ -146,7 +146,7 @@ mh_spacecmp_key_eq(
#define MH_DEBUG 1
#include "third_party/mhash.h"

static inline void
static void
schema_space_value_free(const struct schema_space_value *val) {
if (val) {
pefree(val->space_name, 1);
Expand All @@ -161,7 +161,7 @@ schema_space_value_free(const struct schema_space_value *val) {
}
}

static inline void
static void
schema_space_free(struct mh_schema_space_t *schema) {
int pos = 0;
mh_int_t space_slot = 0;
Expand Down Expand Up @@ -198,40 +198,90 @@ schema_space_free(struct mh_schema_space_t *schema) {
}
}

int parse_field_type(const char *sfield, size_t sfield_len) {
if (sfield_len == 3) {
if (tolower(sfield[0]) == 's' &&
tolower(sfield[1]) == 't' &&
tolower(sfield[2]) == 'r')
return FT_STR;
if (tolower(sfield[0]) == 'n' &&
tolower(sfield[1]) == 'u' &&
tolower(sfield[2]) == 'm')
return FT_NUM;
static const char *field_type_strs[] = {
/* [FIELD_TYPE_ANY] = */ "any",
/* [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",
/* [FIELD_TYPE_SCALAR] = */ "scalar",
/* [FIELD_TYPE_DECIMAL] = */ "decimal",
/* [FIELD_TYPE_UUID] = */ "uuid",
/* [FIELD_TYPE_ARRAY] = */ "array",
/* [FIELD_TYPE_MAP] = */ "map",
};

/**
* Find a string in an array of strings.
*/
static uint32_t
strnindex(const char **haystack, const char *needle, uint32_t len, uint32_t hmax)
{
if (len == 0)
return hmax;
for (unsigned index = 0; index != hmax && haystack[index]; ++index) {
if (strncasecmp(haystack[index], needle, len) == 0 &&
strlen(haystack[index]) == len)
return index;
}
return FT_OTHER;
return hmax;
}

/**
* Strict compare a null-terminated string with a length specified
* string.
*/
static inline bool
strncmp_strict(const char *str, size_t str_len, const char *str_null_term)
{
return (strncmp(str, str_null_term, str_len) == 0 &&
strlen(str_null_term) == str_len);
}

static inline int
static enum field_type
field_type_by_name(const char *name, size_t len)
{
enum field_type field_type = strnindex(field_type_strs, name, len,
field_type_MAX);
if (field_type != field_type_MAX)
return field_type;
/* 'num' and 'str' in _index are deprecated since Tarantool 1.7 */
if (strncasecmp(name, "num", len) == 0)
return FIELD_TYPE_UNSIGNED;
else if (strncasecmp(name, "str", len) == 0)
return FIELD_TYPE_STRING;
else if (len == 1 && name[0] == '*')
return FIELD_TYPE_ANY;
return field_type_MAX;
}

static int
parse_schema_space_value_value(struct schema_field_value *fld,
const char **tuple) {
uint32_t sfield_len = 0;
if (mp_typeof(**tuple) != MP_STR)
goto error;
const char *sfield = mp_decode_str(tuple, &sfield_len);
if (memcmp(sfield, "name", sfield_len) == 0) {
if (strncmp_strict(sfield, sfield_len, "name")) {
if (mp_typeof(**tuple) != MP_STR)
goto error;
sfield = mp_decode_str(tuple, &fld->field_name_len);
fld->field_name = pemalloc(fld->field_name_len, 1);
if (!fld->field_name)
goto error;
memcpy(fld->field_name, sfield, fld->field_name_len);
} else if (memcmp(sfield, "type", sfield_len) == 0) {
} else if (strncmp_strict(sfield, sfield_len, "type")) {
if (mp_typeof(**tuple) != MP_STR)
goto error;
sfield = mp_decode_str(tuple, &sfield_len);
fld->field_type = parse_field_type(sfield, sfield_len);
fld->field_type = field_type_by_name(sfield, sfield_len);
} else if (strncmp_strict(sfield, sfield_len, "is_nullable")) {
if (mp_typeof(**tuple) != MP_BOOL)
goto error;
fld->is_nullable = mp_decode_bool(tuple);
} else {
mp_next(tuple);
}
Expand All @@ -240,7 +290,19 @@ parse_schema_space_value_value(struct schema_field_value *fld,
return -1;
}

static inline int
/**
* Initialization value.
*/
static const struct schema_field_value field_val_def = {
.field_number = 0,
.field_name_len = 0,
.field_name = NULL,
.field_type = field_type_MAX,
.coll_id = COLL_NONE,
.is_nullable = false
};

static int
parse_schema_space_value(struct schema_space_value *space_string,
const char **tuple) {
uint32_t fmp_tmp_len = 0;
Expand All @@ -255,6 +317,7 @@ parse_schema_space_value(struct schema_space_value *space_string,
int i = 0;
for (i = 0; i < fmt_len; ++i) {
struct schema_field_value *val = &(space_string->schema_list[i]);
*val = field_val_def;
if (mp_typeof(**tuple) != MP_MAP)
goto error;
uint32_t arrsz = mp_decode_map(tuple);
Expand All @@ -269,7 +332,103 @@ parse_schema_space_value(struct schema_space_value *space_string,
return -1;
}

static inline int
/**
* 1.6.6-1.7.5
* Decode parts array from tuple field.
*/
static int
decode_index_parts_166(struct schema_field_value *parts, uint32_t part_count,
const char **data)
{
for (uint32_t i = 0; i < part_count; ++i) {
struct schema_field_value *part = &parts[i];
*part = field_val_def;
if (mp_typeof(**data) != MP_ARRAY)
return -1;
uint32_t item_count = mp_decode_array(data);
if (item_count < 2)
return -1;

if (mp_typeof(**data) != MP_UINT)
return -1;
part->field_number = mp_decode_uint(data);

if (mp_typeof(**data) != MP_STR)
return -1;
uint32_t len;
const char *str = mp_decode_str(data, &len);
part->field_type = field_type_by_name(str, len);

for (uint32_t j = 2; j < item_count; ++j)
mp_next(data);
}
return 0;
}

static int
decode_index_part(struct schema_field_value *part, uint32_t map_size,
const char **data)
{
*part = field_val_def;
for (uint32_t i = 0; i < map_size; ++i) {
if (mp_typeof(**data) != MP_STR)
return -1;

uint32_t k_len;
const char *key = mp_decode_str(data, &k_len);
if (strncmp_strict(key, k_len, "type")) {
if (mp_typeof(**data) != MP_STR)
return -1;
uint32_t v_len;
const char *val = mp_decode_str(data, &v_len);
part->field_type = field_type_by_name(val, v_len);
} else if (strncmp_strict(key, k_len, "field")) {
if (mp_typeof(**data) != MP_UINT)
return -1;
part->field_number = mp_decode_uint(data);
} else if (strncmp_strict(key, k_len, "collation")) {
if (mp_typeof(**data) != MP_UINT)
return -1;
part->coll_id = mp_decode_uint(data);
} else if (strncmp_strict(key, k_len, "is_nullable")) {
if (mp_typeof(**data) != MP_BOOL)
return -1;
part->is_nullable = mp_decode_bool(data);
} else {
mp_next(data);
}
}

/* Collation is reasonable only for string and scalar parts. */
if (part->coll_id != COLL_NONE &&
part->field_type != FIELD_TYPE_STRING &&
part->field_type != FIELD_TYPE_SCALAR) {
return -1;
}

return 0;
}

/**
* Decode parts array from tuple field.
*/
static int
decode_index_parts(struct schema_field_value *parts, uint32_t part_count,
const char **data)
{
for (uint32_t i = 0; i < part_count; ++i) {
struct schema_field_value *part = &parts[i];
if (mp_typeof(**data) != MP_MAP)
return -1;

uint32_t map_size = mp_decode_map(data);
if (decode_index_part(part, map_size, data) != 0)
return -1;
}
return 0;
}

static int
parse_schema_index_value(struct schema_index_value *index_string,
const char **tuple) {
if (mp_typeof(**tuple) != MP_ARRAY)
Expand All @@ -283,28 +442,22 @@ parse_schema_index_value(struct schema_index_value *index_string,
goto error;
memset(index_string->index_parts, 0, part_count *
sizeof(struct schema_field_value));
int i = 0;
for (i = 0; i < part_count; ++i) {
if (mp_typeof(**tuple) != MP_ARRAY)
goto error;
if (mp_decode_array(tuple) != 2)
goto error;
struct schema_field_value *val = &(index_string->index_parts[i]);
if (mp_typeof(**tuple) != MP_UINT)
goto error;
val->field_number = mp_decode_uint(tuple);
uint32_t sfield_len = 0;
if (mp_typeof(**tuple) != MP_STR)
goto error;
const char *sfield = mp_decode_str(tuple, &sfield_len);
val->field_type = parse_field_type(sfield, sfield_len);

if (mp_typeof(**tuple) == MP_ARRAY) {
/* Base coding format is used. */
return decode_index_parts_166(index_string->index_parts,
part_count, tuple);
} else {
/* Extended coding format is used. */
return decode_index_parts(index_string->index_parts,
part_count, tuple);
}
return 0;

error:
return -1;
}

static inline int
static int
schema_add_space(
struct mh_schema_space_t *schema,
const char **data
Expand Down Expand Up @@ -421,7 +574,7 @@ tarantool_schema_add_spaces(
return -1;
}

static inline int schema_add_index(
static int schema_add_index(
struct mh_schema_space_t *schema,
const char **data
) {
Expand Down
Loading