diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua index 7a4464338d75321962f53f8b6b5168c7a5ed7a17..cb6dfba24a3944f115cadb642406aa8613b80c59 100644 --- a/src/box/lua/upgrade.lua +++ b/src/box/lua/upgrade.lua @@ -91,6 +91,23 @@ local function set_system_triggers(val) foreach_system_space(function(s) s:run_triggers(val) end) end +-- Clears formats of all system spaces. It is used to disable system space +-- format checking before creation of a bootstrap snapshot. +local function clear_system_formats() + foreach_system_space(function(s) + box.space._space:update({s.id}, {{'=', 7, {}}}) + end) +end + +-- Applies no-op update to all system space records to run system triggers. +-- It is used to re-enable system space format checking after creation of +-- a bootstrap snapshot. +local function reset_system_formats() + foreach_system_space(function(s) + box.space._space:update({s.id}, {}) + end) +end + local function version_from_tuple(tuple) local major, minor, patch = tuple:unpack(2, 4) patch = patch or 0 @@ -336,7 +353,6 @@ local function initial_1_7_5() local _cluster = box.space[box.schema.CLUSTER_ID] local _truncate = box.space[box.schema.TRUNCATE_ID] local MAP = setmap({}) - local datetime = os.date("%Y-%m-%d %H:%M:%S") -- -- _schema @@ -481,8 +497,8 @@ local function initial_1_7_5() -- Create users -- log.info("create user guest") - _user:insert{GUEST, ADMIN, 'guest', 'user', MAP} - box.schema.user.passwd('guest', '') + _user:insert{GUEST, ADMIN, 'guest', 'user', + {['chap-sha1'] = 'vhvewKp0tNyweZQ+cFKAlsyphfg='}} log.info("create user admin") _user:insert{ADMIN, ADMIN, 'admin', 'user', MAP} log.info("create role public") @@ -511,9 +527,7 @@ local function initial_1_7_5() -- create "box.schema.user.info" function log.info('create function "box.schema.user.info" with setuid') - _func:replace({1, ADMIN, 'box.schema.user.info', 1, 'LUA', '', 'function', - {}, 'any', 'none', 'none', false, false, true, {'LUA'}, - MAP, '', datetime, datetime}) + _func:replace{1, ADMIN, 'box.schema.user.info', 1, 'LUA'} -- grant 'public' role access to 'box.schema.user.info' function log.info('grant execute on function "box.schema.user.info" to public') @@ -654,7 +668,8 @@ end -------------------------------------------------------------------------------- local function create_vsequence_space() create_sysview(box.schema.SEQUENCE_ID, box.schema.VSEQUENCE_ID) - box.space._vsequence:format(sequence_format) + box.space._space:update({box.schema.VSEQUENCE_ID}, + {{'=', 7, sequence_format}}) end local function upgrade_to_1_10_0() @@ -667,23 +682,18 @@ end local function upgrade_priv_to_1_10_2() local _priv = box.space._priv local _vpriv = box.space._vpriv + local _space = box.space._space local _index = box.space._index - local format = _priv:format() - - format[4].type = 'scalar' - _priv:format(format) - format = _vpriv:format() - format[4].type = 'scalar' - _vpriv:format(format) - + _space:update({_priv.id}, {{'=', '[7][4].type', 'scalar'}}) + _space:update({_vpriv.id}, {{'=', '[7][4].type', 'scalar'}}) _index:update({_priv.id, _priv.index.primary.id}, - {{'=', 'parts', {{1, 'unsigned'}, {2, 'string'}, {3, 'scalar'}}}}) + {{'=', 6, {{1, 'unsigned'}, {2, 'string'}, {3, 'scalar'}}}}) _index:update({_vpriv.id, _vpriv.index.primary.id}, - {{'=', 'parts', {{1, 'unsigned'}, {2, 'string'}, {3, 'scalar'}}}}) + {{'=', 6, {{1, 'unsigned'}, {2, 'string'}, {3, 'scalar'}}}}) _index:update({_priv.id, _priv.index.object.id}, - {{'=', 'parts', {{2, 'string'}, {3, 'scalar'}}}}) + {{'=', 6, {{2, 'string'}, {3, 'scalar'}}}}) _index:update({_vpriv.id, _priv.index.object.id}, - {{'=', 'parts', {{2, 'string'}, {3, 'scalar'}}}}) + {{'=', 6, {{2, 'string'}, {3, 'scalar'}}}}) end local function create_vinyl_deferred_delete_space() @@ -785,7 +795,7 @@ local function upgrade_to_2_1_0() local format = {} format[1] = {type='string', name='key'} format[2] = {type='any', name='value', is_nullable=true} - box.space._schema:format(format) + _space:update({box.schema.SCHEMA_ID}, {{'=', 7, format}}) box.space._collation:replace{0, "none", ADMIN, "BINARY", "", setmap{}} box.space._collation:replace{3, "binary", ADMIN, "BINARY", "", setmap{}} @@ -800,7 +810,7 @@ end local function upgrade_to_2_1_1() local _index = box.space[box.schema.INDEX_ID] for _, index in _index:pairs() do - local opts = index.opts + local opts = index[5] if opts['sql'] ~= nil then opts['sql'] = nil _index:replace(box.tuple.new({index.id, index.iid, index.name, @@ -956,6 +966,7 @@ end -- Add sequence field to _space_sequence table local function upgrade_sequence_to_2_2_1() log.info("add sequence field to space _space_sequence") + local _space = box.space[box.schema.SPACE_ID] local _index = box.space[box.schema.INDEX_ID] local _space_sequence = box.space[box.schema.SPACE_SEQUENCE_ID] for _, v in _space_sequence:pairs() do @@ -977,10 +988,10 @@ local function upgrade_sequence_to_2_2_1() _space_sequence:insert(t) ::continue:: end - local format = _space_sequence:format() - format[4] = {name = 'field', type = 'unsigned'} - format[5] = {name = 'path', type = 'string'} - _space_sequence:format(format) + _space:update({_space_sequence.id}, { + {'=', '[7][4]', {name = 'field', type = 'unsigned'}}, + {'=', '[7][5]', {name = 'path', type = 'string'}}, + }) end local function upgrade_ck_constraint_to_2_2_1() @@ -1004,27 +1015,27 @@ local function upgrade_ck_constraint_to_2_2_1() {unique = true}, {{0, 'unsigned'}, {1, 'string'}}} for _, space in _space:pairs() do - local flags = space.flags + local id = space[1] + local name = space[3] + local flags = space[6] if flags.checks then for i, check in pairs(flags.checks) do local expr_str = check.expr local check_name = check.name or - "CK_CONSTRAINT_"..i.."_"..space.name - _ck_constraint:insert({space.id, check_name, false, - 'SQL', expr_str}) + "CK_CONSTRAINT_" .. i .. "_" .. name + _ck_constraint:insert({id, check_name, false, 'SQL', expr_str}) end flags.checks = nil - _space:replace({space.id, space.owner, space.name, space.engine, - space.field_count, flags, space.format}) + _space:update({id}, {{'=', 6, flags}}) end end end local function create_vcollation_space() - local _collation = box.space._collation - local format = _collation:format() + local _space = box.space._space + local format = _space:get({box.schema.COLLATION_ID})[7] create_sysview(box.schema.COLLATION_ID, box.schema.VCOLLATION_ID) - box.space[box.schema.VCOLLATION_ID]:format(format) + _space:update({box.schema.VCOLLATION_ID}, {{'=', 7, format}}) end local function upgrade_func_to_2_2_1() @@ -1033,10 +1044,9 @@ local function upgrade_func_to_2_2_1() local _priv = box.space[box.schema.PRIV_ID] local datetime = os.date("%Y-%m-%d %H:%M:%S") for _, v in box.space._func:pairs() do - box.space._func:replace({v.id, v.owner, v.name, v.setuid, v[5] or 'LUA', - '', 'function', {}, 'any', 'none', 'none', - false, false, true, v[15] or {'LUA'}, - setmap({}), '', datetime, datetime}) + _func:replace({v[1], v[2], v[3], v[4], v[5] or 'LUA', '', 'function', + {}, 'any', 'none', 'none', false, false, true, + v[15] or {'LUA'}, setmap({}), '', datetime, datetime}) end local sql_builtin_list = { "TRIM", "TYPEOF", "PRINTF", "UNICODE", "CHAR", "HEX", "VERSION", @@ -1056,14 +1066,14 @@ local function upgrade_func_to_2_2_1() 'function', {}, 'any', 'none', 'none', false, false, true, {}, setmap({}), '', datetime, datetime}) - _priv:replace{ADMIN, PUBLIC, 'function', t.id, box.priv.X} + _priv:replace{ADMIN, PUBLIC, 'function', t[1], box.priv.X} end local t = _func:auto_increment({ADMIN, 'LUA', 1, 'LUA', 'function(code) return assert(loadstring(code))() end', 'function', {'string'}, 'any', 'none', 'none', false, false, true, {'LUA', 'SQL'}, setmap({}), '', datetime, datetime}) - _priv:replace{ADMIN, PUBLIC, 'function', t.id, box.priv.X} + _priv:replace{ADMIN, PUBLIC, 'function', t[1], box.priv.X} local format = {} format[1] = {name='id', type='unsigned'} format[2] = {name='owner', type='unsigned'} @@ -1084,10 +1094,10 @@ local function upgrade_func_to_2_2_1() format[17] = {name='comment', type='string'} format[18] = {name='created', type='string'} format[19] = {name='last_altered', type='string'} - _func:format(format) + box.space._space:update({_func.id}, {{'=', 7, format}}) box.space._index:update( {_func.id, _func.index.name.id}, - {{'=', 'parts', {{field = 2, type = 'string', collation = 2}}}}) + {{'=', 6, {{field = 2, type = 'string', collation = 2}}}}) end local function create_func_index() @@ -1121,6 +1131,7 @@ end local function upgrade_to_2_3_0() log.info("Create GREATEST and LEAST SQL Builtins") + local _space = box.space[box.schema.SPACE_ID] local _func = box.space[box.schema.FUNC_ID] local _priv = box.space[box.schema.PRIV_ID] local datetime = os.date("%Y-%m-%d %H:%M:%S") @@ -1130,7 +1141,7 @@ local function upgrade_to_2_3_0() 'function', {}, 'any', 'none', 'none', false, false, true, {}, setmap({}), '', datetime, datetime}) - _priv:replace{ADMIN, PUBLIC, 'function', t.id, box.priv.X} + _priv:replace{ADMIN, PUBLIC, 'function', t[1], box.priv.X} end log.info("Extend _ck_constraint space format with is_enabled field") @@ -1144,7 +1155,7 @@ local function upgrade_to_2_3_0() {name='language', type='str'}, {name='code', type='str'}, {name='is_enabled', type='boolean'}} - _ck_constraint:format(format) + _space:update({_ck_constraint.id}, {{'=', 7, format}}) end -------------------------------------------------------------------------------- @@ -1154,7 +1165,7 @@ end local function drop_func_collation() local _func = box.space[box.schema.FUNC_ID] box.space._index:update({_func.id, _func.index.name.id}, - {{'=', 'parts', {{2, 'string'}}}}) + {{'=', 6, {{2, 'string'}}}}) end local function create_session_settings_space() @@ -1187,7 +1198,7 @@ local function function_access() for _, name in pairs(funcs_to_change) do local func = _func.index['name']:get(name) if func ~= nil and func.setuid ~= 0 then - local id = func.id + local id = func[1] log.info('remove old function "'..name..'"') _priv:delete({2, 'function', id}) _func:delete({id}) @@ -1212,9 +1223,11 @@ local function remove_sql_builtin_functions_from_func() local _func = box.space._func local _priv = box.space._priv for _, v in _func:pairs() do - if v.language == "SQL_BUILTIN" then - _priv:delete({2, 'function', v.id}) - _func:delete({v.id}) + local id = v[1] + local language = v[5] + if language == "SQL_BUILTIN" then + _priv:delete({2, 'function', id}) + _func:delete({id}) end end end @@ -1245,22 +1258,24 @@ local function revoke_execute_access_to_lua_function_from_role_public() local _priv = box.space[box.schema.PRIV_ID] if box.func.LUA then local row = _priv:get{PUBLIC, 'function', box.func.LUA.id} - if row and bit.band(row.privilege, box.priv.X) ~= 0 then - local privilege = bit.bxor(row.privilege, box.priv.X) + local privilege = row and row[5] or nil + if privilege and bit.band(privilege, box.priv.X) ~= 0 then + local privilege = bit.bxor(privilege, box.priv.X) -- Note that X privilege sometimes implies R privilege, -- for example executable functions are visible in _vfunc. -- Let's make minimal changes, leaving R privilege instead of X. privilege = bit.bor(privilege, box.priv.R) log.info("revoke execute access to 'LUA' function from public role") _priv:update({PUBLIC, 'function', box.func.LUA.id}, - {{'=', 'privilege', privilege}}) + {{'=', 5, privilege}}) end end end local function make_vfunc_same_format_as_func() log.info("Make format of _vfunc the same as the format of _func") - box.space._vfunc:format(box.space._func:format()) + local format = box.space._space:get({box.schema.FUNC_ID})[7] + box.space._space:update({box.schema.VFUNC_ID}, {{'=', 7, format}}) end local function upgrade_to_2_10_4() @@ -1284,33 +1299,37 @@ local function convert_sql_constraints_to_tuple_constraints() local _ck = box.space[box.schema.CK_CONSTRAINT_ID] log.info("convert constraints from _ck_constraint and _fk_constraint") for _, v in _fk:pairs() do - local def = _space:get{v.child_id} + local name = v[1] + local child_id = v[2] + local parent_id = v[3] + local child_cols = v[8] + local parent_cols = v[9] + local def = _space:get{child_id} local mapping = setmap({}) - for i, id in pairs(v.child_cols) do - mapping[id] = v.parent_cols[i] + for i, id in pairs(child_cols) do + mapping[id] = parent_cols[i] end - local fk = def.flags.foreign_key or {} - fk[v.name] = {space = v.parent_id, field = mapping} - local new_def = def:totable() - new_def[6].foreign_key = fk - _space:replace(new_def) - _fk:delete({v.name, v.child_id}) + local fk = def[6].foreign_key or {} + fk[name] = {space = parent_id, field = mapping} + _space:update({child_id}, {{'=', '[6].foreign_key', fk}}) + _fk:delete({name, child_id}) end for _, v in _ck:pairs() do + local space_id = v[1] + local name = v[2] + local code = v[5] local _func = box.space._func - local def = _space:get{v.space_id} + local def = _space:get{space_id} local datetime = os.date("%Y-%m-%d %H:%M:%S") - local name = 'check_'..def.name.."_"..v.name - local t = _func:auto_increment({ADMIN, name, 1, 'SQL_EXPR', v.code, + local func_name = 'check_' .. def[3] .. '_' .. name + local t = _func:auto_increment({ADMIN, func_name, 1, 'SQL_EXPR', code, 'function', {}, 'any', 'none', 'none', true, true, true, {'LUA'}, setmap({}), '', datetime, datetime}) local ck = def.flags.constraint or {} - ck[v.name] = t.id - local new_def = def:totable() - new_def[6].constraint = ck - _space:replace(new_def) - _ck:delete({v.space_id, v.name}) + ck[name] = t[1] + _space:update({space_id}, {{'=', '[6].constraint', ck}}) + _ck:delete({space_id, name}) end end @@ -1480,6 +1499,11 @@ local function upgrade(options) end local function bootstrap() + -- Disabling system triggers doesn't turn off space format checks. + -- Since a system space format may be updated during the bootstrap + -- sequence, we clear all formats so that we can insert any data + -- into system spaces and reset them back after we're done. + clear_system_formats() set_system_triggers(false) -- erase current schema @@ -1490,6 +1514,7 @@ local function bootstrap() upgrade{_initial_version = mkversion(1, 7, 5)} set_system_triggers(true) + reset_system_formats() -- save new bootstrap.snap box.snapshot()