diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml
index 8d86e362d6f83f546385f0cb03b3df6c1ec6afd1..734c19320dee091a0da0ff5c012f26130a5cbe9f 100644
--- a/doc/user/stored-procedures.xml
+++ b/doc/user/stored-procedures.xml
@@ -363,7 +363,8 @@ localhost> lua box.select(5, 1, 'firstname', 'lastname')
         <listitem>
             <para>
                 Update a tuple identified by a primary
-                <code>key</code>. Update arguments follow,
+                <code>key</code>. If a key is multipart,
+                it is passed in as a Lua table. Update arguments follow,
                 described by <code>format</code>.
                 The format and arguments are passed to
                 <code>box.pack()</code> and the result is sent
diff --git a/mod/box/box.lua b/mod/box/box.lua
index 94f31c6d6d6e4b4d892135c7a3fafaa48bf1f579..f88782e80158f160ae4255165b361c1dd63558d3 100644
--- a/mod/box/box.lua
+++ b/mod/box/box.lua
@@ -2,17 +2,13 @@
 -- A run-time error will be raised on attempt to change
 -- table members.
 local function create_const_table(table)
-    return setmetatable ({}, {
-			     __index = table,
-			     __newindex = function(table_arg,
-						   name_arg,
-						   value_arg)
-				 error("attempting to change constant " ..
-				       tostring(name_arg) ..
-				       " to "
-				       .. tostring(value_arg), 2)
-			     end
-			     })
+    local function newindex(table, name, value)
+        error("Attempt to change constant "..tostring(name)..
+              " to "..tostring(value))
+    end
+    return setmetatable({}, { __index = table,
+                              __newindex = newindex,
+                              __metatable = false })
 end
 
 --- box flags
@@ -115,14 +111,19 @@ end
 --
 function box.update(space, key, format, ...)
     local op_count = select('#', ...)/2
-    return box.process(19,
-                       box.pack('iiipi'..format,
-                                  space,
-                                  1, -- flags, BOX_RETURN_TUPLE
-                                  1, -- primary key part count
-                                  key, -- primary key
-                                  op_count, -- op count
-                                  ...))
+    if type(key) == 'table' then
+        part_count = #key
+        return box.process(19,
+                    box.pack('iii'..string.rep('p', part_count),
+                        space, box.flags.BOX_RETURN_TUPLE, part_count,
+                        unpack(key))..
+                    box.pack('i'..format, op_count, ...))
+    else
+        return box.process(19,
+                    box.pack('iiipi'..format,
+                        space, box.flags.BOX_RETURN_TUPLE, 1,
+                        key, op_count, ...))
+    end
 end
 
 box.upd = {}
@@ -332,3 +333,5 @@ os.rename = nil
 os.tmpname = nil
 os.remove = nil
 require = nil
+
+-- vim: set et ts=4 sts
diff --git a/test/box_big/tree_pk_multipart.test b/test/box_big/tree_pk_multipart.test
index 648b2bfa866c8fb8f91c78964a762338c4a0a0f5..5995946ceb4e596c65591613040a2d640a53ad93 100644
--- a/test/box_big/tree_pk_multipart.test
+++ b/test/box_big/tree_pk_multipart.test
@@ -78,6 +78,8 @@ exec admin "lua box.delete(9, 'The Wolf!', 'Vincent', 0)"
 exec admin "lua box.delete(9, 'The Wolf!', 'Vincent', 3)"
 exec admin "lua box.delete(9, 'Vincent', 'The Wolf!', 0)"
 
+exec admin "lua box.update(9, {'Vincent', 'The Wolf!', 1}, '=p=p', 0, 'Updated', 4, 'New')"
+exec admin "lua box.update(9, {'Updated', 'The Wolf!', 1}, '=p#p', 0, 'Vincent', 4, '')"
 # Checking Vincent's last messages
 exec admin "lua box.select(9, 0, 'Vincent', 'The Wolf!')"
 # Checking The Wolf's last messages