diff --git a/benches/engine.rs b/benches/engine.rs
index e9f38b716454c74c5eece12ba72fc260af338110..2aea2e0518692f254be98ef3f44c407f76966686 100644
--- a/benches/engine.rs
+++ b/benches/engine.rs
@@ -3,7 +3,7 @@ extern crate sbroad;
 use sbroad::errors::QueryPlannerError;
 use sbroad::executor::bucket::Buckets;
 use sbroad::executor::engine::cartridge::hash::str_to_bucket_id;
-use sbroad::executor::engine::Engine;
+use sbroad::executor::engine::{Engine, LocalMetadata};
 use sbroad::executor::ir::ExecutionPlan;
 use sbroad::executor::result::{BoxExecuteFormat, Value};
 use sbroad::executor::vtable::VirtualTable;
@@ -225,15 +225,15 @@ impl Engine for EngineMock {
         self.metadata.tables.is_empty()
     }
 
-    fn get_schema(&self) -> Result<Option<String>, QueryPlannerError> {
-        Ok(Some("".to_string()))
+    fn get_metadata(&self) -> Result<Option<LocalMetadata>, QueryPlannerError> {
+        let metadata = LocalMetadata {
+            schema: "".into(),
+            timeout: 0,
+        };
+        Ok(Some(metadata))
     }
 
-    fn get_timeout(&self) -> Result<Option<u64>, QueryPlannerError> {
-        Ok(Some(0))
-    }
-
-    fn update_metadata(&mut self, _schema: String, _timeout: u64) -> Result<(), QueryPlannerError> {
+    fn update_metadata(&mut self, _metadata: LocalMetadata) -> Result<(), QueryPlannerError> {
         self.metadata = MetadataMock::new();
         Ok(())
     }
diff --git a/src/executor/engine.rs b/src/executor/engine.rs
index 69ff881970ba3c3a9bfac18b2880f05545c58927..c415a095daf278b5ea5df3f9eb083eb0b42ce4e6 100644
--- a/src/executor/engine.rs
+++ b/src/executor/engine.rs
@@ -45,6 +45,14 @@ pub trait Metadata {
     fn get_sharding_key_by_space(&self, space: &str) -> Result<Vec<&str>, QueryPlannerError>;
 }
 
+/// Local storage for uploading metadata.
+pub struct LocalMetadata {
+    /// Cluster schema.
+    pub schema: String,
+    /// Query execution timeout.
+    pub timeout: u64,
+}
+
 /// An execution engine trait.
 pub trait Engine {
     type Metadata;
@@ -60,23 +68,17 @@ pub trait Engine {
     /// Check if the cache is empty.
     fn is_metadata_empty(&self) -> bool;
 
-    /// Retrieve cluster schema.
-    ///
-    /// # Errors
-    /// - Failed to retrieve cluster schema.
-    fn get_schema(&self) -> Result<Option<String>, QueryPlannerError>;
-
-    /// Retrieve timeout to wait for execution completion.
+    /// Retrieve cluster metadata.
     ///
     /// # Errors
-    /// - Failed to get timeout from the configuration.
-    fn get_timeout(&self) -> Result<Option<u64>, QueryPlannerError>;
+    /// - Internal error.
+    fn get_metadata(&self) -> Result<Option<LocalMetadata>, QueryPlannerError>;
 
     /// Update cached metadata information.
     ///
     /// # Errors
     /// - Failed to update metadata information (invalid metadata).
-    fn update_metadata(&mut self, schema: String, timeout: u64) -> Result<(), QueryPlannerError>;
+    fn update_metadata(&mut self, metadata: LocalMetadata) -> Result<(), QueryPlannerError>;
 
     /// Materialize result motion node to virtual table
     ///
diff --git a/src/executor/engine/cartridge.rs b/src/executor/engine/cartridge.rs
index badfa234a5a6e67711be258bd2f075f16aba54b3..598f52422a873318a2e403c2f6b33a0ca61cf32b 100644
--- a/src/executor/engine/cartridge.rs
+++ b/src/executor/engine/cartridge.rs
@@ -10,7 +10,7 @@ use crate::errors::QueryPlannerError;
 use crate::executor::bucket::Buckets;
 use crate::executor::engine::cartridge::cache::ClusterAppConfig;
 use crate::executor::engine::cartridge::hash::str_to_bucket_id;
-use crate::executor::engine::Engine;
+use crate::executor::engine::{Engine, LocalMetadata};
 use crate::executor::ir::ExecutionPlan;
 use crate::executor::result::BoxExecuteFormat;
 use crate::executor::vtable::VirtualTable;
@@ -44,13 +44,12 @@ impl Engine for Runtime {
         self.metadata.is_empty()
     }
 
-    fn get_schema(&self) -> Result<Option<String>, QueryPlannerError> {
+    fn get_metadata(&self) -> Result<Option<LocalMetadata>, QueryPlannerError> {
         if self.metadata.is_empty() {
             let lua = tarantool::lua_state();
 
             let get_schema: LuaFunction<_> = lua.eval("return get_schema;").unwrap();
-
-            let res: String = match get_schema.call() {
+            let schema: String = match get_schema.call() {
                 Ok(res) => res,
                 Err(e) => {
                     say(
@@ -63,17 +62,9 @@ impl Engine for Runtime {
                     return Err(QueryPlannerError::LuaError(format!("Lua error: {:?}", e)));
                 }
             };
-            return Ok(Some(res));
-        }
-        Ok(None)
-    }
 
-    fn get_timeout(&self) -> Result<Option<u64>, QueryPlannerError> {
-        if self.metadata.is_empty() {
-            let lua = tarantool::lua_state();
-            let timeout: LuaFunction<_> = lua.eval("return get_waiting_timeout;").unwrap();
-
-            let waiting_timeout: u64 = match timeout.call() {
+            let waiting_timeout: LuaFunction<_> = lua.eval("return get_waiting_timeout;").unwrap();
+            let timeout: u64 = match waiting_timeout.call() {
                 Ok(res) => res,
                 Err(e) => {
                     say(
@@ -86,14 +77,16 @@ impl Engine for Runtime {
                     return Err(QueryPlannerError::LuaError(format!("Lua error: {:?}", e)));
                 }
             };
-            return Ok(Some(waiting_timeout));
+
+            let metadata = LocalMetadata { schema, timeout };
+            return Ok(Some(metadata));
         }
         Ok(None)
     }
 
-    fn update_metadata(&mut self, schema: String, timeout: u64) -> Result<(), QueryPlannerError> {
-        self.metadata.load_schema(&schema)?;
-        self.metadata.set_exec_waiting_timeout(timeout);
+    fn update_metadata(&mut self, metadata: LocalMetadata) -> Result<(), QueryPlannerError> {
+        self.metadata.load_schema(&metadata.schema)?;
+        self.metadata.set_exec_waiting_timeout(metadata.timeout);
         Ok(())
     }
 
diff --git a/src/executor/engine/mock.rs b/src/executor/engine/mock.rs
index 7578566e08d459884e52f92c1e2eba78b33fca94..b1d8e24adf459b1ce0a1da5d96731dd6f536807d 100644
--- a/src/executor/engine/mock.rs
+++ b/src/executor/engine/mock.rs
@@ -4,7 +4,7 @@ use std::collections::HashMap;
 use crate::errors::QueryPlannerError;
 use crate::executor::bucket::Buckets;
 use crate::executor::engine::cartridge::hash::str_to_bucket_id;
-use crate::executor::engine::Engine;
+use crate::executor::engine::{Engine, LocalMetadata};
 use crate::executor::ir::ExecutionPlan;
 use crate::executor::result::{BoxExecuteFormat, Value};
 use crate::executor::vtable::VirtualTable;
@@ -166,15 +166,15 @@ impl Engine for EngineMock {
         self.metadata.tables.is_empty()
     }
 
-    fn get_schema(&self) -> Result<Option<String>, QueryPlannerError> {
-        Ok(Some("".to_string()))
+    fn get_metadata(&self) -> Result<Option<LocalMetadata>, QueryPlannerError> {
+        let metadata = LocalMetadata {
+            schema: "".into(),
+            timeout: 0,
+        };
+        Ok(Some(metadata))
     }
 
-    fn get_timeout(&self) -> Result<Option<u64>, QueryPlannerError> {
-        Ok(Some(0))
-    }
-
-    fn update_metadata(&mut self, _schema: String, _timeout: u64) -> Result<(), QueryPlannerError> {
+    fn update_metadata(&mut self, _metadata: LocalMetadata) -> Result<(), QueryPlannerError> {
         self.metadata = MetadataMock::new();
         Ok(())
     }
diff --git a/src/parser.rs b/src/parser.rs
index 944599e71625e8cb27476c0c3a25e7242ec4eff2..a498fa32feb6eeab9795da1e6e77fcc109385166 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -9,7 +9,7 @@ use tarantool::tuple::{AsTuple, FunctionArgs, FunctionCtx, Tuple};
 
 use crate::errors::QueryPlannerError;
 use crate::executor::engine::cartridge::load_extra_function;
-use crate::executor::engine::{cartridge, Engine};
+use crate::executor::engine::{cartridge, Engine, LocalMetadata};
 use crate::executor::Query;
 
 use self::extargs::{BucketCalcArgs, BucketCalcArgsDict};
@@ -146,17 +146,15 @@ pub extern "C" fn execute_query(ctx: FunctionCtx, args: FunctionArgs) -> c_int {
 fn load_metadata() -> c_int {
     // Tarantool can yield in the middle of a current closure,
     // so we can hold only an immutable reference to the engine.
-    let mut schema: Option<String> = None;
-    let mut timeout: Option<u64> = None;
+    let mut metadata: Option<LocalMetadata> = None;
     QUERY_ENGINE.with(|e| {
         let engine = &*e.borrow();
-        match (engine.get_schema(), engine.get_timeout()) {
-            (Ok(s), Ok(t)) => {
-                schema = s;
-                timeout = t;
+        match engine.get_metadata() {
+            Ok(meta) => {
+                metadata = meta;
                 0
             }
-            (Err(e), _) | (_, Err(e)) => {
+            Err(e) => {
                 return tarantool::set_error!(TarantoolErrorCode::ProcC, "{}", e.to_string());
             }
         }
@@ -172,10 +170,10 @@ fn load_metadata() -> c_int {
     // Tarantool never yields here, so it is possible to hold
     // a mutable reference to the engine.
     if is_metadata_empty {
-        if let (Some(schema), Some(timeout)) = (schema, timeout) {
+        if let Some(metadata) = metadata {
             QUERY_ENGINE.with(|e| {
                 let engine = &mut *e.borrow_mut();
-                if let Err(e) = engine.update_metadata(schema, timeout) {
+                if let Err(e) = engine.update_metadata(metadata) {
                     return tarantool::set_error!(TarantoolErrorCode::ProcC, "{}", e.to_string());
                 }
                 0