diff --git a/src/box/alter.cc b/src/box/alter.cc index 3007a131d874f664d12e10ec7cc139d8198f9b97..6542e6733d010a03db5d3389acd70a3c7c746c51 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -2537,10 +2537,35 @@ priv_def_create_from_tuple(struct priv_def *priv, struct tuple *tuple) { priv->grantor_id = tuple_field_u32_xc(tuple, BOX_PRIV_FIELD_ID); priv->grantee_id = tuple_field_u32_xc(tuple, BOX_PRIV_FIELD_UID); + const char *object_type = tuple_field_cstr_xc(tuple, BOX_PRIV_FIELD_OBJECT_TYPE); - priv->object_id = tuple_field_u32_xc(tuple, BOX_PRIV_FIELD_OBJECT_ID); priv->object_type = schema_object_type(object_type); + + const char *data = tuple_field(tuple, BOX_PRIV_FIELD_OBJECT_ID); + if (data == NULL) { + tnt_raise(ClientError, ER_NO_SUCH_FIELD, + BOX_PRIV_FIELD_OBJECT_ID + TUPLE_INDEX_BASE); + } + /* + * When granting or revoking privileges on a whole entity + * we pass empty string ('') to object_id to indicate + * grant on every object of that entity. + * So check for that first. + */ + switch (mp_typeof(*data)) { + case MP_STR: + if (mp_decode_strl(&data) == 0) { + /* Entity-wide privilege. */ + priv->object_id = 0; + priv->object_type = schema_entity_type(priv->object_type); + break; + } + FALLTHROUGH; + default: + priv->object_id = tuple_field_u32_xc(tuple, + BOX_PRIV_FIELD_OBJECT_ID); + } if (priv->object_type == SC_UNKNOWN) { tnt_raise(ClientError, ER_UNKNOWN_SCHEMA_OBJECT, object_type); @@ -2583,10 +2608,8 @@ priv_def_check(struct priv_def *priv, enum priv_type priv_type) break; case SC_SPACE: { - struct space *space = NULL; - if (priv->object_id != 0) - space = space_cache_find_xc(priv->object_id); - if ((space == NULL || space->def->uid != grantor->def->uid) && + struct space *space = space_cache_find_xc(priv->object_id); + if (space->def->uid != grantor->def->uid && grantor->def->uid != ADMIN) { tnt_raise(AccessDeniedError, priv_name(priv_type), @@ -2597,10 +2620,8 @@ priv_def_check(struct priv_def *priv, enum priv_type priv_type) } case SC_FUNCTION: { - struct func *func = NULL; - if (priv->object_id != 0) - func = func_cache_find(priv->object_id); - if ((func == NULL || func->def->uid != grantor->def->uid) && + struct func *func = func_cache_find(priv->object_id); + if (func->def->uid != grantor->def->uid && grantor->def->uid != ADMIN) { tnt_raise(AccessDeniedError, priv_name(priv_type), @@ -2611,10 +2632,8 @@ priv_def_check(struct priv_def *priv, enum priv_type priv_type) } case SC_SEQUENCE: { - struct sequence *seq = NULL; - if (priv->object_id != 0) - seq = sequence_cache_find(priv->object_id); - if ((seq == NULL || seq->def->uid != grantor->def->uid) && + struct sequence *seq = sequence_cache_find(priv->object_id); + if (seq->def->uid != grantor->def->uid && grantor->def->uid != ADMIN) { tnt_raise(AccessDeniedError, priv_name(priv_type), @@ -2645,6 +2664,18 @@ priv_def_check(struct priv_def *priv, enum priv_type priv_type) } /* Not necessary to do during revoke, but who cares. */ role_check(grantee, role); + break; + } + case SC_ENTITY_SPACE: + case SC_ENTITY_FUNCTION: + case SC_ENTITY_SEQUENCE: + { + /* Only admin may grant privileges on an entire entity. */ + if (grantor->def->uid != ADMIN) { + tnt_raise(AccessDeniedError, priv_name(priv_type), + schema_object_name(priv->object_type), name, + grantor->def->name); + } } default: break; diff --git a/src/box/bootstrap.snap b/src/box/bootstrap.snap index b610828c9c9ae9a22acdd8c150c16c6838b7a273..44992b050e9d73d69608fb92782d1e965f6cdc51 100644 Binary files a/src/box/bootstrap.snap and b/src/box/bootstrap.snap differ diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index b9b8c9004b54b0f0585bef890dd9cf986bf18c42..d347fd1e62e0f7b13f9e7e82420cbc61f93c0255 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -1801,16 +1801,16 @@ local function privilege_name(privilege) end local function object_resolve(object_type, object_name) + if object_name ~= nil and type(object_name) ~= 'string' + and type(object_name) ~= 'number' then + box.error(box.error.ILLEGAL_PARAMS, "wrong object name type") + end if object_type == 'universe' then - if object_name ~= nil and type(object_name) ~= 'string' - and type(object_name) ~= 'number' then - box.error(box.error.ILLEGAL_PARAMS, "wrong object name type") - end return 0 end if object_type == 'space' then - if object_name == nil or object_name == 0 then - return 0 + if object_name == '' then + return '' end local space = box.space[object_name] if space == nil then @@ -1819,8 +1819,8 @@ local function object_resolve(object_type, object_name) return space.id end if object_type == 'function' then - if object_name == nil or object_name == 0 then - return 0 + if object_name == '' then + return '' end local _vfunc = box.space[box.schema.VFUNC_ID] local func @@ -1836,8 +1836,8 @@ local function object_resolve(object_type, object_name) end end if object_type == 'sequence' then - if object_name == nil or object_name == 0 then - return 0 + if object_name == '' then + return '' end local seq = sequence_resolve(object_name) if seq == nil then @@ -1864,7 +1864,7 @@ local function object_resolve(object_type, object_name) end local function object_name(object_type, object_id) - if object_type == 'universe' then + if object_type == 'universe' or object_id == '' then return "" end local space @@ -2072,12 +2072,18 @@ local function grant(uid, name, privilege, object_type, object_name, options) -- From user point of view, role is the same thing -- as a privilege. Allow syntax grant(user, role). - if object_name == nil and object_type == nil then - -- sic: avoid recursion, to not bother with roles - -- named 'execute' - object_type = 'role' - object_name = privilege - privilege = 'execute' + if object_name == nil then + if object_type == nil then + -- sic: avoid recursion, to not bother with roles + -- named 'execute' + object_type = 'role' + object_name = privilege + privilege = 'execute' + else + -- Allow syntax grant(user, priv, entity) + -- for entity grants. + object_name = '' + end end local privilege_hex = privilege_check(privilege, object_type) @@ -2117,10 +2123,16 @@ end local function revoke(uid, name, privilege, object_type, object_name, options) -- From user point of view, role is the same thing -- as a privilege. Allow syntax revoke(user, role). - if object_name == nil and object_type == nil then - object_type = 'role' - object_name = privilege - privilege = 'execute' + if object_name == nil then + if object_type == nil then + object_type = 'role' + object_name = privilege + privilege = 'execute' + else + -- Allow syntax revoke(user, privilege, entity) + -- to revoke entity privileges. + object_name = '' + end end local privilege_hex = privilege_check(privilege, object_type) options = options or {} @@ -2192,8 +2204,8 @@ local function drop(uid, opts) local privs = _vpriv.index.primary:select{uid} for k, tuple in pairs(privs) do - -- we need an additional box.session.su() here, because of - -- unnecessary check for privilege PRIV_REVOKE in priv_def_check() + -- we need an additional box.session.su() here, because of + -- unnecessary check for privilege PRIV_REVOKE in priv_def_check() box.session.su("admin", revoke, uid, uid, tuple[5], tuple[3], tuple[4]) end box.space[box.schema.USER_ID]:delete{uid} diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua index 0293f6ef8ddd84fb8518c13a290163072d99794e..ec3826399ab264bd94eb0d9046a773bf57dcc0d2 100644 --- a/src/box/lua/upgrade.lua +++ b/src/box/lua/upgrade.lua @@ -964,6 +964,28 @@ local function upgrade_to_1_10_0() create_vsequence_space() end +-------------------------------------------------------------------------------- +--- Tarantool 1.10.2 +-------------------------------------------------------------------------------- +local function upgrade_priv_to_1_10_2() + local _priv = box.space._priv + local _vpriv = box.space._vpriv + local format = _priv:format() + + format[4].type = 'scalar' + _priv:format(format) + format = _vpriv:format() + format[4].type = 'scalar' + _vpriv:format(format) + _priv.index.primary:alter{parts={2, 'unsigned', 3, 'string', 4, 'scalar'}} + _vpriv.index.primary:alter{parts={2, 'unsigned', 3, 'string', 4, 'scalar'}} + _priv.index.object:alter{parts={3, 'string', 4, 'scalar'}} + _vpriv.index.object:alter{parts={3, 'string', 4, 'scalar'}} +end + +local function upgrade_to_1_10_2() + upgrade_priv_to_1_10_2() +end local function get_version() local version = box.space._schema:get{'version'} @@ -991,6 +1013,7 @@ local function upgrade(options) {version = mkversion(1, 7, 6), func = upgrade_to_1_7_6, auto = false}, {version = mkversion(1, 7, 7), func = upgrade_to_1_7_7, auto = true}, {version = mkversion(1, 10, 0), func = upgrade_to_1_10_0, auto = true}, + {version = mkversion(1, 10, 2), func = upgrade_to_1_10_2, auto = true}, } for _, handler in ipairs(handlers) do diff --git a/src/box/schema.cc b/src/box/schema.cc index 433f52c085d6a7ca02dbb3e94ab13bdf319d525a..aaa63a08340a41d8ff4283112a99314d67a60352 100644 --- a/src/box/schema.cc +++ b/src/box/schema.cc @@ -535,11 +535,12 @@ schema_find_name(enum schema_object_type type, uint32_t object_id) { switch (type) { case SC_UNIVERSE: + case SC_ENTITY_SPACE: + case SC_ENTITY_FUNCTION: + case SC_ENTITY_SEQUENCE: return ""; case SC_SPACE: { - if (object_id == 0) - return "SPACE"; struct space *space = space_by_id(object_id); if (space == NULL) break; @@ -547,8 +548,6 @@ schema_find_name(enum schema_object_type type, uint32_t object_id) } case SC_FUNCTION: { - if (object_id == 0) - return "FUNCTION"; struct func *func = func_by_id(object_id); if (func == NULL) break; @@ -556,8 +555,6 @@ schema_find_name(enum schema_object_type type, uint32_t object_id) } case SC_SEQUENCE: { - if (object_id == 0) - return "SEQUENCE"; struct sequence *seq = sequence_by_id(object_id); if (seq == NULL) break; diff --git a/src/box/schema.h b/src/box/schema.h index 0822262d097b070d95aa1b0f8d1964099ffd20c2..f1735ff3457d0488781ebbf312ddafdc15a36a37 100644 --- a/src/box/schema.h +++ b/src/box/schema.h @@ -250,16 +250,19 @@ static inline struct access * entity_access_get(enum schema_object_type type) { - switch (type) { - case SC_SPACE: - return entity_access.space; - case SC_FUNCTION: - return entity_access.function; - case SC_SEQUENCE: - return entity_access.sequence; - default: - return NULL; - } + switch (type) { + case SC_SPACE: + case SC_ENTITY_SPACE: + return entity_access.space; + case SC_FUNCTION: + case SC_ENTITY_FUNCTION: + return entity_access.function; + case SC_SEQUENCE: + case SC_ENTITY_SEQUENCE: + return entity_access.sequence; + default: + return NULL; + } } #endif /* INCLUDES_TARANTOOL_BOX_SCHEMA_H */ diff --git a/src/box/schema_def.c b/src/box/schema_def.c index 97c074ab2799f86603946746dd4065825a5c0e1b..9091af0549df5551cbb930d8f58c5ef939c2d468 100644 --- a/src/box/schema_def.c +++ b/src/box/schema_def.c @@ -41,6 +41,23 @@ static const char *object_type_strs[] = { /* [SC_COLLATION] = */ "collation", }; +enum schema_object_type +schema_entity_type(enum schema_object_type type) +{ + switch (type) { + case SC_SPACE: + return SC_ENTITY_SPACE; + case SC_FUNCTION: + return SC_ENTITY_FUNCTION; + case SC_SEQUENCE: + return SC_ENTITY_SEQUENCE; + case SC_COLLATION: + return SC_ENTITY_COLLATION; + default: + return SC_UNKNOWN; + } +} + enum schema_object_type schema_object_type(const char *name) { diff --git a/src/box/schema_def.h b/src/box/schema_def.h index 2edb8d37fea9634da114044b2da41cec35adc80d..d2fc39b76c6ca28acad47f2607b3af54212ef59b 100644 --- a/src/box/schema_def.h +++ b/src/box/schema_def.h @@ -228,9 +228,23 @@ enum schema_object_type { SC_ROLE = 5, SC_SEQUENCE = 6, SC_COLLATION = 7, - schema_object_type_MAX = 8 + /* + * All object types are supposed to be above this point, + * all entity types - below. + */ + schema_object_type_MAX = 8, + SC_ENTITY_SPACE, + SC_ENTITY_FUNCTION, + SC_ENTITY_SEQUENCE, + SC_ENTITY_COLLATION }; +/** + * Given a object type, return an entity type it belongs to. + */ +enum schema_object_type +schema_entity_type(enum schema_object_type type); + enum schema_object_type schema_object_type(const char *name); diff --git a/src/box/user.cc b/src/box/user.cc index fbf06566a7df4e43346686b76d3c7a91543a7ca1..eec785652cca6dc9cdffbb94bb49fc2b5a9aad69 100644 --- a/src/box/user.cc +++ b/src/box/user.cc @@ -207,12 +207,23 @@ access_find(struct priv_def *priv) access = universe.access; break; } + case SC_ENTITY_SPACE: + { + access = entity_access.space; + break; + } + case SC_ENTITY_FUNCTION: + { + access = entity_access.function; + break; + } + case SC_ENTITY_SEQUENCE: + { + access = entity_access.sequence; + break; + } case SC_SPACE: { - if (priv->object_id == 0) { - access = entity_access.space; - break; - } struct space *space = space_by_id(priv->object_id); if (space) access = space->access; @@ -220,10 +231,6 @@ access_find(struct priv_def *priv) } case SC_FUNCTION: { - if (priv->object_id == 0) { - access = entity_access.function; - break; - } struct func *func = func_by_id(priv->object_id); if (func) access = func->access; @@ -231,10 +238,6 @@ access_find(struct priv_def *priv) } case SC_SEQUENCE: { - if (priv->object_id == 0) { - access = entity_access.sequence; - break; - } struct sequence *seq = sequence_by_id(priv->object_id); if (seq) access = seq->access; diff --git a/test/box-py/bootstrap.result b/test/box-py/bootstrap.result index 16c2027cfd2f1ba8c9ce57a1828b81cc0d243a74..cf8242de51751266189a74fc1cfeb393dff694f3 100644 --- a/test/box-py/bootstrap.result +++ b/test/box-py/bootstrap.result @@ -5,7 +5,7 @@ box.space._schema:select{} --- - - ['cluster', '<cluster uuid>'] - ['max_id', 511] - - ['version', 1, 10, 0] + - ['version', 1, 10, 2] ... box.space._cluster:select{} --- @@ -58,10 +58,10 @@ box.space._space:select{} 'type': 'string'}, {'name': 'auth', 'type': 'map'}]] - [312, 1, '_priv', 'memtx', 0, {}, [{'name': 'grantor', 'type': 'unsigned'}, { 'name': 'grantee', 'type': 'unsigned'}, {'name': 'object_type', 'type': 'string'}, - {'name': 'object_id', 'type': 'unsigned'}, {'name': 'privilege', 'type': 'unsigned'}]] + {'name': 'object_id', 'type': 'scalar'}, {'name': 'privilege', 'type': 'unsigned'}]] - [313, 1, '_vpriv', 'sysview', 0, {}, [{'name': 'grantor', 'type': 'unsigned'}, {'name': 'grantee', 'type': 'unsigned'}, {'name': 'object_type', 'type': 'string'}, - {'name': 'object_id', 'type': 'unsigned'}, {'name': 'privilege', 'type': 'unsigned'}]] + {'name': 'object_id', 'type': 'scalar'}, {'name': 'privilege', 'type': 'unsigned'}]] - [320, 1, '_cluster', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'uuid', 'type': 'string'}]] - [330, 1, '_truncate', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'count', @@ -104,13 +104,13 @@ box.space._index:select{} - [305, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]] - [305, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]] - [312, 0, 'primary', 'tree', {'unique': true}, [[1, 'unsigned'], [2, 'string'], - [3, 'unsigned']]] + [3, 'scalar']]] - [312, 1, 'owner', 'tree', {'unique': false}, [[0, 'unsigned']]] - - [312, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'unsigned']]] + - [312, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'scalar']]] - [313, 0, 'primary', 'tree', {'unique': true}, [[1, 'unsigned'], [2, 'string'], - [3, 'unsigned']]] + [3, 'scalar']]] - [313, 1, 'owner', 'tree', {'unique': false}, [[0, 'unsigned']]] - - [313, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'unsigned']]] + - [313, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'scalar']]] - [320, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]] - [320, 1, 'uuid', 'tree', {'unique': true}, [[1, 'string']]] - [330, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]] diff --git a/test/box/access.result b/test/box/access.result index f4669a4a3cc37027e38c56d521dffd7cff8d81df..599500633f278337c723d836930516a582de6989 100644 --- a/test/box/access.result +++ b/test/box/access.result @@ -504,7 +504,7 @@ box.space._priv:select{id} ... box.schema.user.grant('user', 'read', 'universe') --- -- error: User 'user' already has read access on universe 'nil' +- error: User 'user' already has read access on universe '' ... box.space._priv:select{id} --- @@ -690,7 +690,7 @@ box.schema.user.grant('guest', 'read,write,execute', 'universe') ... box.schema.user.grant('guest', 'read,write,execute', 'universe') --- -- error: User 'guest' already has read,write,execute access on universe 'nil' +- error: User 'guest' already has read,write,execute access on universe '' ... box.schema.user.grant('guest', 'read,write,execute', 'universe', '', { if_not_exists = true }) --- @@ -703,7 +703,7 @@ box.schema.user.revoke('guest', 'usage,session', 'universe') ... box.schema.user.revoke('guest', 'read,write,execute', 'universe') --- -- error: User 'guest' does not have read,write,execute access on universe 'nil' +- error: User 'guest' does not have read,write,execute access on universe '' ... box.schema.user.revoke('guest', 'read,write,execute', 'universe', '', { if_exists = true }) --- diff --git a/test/box/access_misc.result b/test/box/access_misc.result index 2d87fa2d5e51255ae8ca874a73c4d39deaa4dbbc..3061f11810937ffce3e90cef78badd96fb059765 100644 --- a/test/box/access_misc.result +++ b/test/box/access_misc.result @@ -436,7 +436,7 @@ box.schema.user.revoke('testuser', 'usage,session', 'universe') ... box.schema.user.revoke('testuser', 'read, write, execute', 'universe') --- -- error: User 'testuser' does not have read, write, execute access on universe 'nil' +- error: User 'testuser' does not have read, write, execute access on universe '' ... box.schema.user.revoke('testuser', 'create', 'universe') --- @@ -797,10 +797,10 @@ box.space._space:select() 'type': 'string'}, {'name': 'auth', 'type': 'map'}]] - [312, 1, '_priv', 'memtx', 0, {}, [{'name': 'grantor', 'type': 'unsigned'}, { 'name': 'grantee', 'type': 'unsigned'}, {'name': 'object_type', 'type': 'string'}, - {'name': 'object_id', 'type': 'unsigned'}, {'name': 'privilege', 'type': 'unsigned'}]] + {'name': 'object_id', 'type': 'scalar'}, {'name': 'privilege', 'type': 'unsigned'}]] - [313, 1, '_vpriv', 'sysview', 0, {}, [{'name': 'grantor', 'type': 'unsigned'}, {'name': 'grantee', 'type': 'unsigned'}, {'name': 'object_type', 'type': 'string'}, - {'name': 'object_id', 'type': 'unsigned'}, {'name': 'privilege', 'type': 'unsigned'}]] + {'name': 'object_id', 'type': 'scalar'}, {'name': 'privilege', 'type': 'unsigned'}]] - [320, 1, '_cluster', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'uuid', 'type': 'string'}]] - [330, 1, '_truncate', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'count', @@ -853,7 +853,7 @@ box.schema.user.grant('tester', 'read', 'universe') -- error: the privilege is not granted box.schema.user.revoke('tester', 'create', 'universe') --- -- error: User 'tester' does not have create access on universe 'nil' +- error: User 'tester' does not have create access on universe '' ... -- no error: if_exists clause box.schema.user.revoke('tester', 'create', 'universe', nil, { if_exists = true }) diff --git a/test/box/alter.result b/test/box/alter.result index eb7014d8b35d2170718f60542c46c790bd5ef63b..36bdb5fd3411b2bc2bfebb7fadfa17d9be2907c7 100644 --- a/test/box/alter.result +++ b/test/box/alter.result @@ -214,13 +214,13 @@ _index:select{} - [305, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]] - [305, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]] - [312, 0, 'primary', 'tree', {'unique': true}, [[1, 'unsigned'], [2, 'string'], - [3, 'unsigned']]] + [3, 'scalar']]] - [312, 1, 'owner', 'tree', {'unique': false}, [[0, 'unsigned']]] - - [312, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'unsigned']]] + - [312, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'scalar']]] - [313, 0, 'primary', 'tree', {'unique': true}, [[1, 'unsigned'], [2, 'string'], - [3, 'unsigned']]] + [3, 'scalar']]] - [313, 1, 'owner', 'tree', {'unique': false}, [[0, 'unsigned']]] - - [313, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'unsigned']]] + - [313, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'scalar']]] - [320, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]] - [320, 1, 'uuid', 'tree', {'unique': true}, [[1, 'string']]] - [330, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]] diff --git a/test/xlog/upgrade.result b/test/xlog/upgrade.result index f02996bbabb681e5acd77b23bafdb47f1bbf6fa6..76467baf15c45a03b533580321f008edc3d22cdc 100644 --- a/test/xlog/upgrade.result +++ b/test/xlog/upgrade.result @@ -36,7 +36,7 @@ box.space._schema:select() --- - - ['cluster', '<server_uuid>'] - ['max_id', 513] - - ['version', 1, 10, 0] + - ['version', 1, 10, 2] ... box.space._space:select() --- @@ -85,10 +85,10 @@ box.space._space:select() 'type': 'string'}, {'name': 'auth', 'type': 'map'}]] - [312, 1, '_priv', 'memtx', 0, {}, [{'name': 'grantor', 'type': 'unsigned'}, { 'name': 'grantee', 'type': 'unsigned'}, {'name': 'object_type', 'type': 'string'}, - {'name': 'object_id', 'type': 'unsigned'}, {'name': 'privilege', 'type': 'unsigned'}]] + {'name': 'object_id', 'type': 'scalar'}, {'name': 'privilege', 'type': 'unsigned'}]] - [313, 1, '_vpriv', 'sysview', 0, {}, [{'name': 'grantor', 'type': 'unsigned'}, {'name': 'grantee', 'type': 'unsigned'}, {'name': 'object_type', 'type': 'string'}, - {'name': 'object_id', 'type': 'unsigned'}, {'name': 'privilege', 'type': 'unsigned'}]] + {'name': 'object_id', 'type': 'scalar'}, {'name': 'privilege', 'type': 'unsigned'}]] - [320, 1, '_cluster', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'uuid', 'type': 'string'}]] - [330, 1, '_truncate', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'count', @@ -134,13 +134,13 @@ box.space._index:select() - [305, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]] - [305, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]] - [312, 0, 'primary', 'tree', {'unique': true}, [[1, 'unsigned'], [2, 'string'], - [3, 'unsigned']]] + [3, 'scalar']]] - [312, 1, 'owner', 'tree', {'unique': false}, [[0, 'unsigned']]] - - [312, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'unsigned']]] + - [312, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'scalar']]] - [313, 0, 'primary', 'tree', {'unique': true}, [[1, 'unsigned'], [2, 'string'], - [3, 'unsigned']]] + [3, 'scalar']]] - [313, 1, 'owner', 'tree', {'unique': false}, [[0, 'unsigned']]] - - [313, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'unsigned']]] + - [313, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'scalar']]] - [320, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]] - [320, 1, 'uuid', 'tree', {'unique': true}, [[1, 'string']]] - [330, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]