[tarantool-patches] Re: [PATCH v1 1/1] box: introduce VARBINARY field type

Konstantin Osipov kostja at tarantool.org
Thu Jun 27 11:01:32 MSK 2019


* Kirill Shcherbatov <kshcherbatov at tarantool.org> [19/06/27 10:40]:
> > please add docbot request.
> 
> In fact, I did not include TarantoolBot query consciously: this patch is preparatory for #4206, and only
> introduces a new field type, while preparing data corresponding to this field in Tarantool now
> is not easy (see the test case below).
> 
> But in general, the documentation may be updated. So I've updated a commit message.

since it's usable in format/index definitions, it's an external
behaviour change and has to be documented. Actually it's going to
be a sweeping changes in many places in the docs, since the type
system has multiple mentions in the docs.

> ==========================================
> 
> A new VARBINARY field type would be useful for SQL type system.
> 
> Closes #4201
> Needed for #4206
> 
> @TarantoolBot document
> Title: new varbinary field type
> 
> Introduced a new field type varbinary to represent mp_bin values.
> The new type varbinary may be used in format or index definition.
> 
> Example:
> s = box.schema.space.create('withdata')
> s:format({{"b", "varbinary"}})
> pk = s:create_index('pk', {parts = {1, "varbinary"}})
> ---
>  src/box/field_def.c              |  23 +++--
>  src/box/field_def.h              |   1 +
>  src/box/lua/key_def.c            |   1 +
>  src/box/tuple_compare.cc         |  17 ++++
>  test/box/varbinary_type.result   | 152 +++++++++++++++++++++++++++++++
>  test/box/varbinary_type.test.lua |  51 +++++++++++
>  6 files changed, 235 insertions(+), 10 deletions(-)
>  create mode 100644 test/box/varbinary_type.result
>  create mode 100644 test/box/varbinary_type.test.lua
> 
> diff --git a/src/box/field_def.c b/src/box/field_def.c
> index 0ba3d3294..346042b98 100644
> --- a/src/box/field_def.c
> +++ b/src/box/field_def.c
> @@ -55,6 +55,7 @@ const uint32_t field_mp_type[] = {
>  		(1U << MP_FLOAT) | (1U << MP_DOUBLE),
>  	/* [FIELD_TYPE_INTEGER]  =  */ (1U << MP_UINT) | (1U << MP_INT),
>  	/* [FIELD_TYPE_BOOLEAN]  =  */ 1U << MP_BOOL,
> +	/* [FIELD_TYPE_VARBINARY] =  */ 1U << MP_BIN,
>  	/* [FIELD_TYPE_SCALAR]   =  */ (1U << MP_UINT) | (1U << MP_INT) |
>  		(1U << MP_FLOAT) | (1U << MP_DOUBLE) | (1U << MP_STR) |
>  		(1U << MP_BIN) | (1U << MP_BOOL),
> @@ -69,6 +70,7 @@ const char *field_type_strs[] = {
>  	/* [FIELD_TYPE_NUMBER]   = */ "number",
>  	/* [FIELD_TYPE_INTEGER]  = */ "integer",
>  	/* [FIELD_TYPE_BOOLEAN]  = */ "boolean",
> +	/* [FIELD_TYPE_VARBINARY] = */"varbinary",
>  	/* [FIELD_TYPE_SCALAR]   = */ "scalar",
>  	/* [FIELD_TYPE_ARRAY]    = */ "array",
>  	/* [FIELD_TYPE_MAP]      = */ "map",
> @@ -96,16 +98,17 @@ field_type_by_name_wrapper(const char *str, uint32_t len)
>   * values can be stored in the j type.
>   */
>  static const bool field_type_compatibility[] = {
> -	   /*   ANY   UNSIGNED  STRING   NUMBER  INTEGER  BOOLEAN   SCALAR   ARRAY     MAP */
> -/*   ANY    */ true,   false,   false,   false,   false,   false,   false,   false,   false,
> -/* UNSIGNED */ true,   true,    false,   true,    true,    false,   true,    false,   false,
> -/*  STRING  */ true,   false,   true,    false,   false,   false,   true,    false,   false,
> -/*  NUMBER  */ true,   false,   false,   true,    false,   false,   true,    false,   false,
> -/*  INTEGER */ true,   false,   false,   true,    true,    false,   true,    false,   false,
> -/*  BOOLEAN */ true,   false,   false,   false,   false,   true,    true,    false,   false,
> -/*  SCALAR  */ true,   false,   false,   false,   false,   false,   true,    false,   false,
> -/*   ARRAY  */ true,   false,   false,   false,   false,   false,   false,   true,    false,
> -/*    MAP   */ true,   false,   false,   false,   false,   false,   false,   false,   true,
> +	   /*   ANY   UNSIGNED  STRING   NUMBER  INTEGER  BOOLEAN VARBINARY SCALAR   ARRAY     MAP */
> +/*   ANY    */ true,   false,   false,   false,   false,   false,   false,  false,   false,   false,
> +/* UNSIGNED */ true,   true,    false,   true,    true,    false,   false,  true,    false,   false,
> +/*  STRING  */ true,   false,   true,    false,   false,   false,   false,  true,    false,   false,
> +/*  NUMBER  */ true,   false,   false,   true,    false,   false,   false,  true,    false,   false,
> +/*  INTEGER */ true,   false,   false,   true,    true,    false,   false,  true,    false,   false,
> +/*  BOOLEAN */ true,   false,   false,   false,   false,   true,    false,  true,    false,   false,
> +/* VARBINARY*/ true,   false,   false,   false,   false,   false,   true,   true,    false,   false,
> +/*  SCALAR  */ true,   false,   false,   false,   false,   false,   false,  true,    false,   false,
> +/*   ARRAY  */ true,   false,   false,   false,   false,   false,   false,  false,   true,    false,
> +/*    MAP   */ true,   false,   false,   false,   false,   false,   false,  false,   false,   true,
>  };
>  
>  bool
> diff --git a/src/box/field_def.h b/src/box/field_def.h
> index f944de9d6..c1a7ec0a9 100644
> --- a/src/box/field_def.h
> +++ b/src/box/field_def.h
> @@ -56,6 +56,7 @@ enum field_type {
>  	FIELD_TYPE_NUMBER,
>  	FIELD_TYPE_INTEGER,
>  	FIELD_TYPE_BOOLEAN,
> +	FIELD_TYPE_VARBINARY,
>  	FIELD_TYPE_SCALAR,
>  	FIELD_TYPE_ARRAY,
>  	FIELD_TYPE_MAP,
> diff --git a/src/box/lua/key_def.c b/src/box/lua/key_def.c
> index dfcc89442..052a1c85d 100644
> --- a/src/box/lua/key_def.c
> +++ b/src/box/lua/key_def.c
> @@ -111,6 +111,7 @@ luaT_key_def_set_part(struct lua_State *L, struct key_part_def *part,
>  	part->type = field_type_by_name(type_name, type_len);
>  	switch (part->type) {
>  	case FIELD_TYPE_ANY:
> +	case FIELD_TYPE_VARBINARY:
>  	case FIELD_TYPE_ARRAY:
>  	case FIELD_TYPE_MAP:
>  		/* Tuple comparators don't support these types. */
> diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc
> index c1a70a087..95a0f58c9 100644
> --- a/src/box/tuple_compare.cc
> +++ b/src/box/tuple_compare.cc
> @@ -404,6 +404,8 @@ tuple_compare_field(const char *field_a, const char *field_b,
>  		return mp_compare_number(field_a, field_b);
>  	case FIELD_TYPE_BOOLEAN:
>  		return mp_compare_bool(field_a, field_b);
> +	case FIELD_TYPE_VARBINARY:
> +		return mp_compare_bin(field_a, field_b);
>  	case FIELD_TYPE_SCALAR:
>  		return coll != NULL ?
>  		       mp_compare_scalar_coll(field_a, field_b, coll) :
> @@ -434,6 +436,8 @@ tuple_compare_field_with_type(const char *field_a, enum mp_type a_type,
>  						   field_b, b_type);
>  	case FIELD_TYPE_BOOLEAN:
>  		return mp_compare_bool(field_a, field_b);
> +	case FIELD_TYPE_VARBINARY:
> +		return mp_compare_bin(field_a, field_b);
>  	case FIELD_TYPE_SCALAR:
>  		return coll != NULL ?
>  		       mp_compare_scalar_coll(field_a, field_b, coll) :
> @@ -1502,6 +1506,14 @@ field_hint_string(const char *field, struct coll *coll)
>  			      hint_str_coll(field, len, coll);
>  }
>  
> +static inline hint_t
> +field_hint_varbinary(const char *field)
> +{
> +	assert(mp_typeof(*field) == MP_BIN);
> +	uint32_t len = mp_decode_binl(&field);
> +	return hint_bin(field, len);
> +}
> +
>  static inline hint_t
>  field_hint_scalar(const char *field, struct coll *coll)
>  {
> @@ -1547,6 +1559,8 @@ field_hint(const char *field, struct coll *coll)
>  		return field_hint_number(field);
>  	case FIELD_TYPE_STRING:
>  		return field_hint_string(field, coll);
> +	case FIELD_TYPE_VARBINARY:
> +		return field_hint_varbinary(field);
>  	case FIELD_TYPE_SCALAR:
>  		return field_hint_scalar(field, coll);
>  	default:
> @@ -1648,6 +1662,9 @@ key_def_set_hint_func(struct key_def *def)
>  	case FIELD_TYPE_STRING:
>  		key_def_set_hint_func<FIELD_TYPE_STRING>(def);
>  		break;
> +	case FIELD_TYPE_VARBINARY:
> +		key_def_set_hint_func<FIELD_TYPE_VARBINARY>(def);
> +		break;
>  	case FIELD_TYPE_SCALAR:
>  		key_def_set_hint_func<FIELD_TYPE_SCALAR>(def);
>  		break;
> diff --git a/test/box/varbinary_type.result b/test/box/varbinary_type.result
> new file mode 100644
> index 000000000..c7cd5700c
> --- /dev/null
> +++ b/test/box/varbinary_type.result
> @@ -0,0 +1,152 @@
> +env = require('test_run')
> +---
> +...
> +test_run = env.new()
> +---
> +...
> +--
> +-- gh-4201: Introduce varbinary field type.
> +--
> +s = box.schema.space.create('withdata')
> +---
> +...
> +s:format({{"b", "integer"}})
> +---
> +...
> +_ = s:create_index('pk', {parts = {1, "varbinary"}})
> +---
> +- error: Field 1 has type 'integer' in space format, but type 'varbinary' in index
> +    definition
> +...
> +s:format({{"b", "varbinary"}})
> +---
> +...
> +_ = s:create_index('pk', {parts = {1, "integer"}})
> +---
> +- error: Field 1 has type 'varbinary' in space format, but type 'integer' in index
> +    definition
> +...
> +pk = s:create_index('pk', {parts = {1, "varbinary"}})
> +---
> +...
> +buffer = require('buffer')
> +---
> +...
> +ffi = require('ffi')
> +---
> +...
> +test_run:cmd("setopt delimiter ';'")
> +---
> +- true
> +...
> +function bintuple_insert(space, bytes)
> +	local tmpbuf = buffer.IBUF_SHARED
> +	tmpbuf:reset()
> +	local p = tmpbuf:alloc(3 + #bytes)
> +	p[0] = 0x91
> +	p[1] = 0xC4
> +	p[2] = #bytes
> +	for i, c in pairs(bytes) do p[i + 3 - 1] = c end
> +	ffi.cdef[[int box_insert(uint32_t space_id, const char *tuple, const char *tuple_end, box_tuple_t **result);]]
> +	ffi.C.box_insert(space.id, tmpbuf.rpos, tmpbuf.wpos, nil)
> +end
> +test_run:cmd("setopt delimiter ''");
> +---
> +...
> +bintuple_insert(s, {0xDE, 0xAD, 0xBE, 0xAF})
> +---
> +...
> +bintuple_insert(s, {0xFE, 0xED, 0xFA, 0xCE})
> +---
> +...
> +s:select()
> +---
> +- - [!!binary 3q2+rw==]
> +  - [!!binary /u36zg==]
> +...
> +box.execute("SELECT * FROM \"withdata\" WHERE \"b\" < x'FEEDFACE';")
> +---
> +- metadata:
> +  - name: b
> +    type: varbinary
> +  rows:
> +  - [!!binary 3q2+rw==]
> +...
> +pk:alter({parts = {1, "scalar"}})
> +---
> +...
> +s:format({{"b", "scalar"}})
> +---
> +...
> +s:insert({11})
> +---
> +- [11]
> +...
> +s:insert({22})
> +---
> +- [22]
> +...
> +s:insert({"11"})
> +---
> +- ['11']
> +...
> +s:insert({"22"})
> +---
> +- ['22']
> +...
> +s:select()
> +---
> +- - [11]
> +  - [22]
> +  - ['11']
> +  - ['22']
> +  - [!!binary 3q2+rw==]
> +  - [!!binary /u36zg==]
> +...
> +box.execute("SELECT * FROM \"withdata\" WHERE \"b\" <= x'DEADBEAF';")
> +---
> +- metadata:
> +  - name: b
> +    type: scalar
> +  rows:
> +  - [11]
> +  - [22]
> +  - ['11']
> +  - ['22']
> +  - [!!binary 3q2+rw==]
> +...
> +pk:alter({parts = {1, "varbinary"}})
> +---
> +- error: 'Tuple field 1 type does not match one required by operation: expected varbinary'
> +...
> +s:delete({11})
> +---
> +- [11]
> +...
> +s:delete({22})
> +---
> +- [22]
> +...
> +s:delete({"11"})
> +---
> +- ['11']
> +...
> +s:delete({"22"})
> +---
> +- ['22']
> +...
> +bintuple_insert(s, {0xFA, 0xDE, 0xDE, 0xAD})
> +---
> +...
> +pk:alter({parts = {1, "varbinary"}})
> +---
> +...
> +s:select()
> +---
> +- - [!!binary 3q2+rw==]
> +  - [!!binary +t7erQ==]
> +  - [!!binary /u36zg==]
> +...
> +s:drop()
> +---
> +...
> diff --git a/test/box/varbinary_type.test.lua b/test/box/varbinary_type.test.lua
> new file mode 100644
> index 000000000..7895a1d22
> --- /dev/null
> +++ b/test/box/varbinary_type.test.lua
> @@ -0,0 +1,51 @@
> +env = require('test_run')
> +test_run = env.new()
> +
> +--
> +-- gh-4201: Introduce varbinary field type.
> +--
> +s = box.schema.space.create('withdata')
> +s:format({{"b", "integer"}})
> +_ = s:create_index('pk', {parts = {1, "varbinary"}})
> +s:format({{"b", "varbinary"}})
> +_ = s:create_index('pk', {parts = {1, "integer"}})
> +pk = s:create_index('pk', {parts = {1, "varbinary"}})
> +
> +buffer = require('buffer')
> +ffi = require('ffi')
> +
> +test_run:cmd("setopt delimiter ';'")
> +function bintuple_insert(space, bytes)
> +	local tmpbuf = buffer.IBUF_SHARED
> +	tmpbuf:reset()
> +	local p = tmpbuf:alloc(3 + #bytes)
> +	p[0] = 0x91
> +	p[1] = 0xC4
> +	p[2] = #bytes
> +	for i, c in pairs(bytes) do p[i + 3 - 1] = c end
> +	ffi.cdef[[int box_insert(uint32_t space_id, const char *tuple, const char *tuple_end, box_tuple_t **result);]]
> +	ffi.C.box_insert(space.id, tmpbuf.rpos, tmpbuf.wpos, nil)
> +end
> +test_run:cmd("setopt delimiter ''");
> +
> +bintuple_insert(s, {0xDE, 0xAD, 0xBE, 0xAF})
> +bintuple_insert(s, {0xFE, 0xED, 0xFA, 0xCE})
> +s:select()
> +box.execute("SELECT * FROM \"withdata\" WHERE \"b\" < x'FEEDFACE';")
> +pk:alter({parts = {1, "scalar"}})
> +s:format({{"b", "scalar"}})
> +s:insert({11})
> +s:insert({22})
> +s:insert({"11"})
> +s:insert({"22"})
> +s:select()
> +box.execute("SELECT * FROM \"withdata\" WHERE \"b\" <= x'DEADBEAF';")
> +pk:alter({parts = {1, "varbinary"}})
> +s:delete({11})
> +s:delete({22})
> +s:delete({"11"})
> +s:delete({"22"})
> +bintuple_insert(s, {0xFA, 0xDE, 0xDE, 0xAD})
> +pk:alter({parts = {1, "varbinary"}})
> +s:select()
> +s:drop()
> -- 
> 2.21.0
> 

-- 
Konstantin Osipov, Moscow, Russia



More information about the Tarantool-patches mailing list