[tarantool-patches] Re: [PATCH v2] Introduce separate entity object types for entity privileges.

  • From: Serge Petrenko <sergepetrenko@xxxxxxxxxxxxx>
  • To: Vladimir Davydov <vdavydov.dev@xxxxxxxxx>
  • Date: Fri, 17 Aug 2018 15:19:29 +0300

Hi! Thank you for review. I fixed your comments, the new diff is below.

17 авг. 2018 г., в 12:19, Vladimir Davydov <vdavydov.dev@xxxxxxxxx> 
написал(а):

On Tue, Aug 14, 2018 at 04:41:25PM +0300, Serge Petrenko wrote:
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);

This isn't object_id. It's msgpack. Please rename this variable to
emphasize that. For instance, 'object_id_field', 'object_id_raw', or
simply 'data’.

Ok, let it be ‘data’.


+    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) {

Nit: in a case like this, better use strcmp.

We decided to switch to «» (empty string), so use mp_decode_strl(&data) == 0 
here


+                    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]);
+    }
+

Somehow, I don't like this piece of code. For instance, you raise
the same error (FIELD_TYPE_UNSIGNED) in two places. Also, you use
tuple_field_*_xc after you explicitly check the type, which is
pointless, because they can't fail.

May be, something like this?

      switch (mp_typeof(*data)) {
      case MP_STR:
              if (mp_decode_strl(&data) == 0) {
                      /* Entity-wide privilege. */
                      priv->object_id = 0;
                      break;
              }
              FALLTHROUGH;
      default:
              priv->object_id = tuple_field_u32_xc(...);
      }

Ok, I use your variant.


     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..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

No, I don't like this: now, if you want to add a new object type,
you have to patch two places: here and below, where the object name
is resolved. Let's leave it as before.

Ok.


    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
+

Extra new line, please remove.

Done


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},

Should be 1.10.2

1.10.1 has already been released.

Changed to 1.10.2 and updated bootstrap.snap


    }

    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 "";

Please rewrite it as

      case SC_ENTITY_SPACE:
      case SC_ENTITY_FUNCTION:
      case SC_ENTITY_SEQUENCE:
      ...
              return "";

Also, I don't like that sometimes we use '*' and sometimes '' when
reporting errors. What about using '' for entity-wide privileges
everywhere, including the _priv space? This would save us from
possible conflicts with objects named '*' (yeah, no sane user would
call a space like that, but still). This would also allow us to
simplify object_resolve() as I suggested in the previous review
round.

Done. I like the idea with using «» instead of «*», switched to that.

     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",

I don't like this code duplication. Actually, I don't think that you
need to have separate names for entity-wide privileges at all: AFAICS,
schema_object_name() is never called for SC_ENTITY_*. Let's remove
SC_ENTITY_* from this array.

If you do that, you won't be able to increment object type to get entity
type. Well, OK, it's not that scary, taking into account the fact that
you always use a helper function for that (see right below). I see it
that way

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

      /* Entity types. */
      SC_ENTITY_SPACE,
      SC_ENTITY_FUNCTION,
      …
}


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;
      ...
      }
}


Ok, switched to your variant with slight differences.

};

+enum schema_object_type
+schema_entity_type(enum schema_object_type type)
+{
+    switch(type) {

            ^^
        space missing

Fixed.


+    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
};


---
 src/box/alter.cc             |  27 +++++++++++++++++++-
 src/box/bootstrap.snap       | Bin 1540 -> 1556 bytes
 src/box/lua/schema.lua       |  58 ++++++++++++++++++++++++++-----------------
 src/box/lua/upgrade.lua      |  23 +++++++++++++++++
 src/box/schema.cc            |  11 ++++----
 src/box/schema.h             |  23 +++++++++--------
 src/box/schema_def.c         |   7 ++++++
 src/box/schema_def.h         |  18 +++++++++++++-
 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, 166 insertions(+), 78 deletions(-)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 3007a131d..f586a2695 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);
diff --git a/src/box/bootstrap.snap b/src/box/bootstrap.snap
index 
b610828c9c9ae9a22acdd8c150c16c6838b7a273..44992b050e9d73d69608fb92782d1e965f6cdc51
 100644
GIT binary patch
delta 1551
zcmV+q2JrcW43rFz7=JM>GB!9ZXE|m$WMeloGhzx!ZgX^DZewLSAT%>EG&o@}VJ$c{
zGcheRV>UP~VPZ03EipATVq!NoIX7cCWeQe9Y;R+0Iv{&}3JTS_3%bn(nE=k-$Bkd5
z0000004TLD{QyvfEC41w*h<hAaRLBeJb=_J{}F0FAgJ*mVt>V;#?6&k&og$Aul<dv
zv3Dv(N-{sS_S_R$=If$P=IFJ-Qc5dSF3)wMv;i7#PyNg>UnEmX0mA^f0L=io5sT!g
zD{Fnf#vxPKYgy*n?1AMVIy{=p9gia^hC=L0fWLuz8rC_P&bxEnm$jbL+0jvRI_+sG
zru|Ih;m)d9Ab%fU2!MAhTHBbGce$H&nf~2*&yFmHLT-w8E2;yCj1eht_F<%$wYjrA
z--_qmirxZNlbP>7cRjpY(I5*1%V7?t>8y7vDuOB;TVebwm5d3mRG{g<l`_3ftd)rc
zn_;zHClt(+{hgbmxU+pKw$>&pI!j<g$w35)6B;Hdw}0vc|76#A%XVkpWtdu!!EHY`
zQ473V(OEa~Z9g}|)Sgs&h}w*uq0W{Rc(<Zvf8ImXW-LrCDFM%iVB<2)IG&t`=^X0p
z%Yh$fD8!Boc(<bFh|kp4F)S=%TMBr$q8k55lCM#${Y=DS+Bfbz&A~d;aQkK7b>5ZV
zdG3dP6Mx6^(8sb6!1;Xg8sDAa&WZ-$y>W_Zn~dpXc#Nf8o1_@R#?P@Ion`uUK3>En
z4|O&qz`GSKF%8FiNe275855I3zK&RX`$!^s><!J0t0shXfpC3jd1!TLaj@ww*s37t
z-HLiP9v};~La9)x)67Zcgesj%8+J-DBoj%4cYiCoL(1@BuzjT$lI`Wf$ik??2xi9d
ztc3#01eTBGMdTtHiCXRru~^$q5*v~bieRnCyA@ptRojk|H*sWb>UR9^o~tSri06BO
z0Q-*j>z9Q*4+(#G7_m1GyjxLQ$D%fO4}ENn1MgPUw1qv^wQ}ZNwi<Z1qOu?JnRn@f
zM}I7Goln@sxA7u>0uPF;){6CdrBo=>OXh`5;7UxHP%|pfgijbup=MGrPps{8(Quhz
zWw^YXTN9%N1NEZh;%hNtVMQxeEKqt?SWV_GYBSbz?d=0?f`WpY*c$IvG*qAOKeIM_
zQh2wbDYx3&2cp<tnmn~GC&WCKzkjS};(teS=fpg|%u;9X?K_pwnFhnDwIsY-(GRlN
ztgP{o#>Rx0;YE$dsj=v%(gx?x*@*;&XWUfcndq})KR0uozbQ*?y?v(<-mNH&3>7#_
z#&nJefg`BVSY%8M%m4s@04M+v21hAoRSyz?&^U^NFbZH021E!rh)xs$fZ#w_L4OfM
zEf@qq49vQeA))6t$8JsxhygJm2AP2;6jR1Ytzq>yuq)+j_YBuXSm^>oOc44oRR2+r
zfKn$8@9xdDJsnXgj8fvJX-OOEnOz2N82f7Vr6^tAcX*WFIPM{0Ntj!pLMS~2mv!oE
zRrM)J%oMN{r_N{V(s7_ah4$kjihs$6<OnC-Xy|vNdloebHTnit@EUCcD|n6OjV)em
zPC$*u2HNnREZ$rv)082si4@Jx$$z3_Ifq*d0kp^Vv;;5qa1a|JkDvz!Y7ZzgZLtTG
znKqel_G}Nk_kmTD8UY2Zw|;97AY4LmR2{?0eUDLb#Sq+kdJS#-4;^$U>3_%%=)mhn
z2W|IQc+vMG<^-d?>WOsJ?wF5DwFGHVZ;5{eV6!P9un202v<JSzI-4XFWp2pfJ=}&9
z|B3!R7$^i;Ur3=7lANu}q6eAjK|>w!Z8R4d19B91M{)$#!E>qp7jG6HO>MyhU^@4T
z^f(MLmIX$FanP|HqB(=3bAPgI29$n(?koqvkkh_+Jdt&9kemV%zz>2&MdX*2g^(0B
zb3fr-G#O-Ux`l`P)LF58aj(U8%fMRlqE2MOof#G*F;Vmq(Um!gfT;c#$##_N2vs0b
zGn`~?u8)RY;W>4D58f)EMzh}yokR<1H8AM^(7KO=Ygngs1QB1+=m<%o!R6Hut?jEW
B)aL*I

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?adb1g8%>k

diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index b9b8c9004..d347fd1e6 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 0293f6ef8..091da2dc4 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_space_priv_to_1_10_2()
+    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_2()
+    upgrade_space_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 433f52c08..4502ca6dc 100644
--- a/src/box/schema.cc
+++ b/src/box/schema.cc
@@ -535,11 +535,14 @@ 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:
+       case SC_ENTITY_ROLE:
+       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 +550,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 +557,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..bbae046c3 100644
--- a/src/box/schema_def.c
+++ b/src/box/schema_def.c
@@ -41,6 +41,13 @@ static const char *object_type_strs[] = {
        /* [SC_COLLATION]       = */ "collation",
 };
 
+enum schema_object_type
+schema_entity_type(enum schema_object_type type)
+{
+       assert((int) type < (int) schema_object_type_MAX);
+       return type + schema_object_type_MAX - 1;
+}
+
 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..5ece809f1 100644
--- a/src/box/schema_def.h
+++ b/src/box/schema_def.h
@@ -218,6 +218,10 @@ 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 keep the
+ * same order between objects and corresponding entity types.
+ * schema_entity_type() relies on this convention.
  */
 enum schema_object_type {
        SC_UNKNOWN = 0,
@@ -228,9 +232,21 @@ enum schema_object_type {
        SC_ROLE = 5,
        SC_SEQUENCE = 6,
        SC_COLLATION = 7,
-       schema_object_type_MAX = 8
+       schema_object_type_MAX = 8,
+       SC_ENTITY_SPACE,
+       SC_ENTITY_FUNCTION,
+       SC_ENTITY_USER,
+       SC_ENTITY_ROLE,
+       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 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..cf8242de5 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 f4669a4a3..599500633 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..3061f1181 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..76467baf1 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']]]
-- 
2.15.2 (Apple Git-101.1)



Other related posts: