Hi! Thankyou for review!

Please see my answers regarding extra code in grant/revoke and object_resolve
functions below.
The new diff is also below.

7 авг. 2018 г., в 19:38, Vladimir Davydov <vdavydov.dev@gmail.com> написал(а):

On Thu, Aug 02, 2018 at 01:55:58PM +0300, Serge Petrenko wrote:
When granting or revoking a privilege on an entire entity, id 0 was used
to indicate the fact that we don't grant a privilege on a single object,
but on a whole entity. This caused confusion, because for entity USER,
for example, id 0 is a valid object id (user 'guest' uses it).
Any non-zero id dedicated to this cause obviously may be confused as well.
Fix this by creating separate schema_object_types for entities:
SC_ENTITY_SPACE, SC_ENTITY_USER, etc.

Closes: #3574
Prerequisite: #3524
---
https://github.com/tarantool/tarantool/tree/sergepetrenko/gh-3574-whole-entity-types
https://github.com/tarantool/tarantool/issues/3574

Changes in v2: 
 - keep only old syntax for granting access
   to all entities
 - add an upgrade script to alter indices of spaces
   _priv and _vpriv to store 'scalar' in object_id field,
   and use an asterisk ('*') in object_id to indicate
   granting on an entire entity.

Hmm, I wonder what happens if someone creates an object (say space) and
names it "*» …
It is ok, when operating with a space named ‘*’, ‘*’ is in object_name, when operating
on a whole entity, ‘*’ is set internally in object_id field. So there are no conflicts here.

 - keep the new entity types in priv_def and use them
   internally.

src/box/alter.cc             |  27 ++++++++++++++++++++++++++-
src/box/bootstrap.snap       | Bin 1540 -> 1557 bytes
src/box/lua/schema.lua       |  41 ++++++++++++++++++++++++-----------------
src/box/lua/upgrade.lua      |  37 +++++++++++++++++++++++++++++++++++++
src/box/schema.cc            |  18 ++++++++++++++++++
src/box/schema.h             |  23 +++++++++++++----------
src/box/schema_def.c         |  39 +++++++++++++++++++++++++++++++--------
src/box/schema_def.h         |  28 ++++++++++++++++++++++------
src/box/user.cc              |  27 +++++++++++++++------------
test/box-py/bootstrap.result |  14 +++++++-------
test/box/access.result       |   6 +++---
test/box/access_misc.result  |   8 ++++----
test/box/alter.result        |   8 ++++----
test/xlog/upgrade.result     |  14 +++++++-------
14 files changed, 211 insertions(+), 79 deletions(-)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 3007a131d..6057b66c9 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -2529,6 +2529,31 @@ on_replace_dd_collation(struct trigger * /* trigger */, void *event)
}
}

+void
+priv_def_try_fill(struct priv_def *priv, struct tuple *tuple)

This function should be static. Anyway, I don't think it's worth
factoring this code out, because it's pretty straightforward and
executed only in priv_def_create_form_tuple().

I removed the function.
+{
+ const char *object_id = tuple_field(tuple, BOX_PRIV_FIELD_OBJECT_ID);
+ if (object_id == NULL) {
+ tnt_raise(ClientError, ER_NO_SUCH_FIELD,
+   BOX_PRIV_FIELD_OBJECT_ID + TUPLE_INDEX_BASE);
+ }

Please use tuple_field_u32() and tuple_field_str() instead.

+ /*
+  * When granting or revoking privileges on a whole entity we
+  * pass an asterisk ('*') to object_id to indicate grant on every
+  * object of that entity. So check for that first.
+  */
+ if (mp_typeof(*object_id) == MP_STR) {

Shouldn't you check that the string is actually "*»?

Added a check


+ priv->object_id = 0;
+ priv->object_type = schema_entity_type(priv->object_type);

This assumes that priv->object_type is initialized before
priv_def_try_fill(). IMO this makes the function protocol
rather abstruse. Another reason not to factor it out.


Done.
+ } else if (mp_typeof(*object_id) == MP_UINT) {
+ priv->object_id = mp_decode_uint(&object_id);
+ } else {
+ tnt_raise(ClientError, ER_FIELD_TYPE,
+   BOX_PRIV_FIELD_OBJECT_ID + TUPLE_INDEX_BASE,
+   field_type_strs[FIELD_TYPE_UNSIGNED]);
+ }
+}
+
/**
 * Create a privilege definition from tuple.
 */
@@ -2539,8 +2564,8 @@ priv_def_create_from_tuple(struct priv_def *priv, struct tuple *tuple)
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);
+ priv_def_try_fill(priv, tuple);
if (priv->object_type == SC_UNKNOWN) {
tnt_raise(ClientError, ER_UNKNOWN_SCHEMA_OBJECT,
  object_type);
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index b9b8c9004..294dcf4d3 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -1809,9 +1809,9 @@ local function object_resolve(object_type, object_name)
        return 0
    end
    if object_type == 'space' then
-        if object_name == nil or object_name == 0 then
-            return 0
-        end
+ if object_name == nil then
+     return '*'
+ end

Bad indentation - we use spaces in Lua code, not tabs.


Fixed.

        local space = box.space[object_name]
        if  space == nil then
            box.error(box.error.NO_SUCH_SPACE, object_name)
@@ -1819,9 +1819,9 @@ 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
-        end
+ if object_name == nil then
+     return '*'
+ end

Ditto

Fixed


        local _vfunc = box.space[box.schema.VFUNC_ID]
        local func
        if type(object_name) == 'string' then
@@ -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 == nil then
+            return '*'
        end
        local seq = sequence_resolve(object_name)
        if seq == nil then
@@ -1846,6 +1846,9 @@ local function object_resolve(object_type, object_name)
        return seq
    end
    if object_type == 'role' then
+ if object_name == nil then
+     return '*'
+ end

Ditto.


Fixed

        local _vuser = box.space[box.schema.VUSER_ID]
        local role
        if type(object_name) == 'string' then
@@ -1867,6 +1870,9 @@ local function object_name(object_type, object_id)
    if object_type == 'universe' then
        return ""
    end
+    if object_id == '*' then
+        return '*'
+    end
    local space
    if object_type == 'space' then
        space = box.space._vspace
@@ -2079,9 +2085,8 @@ local function grant(uid, name, privilege, object_type,
        object_name = privilege
        privilege = 'execute'
    end
-    local privilege_hex = privilege_check(privilege, object_type)
-
    local oid = object_resolve(object_type, object_name)
+    local privilege_hex = privilege_check(privilege, object_type)

I don't understand why you need this.

Removed, no need to do this.

    options = options or {}
    if options.grantor == nil then
        options.grantor = session.euid()
@@ -2106,10 +2111,10 @@ local function grant(uid, name, privilege, object_type,
        _priv:replace{options.grantor, uid, object_type, oid, privilege_hex}
    elseif not options.if_not_exists then
            if object_type == 'role' then
-                box.error(box.error.ROLE_GRANTED, name, object_name)
+                box.error(box.error.ROLE_GRANTED, name, object_name or '*')
            else
                box.error(box.error.PRIV_GRANTED, name, privilege,
-                          object_type, object_name)
+                          object_type, object_name or '*')

Instead you could set object_name to '*' in the beginning of
grant/revoke functions. This would make your patch shorter,
because you wouldn't have to do it here, nor in object_resolve.


If I set object_name to ‘*’ the case of granting to an entity as a whole will
Be indistinguishable from granting to an object named ‘*’. So I have to handle
This case like I did. I changed the code in object_resolve a little bit to save some
Extra lines.
            end
    end
end
@@ -2122,9 +2127,9 @@ local function revoke(uid, name, privilege, object_type, object_name, options)
        object_name = privilege
        privilege = 'execute'
    end
-    local privilege_hex = privilege_check(privilege, object_type)
    options = options or {}
    local oid = object_resolve(object_type, object_name)
+    local privilege_hex = privilege_check(privilege, object_type)

I don't understand why you need this.

Removed.

    local _priv = box.space[box.schema.PRIV_ID]
    local _vpriv = box.space[box.schema.VPRIV_ID]
    local tuple = _vpriv:get{uid, object_type, oid}
@@ -2134,10 +2139,10 @@ local function revoke(uid, name, privilege, object_type, object_name, options)
            return
        end
        if object_type == 'role' then
-            box.error(box.error.ROLE_NOT_GRANTED, name, object_name)
+            box.error(box.error.ROLE_NOT_GRANTED, name, object_name or '*')
        else
            box.error(box.error.PRIV_NOT_GRANTED, name, privilege,
-                      object_type, object_name)
+                      object_type, object_name or '*')
        end
    end
    local old_privilege = tuple[5]
@@ -2153,13 +2158,14 @@ local function revoke(uid, name, privilege, object_type, object_name, options)
            return
        end
        box.error(box.error.PRIV_NOT_GRANTED, name, privilege,
-                  object_type, object_name)
+                  object_type, object_name or '*')

This hunk as well as the one above wouldn't be needed if you set
object_name to '*' in the beginning of the function (also, see my
comment to grant function).

Answered above.

    end
    if privilege_hex ~= 0 then
        _priv:replace{grantor, uid, object_type, oid, privilege_hex}
    else
        _priv:delete{uid, object_type, oid}
    end
+

Extraneous change. Please remove.

Done


end

local function drop(uid, opts)
@@ -2194,7 +2200,8 @@ local function drop(uid, opts)
    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()
-        box.session.su("admin", revoke, uid, uid, tuple[5], tuple[3], tuple[4])
+        local oid = tuple[4] ~= '*' and tuple[4] or nil
+        box.session.su("admin", revoke, uid, uid, tuple[5], tuple[3], oid)

Why? The 'revoke' function should be able to interpret '*' correctly.


No, answered above.
    end
    box.space[box.schema.USER_ID]:delete{uid}
end
diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua
index 0293f6ef8..4acf20152 100644
--- a/src/box/lua/upgrade.lua
+++ b/src/box/lua/upgrade.lua
@@ -964,6 +964,42 @@ local function upgrade_to_1_10_0()
    create_vsequence_space()
end

+--------------------------------------------------------------------------------
+--- Tarantool 1.10.1
+--------------------------------------------------------------------------------
+local function upgrade_space_priv_to_1_10_1()
+    local _priv = box.space._priv
+    local _vpriv = box.space._vpriv
+    local f = _priv:format()
+
+    f[4].type = 'scalar'
+    _priv:format(f)
+    f = _vpriv:format()
+    f[4].type = 'scalar'
+    _vpriv:format(f)
+    _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_privs_to_1_10_1()

No need to split this code in two functions.

+    local _priv = box.space._priv
+
+    for _, priv in _priv:pairs() do

AFAICS interpretation of '0' as 'all objects of a kind' was added after
1.10.1 i.e. there was no Tarantool release that would use this feature.
So I guess you don't need to upgrade existing privileges, neither do you
need to preserve any code that handles '0' object id. Please consult
with Georgy and Kostja regarding this.

+        if priv[4] == 0 then
+            if priv[3] ~= 'universe' and priv[3] ~= 'user' and priv[3] ~= 'role' then

Please rewrite it as

 if priv[4] == 0 and priv[3] ~= 'universe' and ... then

+                _priv:delete{priv[2], priv[3], priv[4]}
+ _priv:insert{priv[1], priv[2], priv[3], '*', priv[5]}

Bad indentation - we use spaces in Lua code, not tabs.


Removed the privilege upgrade function together with some leftover code handling 
Id 0.
+            end
+        end
+    end
+end
+
+local function upgrade_to_1_10_1()
+    upgrade_space_priv_to_1_10_1()
+    upgrade_privs_to_1_10_1()
+end

local function get_version()
    local version = box.space._schema:get{'version'}
@@ -991,6 +1027,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, 1), func = upgrade_to_1_10_1, auto = true},
    }

    for _, handler in ipairs(handlers) do
diff --git a/src/box/schema.cc b/src/box/schema.cc
index 433f52c08..02f55aaad 100644
--- a/src/box/schema.cc
+++ b/src/box/schema.cc
@@ -536,8 +536,26 @@ schema_find_name(enum schema_object_type type, uint32_t object_id)
switch (type) {
case SC_UNIVERSE:
return "";
+ case SC_ENTITY_SPACE:
+ return "SPACE";
+ case SC_ENTITY_FUNCTION:
+ return "FUNCTION";
+ case SC_ENTITY_SEQUENCE:
+ return "SEQUENCE";
+ case SC_ENTITY_ROLE:
+ return "ROLE";
+ case SC_ENTITY_USER:
+ return "USER";

Shouldn't it be "*»?
It should, indeed. Fixed.

case SC_SPACE:
{
+ /*
+  * Even though we have a separate type
+  * for grants on entire entity, we have to
+  * leave the check for an empty object_id in place,
+  * because without it recover from an old version WAL 
+  * fails even before the upgrade script is being run.
+  * Same applies to SC_FUNCTION and SC_SEQUENCE below.
+  */
if (object_id == 0)
return "SPACE";
struct space *space = space_by_id(object_id);
diff --git a/src/box/schema.h b/src/box/schema.h
index 0822262d0..f1735ff34 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 97c074ab2..51d418e42 100644
--- a/src/box/schema_def.c
+++ b/src/box/schema_def.c
@@ -31,16 +31,39 @@
#include "schema_def.h"

static const char *object_type_strs[] = {
- /* [SC_UKNNOWN]         = */ "unknown",
- /* [SC_UNIVERSE]        = */ "universe",
- /* [SC_SPACE]           = */ "space",
- /* [SC_FUNCTION]        = */ "function",
- /* [SC_USER]            = */ "user",
- /* [SC_ROLE]            = */ "role",
- /* [SC_SEQUENCE]        = */ "sequence",
- /* [SC_COLLATION]       = */ "collation",
+ /* [SC_UKNNOWN]     = */ "unknown",
+ /* [SC_UNIVERSE]     = */ "universe",
+ /* [SC_SPACE]     = */ "space",
+ /* [SC_ENTITY_SPACE]     = */ "all spaces",
+ /* [SC_FUNCTION]     = */ "function",
+ /* [SC_ENTITY_FUNCTION]     = */ "all functions",
+ /* [SC_USER]     = */ "user",
+ /* [SC_ENTITY_USER]     = */ "all users",
+ /* [SC_ROLE]     = */ "role",
+ /* [SC_ENTITY_ROLE]     = */ "all roles",
+ /* [SC_SEQUENCE]     = */ "sequence",
+ /* [SC_ENTITY_SEQUENCE]     = */ "all sequences",
+ /* [SC_COLLATION]     = */ "collation",
+ /* [SC_ENTITY_COLLATION]    = */ "all collations",

Why? I don't think that you need to report "all spaces" anywhere.

fixed.

Here’s the new diff:

 src/box/alter.cc             |  33 ++++++++++++++++++++++++++++++++-
 src/box/bootstrap.snap       | Bin 1540 -> 1557 bytes
 src/box/lua/schema.lua       |  43 ++++++++++++++++++++++---------------------
 src/box/lua/upgrade.lua      |  23 +++++++++++++++++++++++
 src/box/schema.cc            |  16 ++++++++++------
 src/box/schema.h             |  23 +++++++++++++----------
 src/box/schema_def.c         |  39 +++++++++++++++++++++++++++++++--------
 src/box/schema_def.h         |  28 ++++++++++++++++++++++------
 src/box/user.cc              |  27 +++++++++++++++------------
 test/box-py/bootstrap.result |  14 +++++++-------
 test/box/access.result       |   6 +++---
 test/box/access_misc.result  |   8 ++++----
 test/box/alter.result        |   8 ++++----
 test/xlog/upgrade.result     |  14 +++++++-------
 14 files changed, 193 insertions(+), 89 deletions(-)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 3007a131d..7d65cab3a 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -2537,10 +2537,41 @@ 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 *object_id = tuple_field(tuple, BOX_PRIV_FIELD_OBJECT_ID);
+ if (object_id == 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 an asterisk ('*') to object_id to indicate
+  * grant on every object of that entity.
+  * So check for that first.
+  */
+ if (mp_typeof(*object_id) == MP_STR) {
+ object_id = tuple_field_cstr_xc(tuple, BOX_PRIV_FIELD_OBJECT_ID);
+ if(*object_id == '*' && strlen(object_id) == 1) {
+ priv->object_id = 0;
+ priv->object_type = schema_entity_type(priv->object_type);
+ } else {
+ tnt_raise(ClientError, ER_FIELD_TYPE,
+   BOX_PRIV_FIELD_OBJECT_ID + TUPLE_INDEX_BASE,
+   field_type_strs[FIELD_TYPE_UNSIGNED]);
+ }
+ } else if (mp_typeof(*object_id) == MP_UINT) {
+ priv->object_id = tuple_field_u32_xc(tuple,
+      BOX_PRIV_FIELD_OBJECT_ID);
+ } else {
+ tnt_raise(ClientError, ER_FIELD_TYPE,
+   BOX_PRIV_FIELD_OBJECT_ID + TUPLE_INDEX_BASE,
+   field_type_strs[FIELD_TYPE_UNSIGNED]);
+ }
+
  if (priv->object_type == SC_UNKNOWN) {
  tnt_raise(ClientError, ER_UNKNOWN_SCHEMA_OBJECT,
    object_type);
diff --git a/src/box/bootstrap.snap b/src/box/bootstrap.snap
index b610828c9c9ae9a22acdd8c150c16c6838b7a273..da6961d1be7621fe9821623c7c2d57125e8ac7bc 100644
GIT binary patch
delta 1552
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
CN52^W

delta 1534
zcmV<a1p)e%41^4j7=JJ=G%zh^V>dT4F*z~{Np5p=VQyn(Iv_b=V_`LAF*YqTV`gS8
zG-hTvEnzrjFfCy?W;Qf4VP!dGGGq!?Lu_wjYdRo%F*+bOeF_TIx(m9^1&9F7A|rpb
zr2qf`001bpFZ}>e{VM<lJ=RLl7I6XqUp$Ch%_7lYJ_Lj_@PFoXP~+we(A76EO7~<&
z)F3;RA|;uhw(`4WgTRw>I&<{eU?~Ai$VOI~v629dx2JaIm@kx4N&&zCxB$xlBK}6v
zM#}nreKVfmYggvF>;bcooE<&pjzw|&ydgCd;B)Xi4C|Up=iRyONm;Mu=<J|49rmyj
z!~XSg?^aVP(0>n31mId~$~K1OP2OJJrGIzc!y|v*5Q}mxHFpG|K|%#jeQ^A;E^l>*
z3*Bp}NefgxX1+gm^KmUTgDMc1Jsb?P)oZC4!mL!?OgGcvU!7uNP_0u4V%4c@$$Tde
z<JJuBKo=+bJ1@oWHsew%rA$(CR4!bhCq$aiEJ3j}Cx2ttc)M<~yh-n@9Ru2aUZxgY
zOU+j=F>OCDy|bcHe0;hLW1g*=6kJQqvOo9n=`!@rT1v3PA=sEaGtUmrgF1V*+HwF$
z%o|ck2Ck)MDdN~U>lpNk)Rh9)Qd8p>$FU`TvVVQ}JNw3+pEy`&7|(v!cb#wKcU}Xc
zztr*E^M9!-1a3aZxQyRo-mQ)X;JxvQVS5a1E-Z#;*X8(mp!hlb(b=Wn_TxWHa?e&p
z0<NVdiD5jvlVdHR&M*6U`SOA@wvN<F<4PlXstt_|t42g+g<yeLeOP%|b(q;~x1wEl
zEj90~M>ms_NyVg8C=MtXRLX=hZO}2jlujiL*MCw|r<8%iFyl-urCG}bk_A!)lFN(Z
z*9rxd2`ZdQ%ZOz}8m(9>QmHeYBvm9q6rtA9wbTrW=uAh+mpZa8Z9M*WuhEnWw8OPP
z0Ken?`duE+M1Fc0sWuO;rRJ>TPnWxUKDEZdwbU$UUQcC(VtJFR2G>&aT`%TX-lUJ$
zzkkQk8h`!+Ak42Gb5O~I9X_GL4xhR(RGq@`<8YEmeGLBa%Ed{YaV#4wH7X6(wXrob
zRx(mCOfa|?Bo}qm;#z9jPz5?Ii>k-mKV61Bw$iw6MNm)>lUj2vHAVFK{#e#!kBV!l
ziDGG`ab1f2WXaFUg5t{}`TM8d6EBXt_J3uuRg$)9X&lOg&M*+4wU)S+njl=^i<EJZ
zX2ppwLyQ}LBXiMF<cgb*y<$jG_{C2oetkYX_VcpV`IoM<QW}RMaV<4zXt3a^V}T&3
z(OhIq3CsWhfB+}}AqGb&W<?JYfWSD4qc93!7zRWLI0_9I0RX{)ke~>l77Rj$ynhqj
zxeG%W18Ui|uoin^FOJH&6BE><l!R4e54%@5i^3tJ2=RjuhoRy}$qP!PWxP;CvBe2+
zB`AQ$m7GU4)NS@llAFhZ>1-;h#Us!zr2@yPWOP}$xk=>TS*Ej6Q8ZgBx&}sXh}Wym
z;Yvs=Xm6s&oTIkS5VXc28)t^2+kc4qR4r1#;*gdpU~^0s$pG8pm?G)gVGer7p5*j@
zrQSOro_cGm&fR}<@b8h^=iXW!%4reE=RqJFW<g443Z&4$8`^`Azzc12c=p(Su(w)T
z1)jmCmtK6UOn@l~=HxoFllhK1;>sqt`1BcS0HC@As3ba#z^Ko9Pi8avYk$Oa!!S#&
zSx3_!A8xyrpfT#3Y0zk_Hi}Y>p%$pI61F+5M3N&%2xKJAC;$CDD}<6?=$#5uoTZ5Z
zCNj}EgB|fKv=$L@ag>MEJ_76DnN*W1Z`O`MZ9ptwx|K1yxMV1V1(Ltx%(4y7obk4E
zW?=^8GIQ=kv4A0`wS7N1*>`Z!opukPx!_g@c{8|RJi<`!QS!z#<&+X#nnV8V6uo^%
zFL^|hfwSZ-+|LAZ&d5i?Zt>-$tMH_1UnT!Yb{@SussOv@WfJ50JyfLCQd9Bw_N-dh
k2=V>Mm|$S01}gnuSl5<E4okR>OyKJnJxL~`9Mur5?b8(5ga7~l

diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index b9b8c9004..361810c79 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -1801,17 +1801,19 @@ 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' or object_type == 'function' or
+       object_type == 'sequence' or object_type == 'role') and
+       object_name == nil then
+        return '*'
+    end
     if object_type == 'space' then
-        if object_name == nil or object_name == 0 then
-            return 0
-        end
         local space = box.space[object_name]
         if  space == nil then
             box.error(box.error.NO_SUCH_SPACE, object_name)
@@ -1819,9 +1821,6 @@ 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
-        end
         local _vfunc = box.space[box.schema.VFUNC_ID]
         local func
         if type(object_name) == 'string' then
@@ -1836,9 +1835,6 @@ 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
-        end
         local seq = sequence_resolve(object_name)
         if seq == nil then
             box.error(box.error.NO_SUCH_SEQUENCE, object_name)
@@ -1867,6 +1863,9 @@ local function object_name(object_type, object_id)
     if object_type == 'universe' then
         return ""
     end
+    if object_id == '*' then
+        return '*'
+    end
     local space
     if object_type == 'space' then
         space = box.space._vspace
@@ -2106,10 +2105,10 @@ local function grant(uid, name, privilege, object_type,
         _priv:replace{options.grantor, uid, object_type, oid, privilege_hex}
     elseif not options.if_not_exists then
             if object_type == 'role' then
-                box.error(box.error.ROLE_GRANTED, name, object_name)
+                box.error(box.error.ROLE_GRANTED, name, object_name or '*')
             else
                 box.error(box.error.PRIV_GRANTED, name, privilege,
-                          object_type, object_name)
+                          object_type, object_name or '*')
             end
     end
 end
@@ -2134,10 +2133,10 @@ local function revoke(uid, name, privilege, object_type, object_name, options)
             return
         end
         if object_type == 'role' then
-            box.error(box.error.ROLE_NOT_GRANTED, name, object_name)
+            box.error(box.error.ROLE_NOT_GRANTED, name, object_name or '*')
         else
             box.error(box.error.PRIV_NOT_GRANTED, name, privilege,
-                      object_type, object_name)
+                      object_type, object_name or '*')
         end
     end
     local old_privilege = tuple[5]
@@ -2153,13 +2152,14 @@ local function revoke(uid, name, privilege, object_type, object_name, options)
             return
         end
         box.error(box.error.PRIV_NOT_GRANTED, name, privilege,
-                  object_type, object_name)
+                  object_type, object_name or '*')
     end
     if privilege_hex ~= 0 then
         _priv:replace{grantor, uid, object_type, oid, privilege_hex}
     else
         _priv:delete{uid, object_type, oid}
     end
+
 end
 
 local function drop(uid, opts)
@@ -2192,9 +2192,10 @@ 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()
-        box.session.su("admin", revoke, uid, uid, tuple[5], tuple[3], tuple[4])
+        -- we need an additional box.session.su() here, because of
+        -- unnecessary check for privilege PRIV_REVOKE in priv_def_check()
+        local oid = tuple[4] ~= '*' and tuple[4] or nil
+        box.session.su("admin", revoke, uid, uid, tuple[5], tuple[3], oid)
     end
     box.space[box.schema.USER_ID]:delete{uid}
 end
diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua
index 0293f6ef8..5dbc09bbb 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.1
+--------------------------------------------------------------------------------
+local function upgrade_space_priv_to_1_10_1()
+    local _priv = box.space._priv
+    local _vpriv = box.space._vpriv
+    local f = _priv:format()
+
+    f[4].type = 'scalar'
+    _priv:format(f)
+    f = _vpriv:format()
+    f[4].type = 'scalar'
+    _vpriv:format(f)
+    _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_1()
+    upgrade_space_priv_to_1_10_1()
+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, 1), func = upgrade_to_1_10_1, auto = true},
     }
 
     for _, handler in ipairs(handlers) do
diff --git a/src/box/schema.cc b/src/box/schema.cc
index 433f52c08..9958e9016 100644
--- a/src/box/schema.cc
+++ b/src/box/schema.cc
@@ -536,10 +536,18 @@ schema_find_name(enum schema_object_type type, uint32_t object_id)
  switch (type) {
  case SC_UNIVERSE:
  return "";
+ case SC_ENTITY_SPACE:
+ return "";
+ case SC_ENTITY_FUNCTION:
+ return "";
+ case SC_ENTITY_SEQUENCE:
+ return "";
+ case SC_ENTITY_ROLE:
+ return "";
+ case SC_ENTITY_USER:
+ return "";
  case SC_SPACE:
  {
- if (object_id == 0)
- return "SPACE";
  struct space *space = space_by_id(object_id);
  if (space == NULL)
  break;
@@ -547,8 +555,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 +562,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 0822262d0..f1735ff34 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 97c074ab2..18ec6c8d2 100644
--- a/src/box/schema_def.c
+++ b/src/box/schema_def.c
@@ -31,16 +31,39 @@
 #include "schema_def.h"
 
 static const char *object_type_strs[] = {
- /* [SC_UKNNOWN]         = */ "unknown",
- /* [SC_UNIVERSE]        = */ "universe",
- /* [SC_SPACE]           = */ "space",
- /* [SC_FUNCTION]        = */ "function",
- /* [SC_USER]            = */ "user",
- /* [SC_ROLE]            = */ "role",
- /* [SC_SEQUENCE]        = */ "sequence",
- /* [SC_COLLATION]       = */ "collation",
+ /* [SC_UKNNOWN]     = */ "unknown",
+ /* [SC_UNIVERSE]     = */ "universe",
+ /* [SC_SPACE]     = */ "space",
+ /* [SC_ENTITY_SPACE]     = */ "space",
+ /* [SC_FUNCTION]     = */ "function",
+ /* [SC_ENTITY_FUNCTION]     = */ "function",
+ /* [SC_USER]     = */ "user",
+ /* [SC_ENTITY_USER]     = */ "user",
+ /* [SC_ROLE]     = */ "role",
+ /* [SC_ENTITY_ROLE]     = */ "role",
+ /* [SC_SEQUENCE]     = */ "sequence",
+ /* [SC_ENTITY_SEQUENCE]     = */ "sequence",
+ /* [SC_COLLATION]     = */ "collation",
+ /* [SC_ENTITY_COLLATION]    = */ "collation",
 };
 
+enum schema_object_type
+schema_entity_type(enum schema_object_type type)
+{
+ switch(type) {
+ case SC_SPACE:
+ case SC_FUNCTION:
+ case SC_USER:
+ case SC_ROLE:
+ case SC_SEQUENCE:
+ case SC_COLLATION:
+ return type + 1;
+ break;
+ default:
+ unreachable();
+ }
+}
+
 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 2edb8d37f..9b5bd6864 100644
--- a/src/box/schema_def.h
+++ b/src/box/schema_def.h
@@ -218,19 +218,35 @@ enum {
  *
  * Use 0 for unknown to use the same index consistently
  * even when there are more object types in the future.
+ *
+ * When adding new types please follow this rule:
+ * SC_ENTITY_NEW_OBJECT = SC_NEW_OBJECT + 1
+ * schema_entity_type() relies on this convention.
  */
 enum schema_object_type {
  SC_UNKNOWN = 0,
  SC_UNIVERSE = 1,
  SC_SPACE = 2,
- SC_FUNCTION = 3,
- SC_USER = 4,
- SC_ROLE = 5,
- SC_SEQUENCE = 6,
- SC_COLLATION = 7,
- schema_object_type_MAX = 8
+ SC_ENTITY_SPACE = 3,
+ SC_FUNCTION = 4,
+ SC_ENTITY_FUNCTION = 5,
+ SC_USER = 6,
+ SC_ENTITY_USER = 7,
+ SC_ROLE = 8,
+ SC_ENTITY_ROLE = 9,
+ SC_SEQUENCE = 10,
+ SC_ENTITY_SEQUENCE = 11,
+ SC_COLLATION = 12,
+ SC_ENTITY_COLLATION = 13,
+ schema_object_type_MAX = 13
 };
 
+/**
+ * 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 fbf06566a..eec785652 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 16c2027cf..1641c318e 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, 1]
 ...
 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 f4669a4a3..687bbf579 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 2d87fa2d5..7d6aa0a4b 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 eb7014d8b..36bdb5fd3 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 f02996bba..8f5b4ad26 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, 1]
 ...
 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']]]
-- 
2.15.2 (Apple Git-101.1)