From 2c5217ff9f62335ae2c2606fa5b0f2f606564a05 Mon Sep 17 00:00:00 2001
From: Denis Smirnov <sd@picodata.io>
Date: Thu, 13 Jun 2024 20:37:56 +0700
Subject: [PATCH] feat: move to rust API for local SQL

---
 Cargo.lock                                    | 616 ++++++++++--------
 sbroad-benches/Cargo.toml                     |  15 +-
 sbroad-cartridge/Cargo.toml                   |   6 +-
 sbroad-cartridge/src/cartridge/storage.rs     |  21 +-
 sbroad-cartridge/src/storage.lua              |   1 -
 sbroad-core/Cargo.toml                        |  16 +-
 sbroad-core/src/backend/sql/ir.rs             |   8 +
 sbroad-core/src/core-router.lua               |  26 +-
 sbroad-core/src/core-storage.lua              |  69 --
 sbroad-core/src/executor/engine.rs            |   8 +-
 sbroad-core/src/executor/engine/helpers.rs    | 485 +++++++-------
 .../src/executor/engine/helpers/storage.rs    | 217 ++++--
 .../executor/engine/helpers/storage/meta.rs   |  42 --
 sbroad-core/src/executor/lru.rs               |  10 +-
 sbroad-core/src/executor/result.rs            |  25 +-
 sbroad-core/src/executor/vtable.rs            |   2 +-
 sbroad-core/src/ir.rs                         |  26 +
 17 files changed, 890 insertions(+), 703 deletions(-)
 delete mode 100644 sbroad-core/src/core-storage.lua
 delete mode 100644 sbroad-core/src/executor/engine/helpers/storage/meta.rs

diff --git a/Cargo.lock b/Cargo.lock
index 4efe5f6a5..63193dd16 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "ahash"
-version = "0.7.6"
+version = "0.7.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
 dependencies = [
  "getrandom",
  "once_cell",
@@ -15,18 +15,18 @@ dependencies = [
 
 [[package]]
 name = "aho-corasick"
-version = "1.0.2"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.81"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
 
 [[package]]
 name = "arrayref"
@@ -42,13 +42,13 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
 
 [[package]]
 name = "async-trait"
-version = "0.1.71"
+version = "0.1.80"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf"
+checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
- "syn 2.0.55",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
+ "syn 2.0.66",
 ]
 
 [[package]]
@@ -64,9 +64,9 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "1.1.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
 
 [[package]]
 name = "base64"
@@ -97,16 +97,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "blake3"
-version = "1.4.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "729b71f35bd3fa1a4c86b85d32c8b9069ea7fe14f7a53cfabb65f62d4265b888"
+checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52"
 dependencies = [
  "arrayref",
  "arrayvec",
  "cc",
  "cfg-if",
  "constant_time_eq",
- "digest 0.10.7",
 ]
 
 [[package]]
@@ -129,15 +128,15 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.13.0"
+version = "3.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "byteorder"
-version = "1.4.3"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cast"
@@ -147,9 +146,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
 [[package]]
 name = "cc"
-version = "1.0.79"
+version = "1.0.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
 
 [[package]]
 name = "cfg-if"
@@ -170,15 +169,15 @@ dependencies = [
 
 [[package]]
 name = "constant_time_eq"
-version = "0.2.6"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6"
+checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.9"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
+checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
 dependencies = [
  "libc",
 ]
@@ -221,47 +220,47 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.8"
+version = "0.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
+checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
 dependencies = [
- "cfg-if",
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-deque"
-version = "0.8.3"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
+checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
 dependencies = [
- "cfg-if",
  "crossbeam-epoch",
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.15"
+version = "0.9.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
 dependencies = [
- "autocfg",
- "cfg-if",
  "crossbeam-utils",
- "memoffset",
- "scopeguard",
 ]
 
 [[package]]
-name = "crossbeam-utils"
-version = "0.8.16"
+name = "crossbeam-queue"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
+checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
 dependencies = [
- "cfg-if",
+ "crossbeam-utils",
 ]
 
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
 [[package]]
 name = "crypto-common"
 version = "0.1.6"
@@ -274,9 +273,9 @@ dependencies = [
 
 [[package]]
 name = "csv"
-version = "1.2.2"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086"
+checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
 dependencies = [
  "csv-core",
  "itoa",
@@ -286,23 +285,13 @@ dependencies = [
 
 [[package]]
 name = "csv-core"
-version = "0.1.10"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
+checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
 dependencies = [
  "memchr",
 ]
 
-[[package]]
-name = "ctor"
-version = "0.1.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
-dependencies = [
- "quote 1.0.35",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "darling"
 version = "0.14.4"
@@ -321,8 +310,8 @@ checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
 dependencies = [
  "fnv",
  "ident_case",
- "proc-macro2 1.0.79",
- "quote 1.0.35",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
  "strsim",
  "syn 1.0.109",
 ]
@@ -334,26 +323,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
 dependencies = [
  "darling_core",
- "quote 1.0.35",
+ "quote 1.0.36",
  "syn 1.0.109",
 ]
 
 [[package]]
 name = "dec"
-version = "0.4.8"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cbdeb628adfc427c3f926528cf76daf4418453e103151739d48f79b8182cb41f"
+checksum = "a8aed775093963adbd1821f88d7934c839330b05f41c9877bdbc7b385e498b9c"
 dependencies = [
  "decnumber-sys",
  "libc",
+ "paste",
  "static_assertions",
 ]
 
 [[package]]
 name = "decnumber-sys"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76a99b958f19724bc0a2202086d135c2e7ed098e95cdae778546e965648fa47b"
+checksum = "23b4bc33814bd5bcd46dd13f9471a29ab1a22c4701ae0c4a182e45e8336d1a5b"
 dependencies = [
  "cc",
  "libc",
@@ -382,7 +372,6 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 dependencies = [
  "block-buffer 0.10.4",
  "crypto-common",
- "subtle",
 ]
 
 [[package]]
@@ -410,9 +399,9 @@ dependencies = [
 
 [[package]]
 name = "either"
-version = "1.8.1"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
+checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
 
 [[package]]
 name = "fnv"
@@ -422,9 +411,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
 name = "futures"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -437,9 +426,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -447,15 +436,15 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -464,38 +453,38 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
- "syn 2.0.55",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
+ "syn 2.0.66",
 ]
 
 [[package]]
 name = "futures-sink"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
 
 [[package]]
 name = "futures-task"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
 
 [[package]]
 name = "futures-util"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -521,9 +510,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.10"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
@@ -532,9 +521,9 @@ dependencies = [
 
 [[package]]
 name = "half"
-version = "1.8.2"
+version = "1.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
+checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
 
 [[package]]
 name = "hash32"
@@ -562,9 +551,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.2"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
 
 [[package]]
 name = "ident_case"
@@ -599,15 +588,15 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "1.0.8"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "js-sys"
-version = "0.3.64"
+version = "0.3.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -620,9 +609,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.147"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "linked-hash-map"
@@ -632,50 +621,51 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
 
 [[package]]
 name = "linkme"
-version = "0.2.10"
+version = "0.3.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edd4ad156b9934dc21cad96fd17278a7cb6f30a5657a9d976cd7b71d6d49c02c"
+checksum = "ccb76662d78edc9f9bf56360d6919bdacc8b7761227727e5082f128eeb90bbf5"
 dependencies = [
  "linkme-impl",
 ]
 
 [[package]]
 name = "linkme-impl"
-version = "0.2.10"
+version = "0.3.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73fd9dc7072de7168cbdaba9125e8f742cd3a965aa12bde994b4611a174488d8"
+checksum = "f8dccda732e04fa3baf2e17cf835bfe2601c7c2edafd64417c627dabae3a8cda"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
- "syn 1.0.109",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
+ "syn 2.0.66",
 ]
 
 [[package]]
 name = "log"
-version = "0.4.19"
+version = "0.4.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
 
 [[package]]
-name = "memchr"
-version = "2.5.0"
+name = "md-5"
+version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
+dependencies = [
+ "cfg-if",
+ "digest 0.10.7",
+]
 
 [[package]]
-name = "memoffset"
-version = "0.9.0"
+name = "memchr"
+version = "2.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
-dependencies = [
- "autocfg",
-]
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
 
 [[package]]
 name = "num-traits"
-version = "0.2.15"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
 dependencies = [
  "autocfg",
 ]
@@ -686,15 +676,15 @@ version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
 dependencies = [
- "hermit-abi 0.3.2",
+ "hermit-abi 0.3.9",
  "libc",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.18.0"
+version = "1.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
 name = "oorandom"
@@ -704,9 +694,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
 
 [[package]]
 name = "opaque-debug"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
 
 [[package]]
 name = "opentelemetry"
@@ -759,42 +749,34 @@ dependencies = [
  "num-traits",
 ]
 
-[[package]]
-name = "output_vt100"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
-dependencies = [
- "winapi",
-]
-
 [[package]]
 name = "paste"
-version = "1.0.13"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pest"
-version = "2.7.0"
+version = "2.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9"
+checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8"
 dependencies = [
+ "memchr",
  "thiserror",
  "ucd-trie",
 ]
 
 [[package]]
 name = "pest_derive"
-version = "2.7.0"
+version = "2.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b"
+checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459"
 dependencies = [
  "pest",
  "pest_generator",
@@ -802,22 +784,22 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.7.0"
+version = "2.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190"
+checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687"
 dependencies = [
  "pest",
  "pest_meta",
- "proc-macro2 1.0.79",
- "quote 1.0.35",
- "syn 2.0.55",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
+ "syn 2.0.66",
 ]
 
 [[package]]
 name = "pest_meta"
-version = "2.7.0"
+version = "2.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0"
+checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd"
 dependencies = [
  "once_cell",
  "pest",
@@ -826,29 +808,29 @@ dependencies = [
 
 [[package]]
 name = "pin-project"
-version = "1.1.2"
+version = "1.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842"
+checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
 dependencies = [
  "pin-project-internal",
 ]
 
 [[package]]
 name = "pin-project-internal"
-version = "1.1.2"
+version = "1.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c"
+checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
- "syn 2.0.55",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
+ "syn 2.0.66",
 ]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.10"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 
 [[package]]
 name = "pin-utils"
@@ -858,9 +840,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
 name = "plotters"
-version = "0.3.5"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
+checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3"
 dependencies = [
  "num-traits",
  "plotters-backend",
@@ -871,15 +853,15 @@ dependencies = [
 
 [[package]]
 name = "plotters-backend"
-version = "0.3.5"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
+checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7"
 
 [[package]]
 name = "plotters-svg"
-version = "0.3.5"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
+checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705"
 dependencies = [
  "plotters-backend",
 ]
@@ -892,13 +874,11 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "pretty_assertions"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
+checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
 dependencies = [
- "ctor",
  "diff",
- "output_vt100",
  "yansi",
 ]
 
@@ -909,8 +889,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
 dependencies = [
  "proc-macro-error-attr",
- "proc-macro2 1.0.79",
- "quote 1.0.35",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
  "syn 1.0.109",
  "version_check",
 ]
@@ -921,8 +901,8 @@ version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
  "version_check",
 ]
 
@@ -937,9 +917,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.79"
+version = "1.0.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
+checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
 dependencies = [
  "unicode-ident",
 ]
@@ -955,11 +935,11 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.35"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 dependencies = [
- "proc-macro2 1.0.79",
+ "proc-macro2 1.0.85",
 ]
 
 [[package]]
@@ -994,9 +974,9 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.7.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
 dependencies = [
  "either",
  "rayon-core",
@@ -1004,14 +984,12 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.11.0"
+version = "1.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
 dependencies = [
- "crossbeam-channel",
  "crossbeam-deque",
  "crossbeam-utils",
- "num_cpus",
 ]
 
 [[package]]
@@ -1022,9 +1000,9 @@ checksum = "369e86b80fa7dc8c561dd9613a5bf25c59d2d3073cd66c47fd9e39802f0ecb58"
 
 [[package]]
 name = "regex"
-version = "1.9.0"
+version = "1.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484"
+checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1034,9 +1012,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.3.0"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1045,9 +1023,9 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.7.3"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846"
+checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
 
 [[package]]
 name = "rmp"
@@ -1073,9 +1051,9 @@ dependencies = [
 
 [[package]]
 name = "rmp-serde"
-version = "1.1.0"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25786b0d276110195fa3d6f3f31299900cf71dfbd6c28450f3f58a0e7f7a347e"
+checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a"
 dependencies = [
  "byteorder",
  "rmp",
@@ -1096,9 +1074,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.14"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "same-file"
@@ -1142,7 +1120,7 @@ dependencies = [
  "serde_yaml",
  "smol_str",
  "tarantool",
- "uuid 1.4.0",
+ "uuid 1.8.0",
  "yaml-rust",
 ]
 
@@ -1163,44 +1141,39 @@ dependencies = [
  "pretty_assertions",
  "rand",
  "rmp",
- "rmp-serde 1.1.0",
+ "rmp-serde 1.1.2",
+ "rmpv",
  "sbroad-proc",
  "serde",
  "serde_yaml",
  "smol_str",
  "tarantool",
  "time",
- "uuid 1.4.0",
+ "uuid 1.8.0",
 ]
 
 [[package]]
 name = "sbroad-proc"
 version = "0.1.0"
 dependencies = [
- "quote 1.0.35",
+ "quote 1.0.36",
  "syn 1.0.109",
 ]
 
-[[package]]
-name = "scopeguard"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
-
 [[package]]
 name = "serde"
-version = "1.0.197"
+version = "1.0.203"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
+checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_bytes"
-version = "0.11.11"
+version = "0.11.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a16be4fe5320ade08736447e3198294a5ea9a6d44dde6f35f0a5e06859c427a"
+checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734"
 dependencies = [
  "serde",
 ]
@@ -1217,20 +1190,20 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.197"
+version = "1.0.203"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
+checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
- "syn 2.0.55",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
+ "syn 2.0.66",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.100"
+version = "1.0.117"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c"
+checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
 dependencies = [
  "itoa",
  "ryu",
@@ -1264,9 +1237,9 @@ dependencies = [
 
 [[package]]
 name = "sha2"
-version = "0.10.7"
+version = "0.10.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
 dependencies = [
  "cfg-if",
  "cpufeatures",
@@ -1275,18 +1248,18 @@ dependencies = [
 
 [[package]]
 name = "slab"
-version = "0.4.8"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "smol_str"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49"
+checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead"
 dependencies = [
  "serde",
 ]
@@ -1303,12 +1276,6 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
-[[package]]
-name = "subtle"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
-
 [[package]]
 name = "syn"
 version = "0.15.44"
@@ -1326,40 +1293,42 @@ version = "1.0.109"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
  "unicode-ident",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.55"
+version = "2.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
  "unicode-ident",
 ]
 
 [[package]]
 name = "tarantool"
 version = "5.0.0"
-source = "git+https://git.picodata.io/picodata/picodata/tarantool-module.git#dbebcc0aace0264b7ba9569e9a8a672b972c95ea"
+source = "git+https://git.picodata.io/picodata/picodata/tarantool-module.git#d758e775797267a9d12e0e2afef73244a9aeaf5e"
 dependencies = [
  "async-trait",
  "base64",
  "bitflags",
+ "crossbeam-queue",
  "dec",
  "dlopen",
  "futures",
  "libc",
  "linkme",
  "log",
+ "md-5",
  "once_cell",
  "refpool",
  "rmp",
- "rmp-serde 1.1.0",
+ "rmp-serde 1.1.2",
  "rmpv",
  "serde",
  "serde_bytes",
@@ -1375,13 +1344,13 @@ dependencies = [
 
 [[package]]
 name = "tarantool-proc"
-version = "3.0.0"
-source = "git+https://git.picodata.io/picodata/picodata/tarantool-module.git#dbebcc0aace0264b7ba9569e9a8a672b972c95ea"
+version = "3.1.0"
+source = "git+https://git.picodata.io/picodata/picodata/tarantool-module.git#d758e775797267a9d12e0e2afef73244a9aeaf5e"
 dependencies = [
  "darling",
  "proc-macro-error",
- "proc-macro2 1.0.79",
- "quote 1.0.35",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
  "syn 1.0.109",
 ]
 
@@ -1396,22 +1365,22 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.41"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802"
+checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.41"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59"
+checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
- "syn 2.0.55",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
+ "syn 2.0.66",
 ]
 
 [[package]]
@@ -1476,7 +1445,7 @@ dependencies = [
 [[package]]
 name = "tlua"
 version = "3.1.0"
-source = "git+https://git.picodata.io/picodata/picodata/tarantool-module.git#dbebcc0aace0264b7ba9569e9a8a672b972c95ea"
+source = "git+https://git.picodata.io/picodata/picodata/tarantool-module.git#d758e775797267a9d12e0e2afef73244a9aeaf5e"
 dependencies = [
  "libc",
  "serde",
@@ -1487,36 +1456,36 @@ dependencies = [
 [[package]]
 name = "tlua-derive"
 version = "0.2.0"
-source = "git+https://git.picodata.io/picodata/picodata/tarantool-module.git#dbebcc0aace0264b7ba9569e9a8a672b972c95ea"
+source = "git+https://git.picodata.io/picodata/picodata/tarantool-module.git#d758e775797267a9d12e0e2afef73244a9aeaf5e"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
  "syn 1.0.109",
 ]
 
 [[package]]
 name = "typenum"
-version = "1.16.0"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
 name = "ucd-trie"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
+checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.10"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unicode-width"
-version = "0.1.10"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
 
 [[package]]
 name = "unicode-xid"
@@ -1532,9 +1501,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
 
 [[package]]
 name = "uuid"
-version = "1.4.0"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be"
+checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
 dependencies = [
  "getrandom",
  "rand",
@@ -1543,13 +1512,13 @@ dependencies = [
 
 [[package]]
 name = "uuid-macro-internal"
-version = "1.4.0"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8614dda80b9075fbca36bc31b58d1447715b1236af98dee21db521c47a0cc2c0"
+checksum = "9881bea7cbe687e36c9ab3b778c36cd0487402e270304e8b1296d5085303c1a2"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
- "syn 2.0.55",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
+ "syn 2.0.66",
 ]
 
 [[package]]
@@ -1566,9 +1535,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "walkdir"
-version = "2.3.3"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
 dependencies = [
  "same-file",
  "winapi-util",
@@ -1582,9 +1551,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.87"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -1592,53 +1561,53 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.87"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
 dependencies = [
  "bumpalo",
  "log",
  "once_cell",
- "proc-macro2 1.0.79",
- "quote 1.0.35",
- "syn 2.0.55",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
+ "syn 2.0.66",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.87"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
 dependencies = [
- "quote 1.0.35",
+ "quote 1.0.36",
  "wasm-bindgen-macro-support",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.87"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
 dependencies = [
- "proc-macro2 1.0.79",
- "quote 1.0.35",
- "syn 2.0.55",
+ "proc-macro2 1.0.85",
+ "quote 1.0.36",
+ "syn 2.0.66",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.87"
+version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
 
 [[package]]
 name = "web-sys"
-version = "0.3.64"
+version = "0.3.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
+checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -1662,11 +1631,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.5"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
 dependencies = [
- "winapi",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1675,6 +1644,79 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+
 [[package]]
 name = "yaml-rust"
 version = "0.4.5"
diff --git a/sbroad-benches/Cargo.toml b/sbroad-benches/Cargo.toml
index 110def286..75479edf0 100644
--- a/sbroad-benches/Cargo.toml
+++ b/sbroad-benches/Cargo.toml
@@ -11,14 +11,23 @@ edition = "2021"
 
 [dependencies]
 sbroad-core = { path = "../sbroad-core", version = "0.1", features = ["mock"] }
-tarantool = { git = "https://git.picodata.io/picodata/picodata/tarantool-module.git" }
 pest = "2.0"
 pest_derive = "2.0"
-bincode = "1.3.3"
+bincode = "1.3"
+
+[dependencies.tarantool]
+git = "https://git.picodata.io/picodata/picodata/tarantool-module.git"
+version = ">=4.0"
+features = ["picodata"]
 
 [dev-dependencies]
 criterion = "0.3"
-rand = "0.8.5"
+rand = "0.8"
+
+[dev-dependencies.tarantool]
+git = "https://git.picodata.io/picodata/picodata/tarantool-module.git"
+version = ">=4.0"
+features = ["picodata", "standalone_decimal"]
 
 [[bench]]
 name = "parse"
diff --git a/sbroad-cartridge/Cargo.toml b/sbroad-cartridge/Cargo.toml
index efeb12c65..5f39a1ffb 100644
--- a/sbroad-cartridge/Cargo.toml
+++ b/sbroad-cartridge/Cargo.toml
@@ -14,7 +14,6 @@ base64ct = { version = "1.5", features = ["alloc"] }
 bincode = "1.3"
 blake3 = "1.3"
 sbroad-core = { path = "../sbroad-core", version = "0.1" }
-tarantool = { git = "https://git.picodata.io/picodata/picodata/tarantool-module.git" }
 sbroad-proc = { path = "../sbroad-proc", version = "0.1" }
 serde = { version = "1.0", features = ["derive", "rc"] }
 serde_yaml = "0.8"
@@ -28,6 +27,11 @@ yaml-rust = "0.4"
 anyhow = "1"
 smol_str = "0.2.1"
 
+[dependencies.tarantool]
+git = "https://git.picodata.io/picodata/picodata/tarantool-module.git"
+version = ">=4.0"
+features = ["picodata"]
+
 [dev-dependencies]
 pretty_assertions = "1.3"
 
diff --git a/sbroad-cartridge/src/cartridge/storage.rs b/sbroad-cartridge/src/cartridge/storage.rs
index da2b159f2..90d5a45f8 100644
--- a/sbroad-cartridge/src/cartridge/storage.rs
+++ b/sbroad-cartridge/src/cartridge/storage.rs
@@ -2,9 +2,9 @@ use crate::cartridge::bucket_count;
 use crate::cartridge::config::StorageConfiguration;
 use sbroad::errors::{Entity, SbroadError};
 use sbroad::executor::bucket::Buckets;
-use sbroad::executor::engine::helpers::storage::runtime::unprepare;
-use sbroad::executor::engine::helpers::storage::PreparedStmt;
+use sbroad::executor::engine::helpers::storage::unprepare;
 use sbroad::executor::engine::helpers::vshard::get_random_bucket;
+use sbroad::executor::engine::helpers::{read_or_prepare, EncodedQueryInfo};
 use sbroad::executor::engine::{helpers, StorageCache};
 use sbroad::executor::engine::{QueryCache, Vshard};
 use sbroad::executor::hash::bucket_id_by_tuple;
@@ -20,6 +20,7 @@ use std::any::Any;
 
 use std::fmt::Display;
 use tarantool::fiber::Mutex;
+use tarantool::sql::Statement;
 use tarantool::tlua::LuaFunction;
 
 use super::ConfigurationProvider;
@@ -31,23 +32,20 @@ pub struct StorageRuntime {
     cache: Mutex<CartridgeCache>,
 }
 
-pub struct CartridgeCache(LRUCache<SmolStr, (PreparedStmt, Vec<NodeId>)>);
+pub struct CartridgeCache(LRUCache<SmolStr, (Statement, Vec<NodeId>)>);
 
 impl StorageCache for CartridgeCache {
     fn put(
         &mut self,
         plan_id: SmolStr,
-        stmt: PreparedStmt,
+        stmt: Statement,
         _: &SchemaInfo,
         table_ids: Vec<NodeId>,
     ) -> Result<(), SbroadError> {
         self.0.put(plan_id, (stmt, table_ids))
     }
 
-    fn get(
-        &mut self,
-        plan_id: &SmolStr,
-    ) -> Result<Option<(&PreparedStmt, &[NodeId])>, SbroadError> {
+    fn get(&mut self, plan_id: &SmolStr) -> Result<Option<(&Statement, &[NodeId])>, SbroadError> {
         let Some((stmt, table_ids)) = self.0.get(plan_id)? else {
             return Ok(None);
         };
@@ -206,7 +204,7 @@ impl StorageRuntime {
     /// # Errors
     /// - Failed to initialize the LRU cache.
     pub fn new() -> Result<Self, SbroadError> {
-        let cache: LRUCache<SmolStr, (PreparedStmt, Vec<NodeId>)> =
+        let cache: LRUCache<SmolStr, (Statement, Vec<NodeId>)> =
             LRUCache::new(DEFAULT_CAPACITY, Some(Box::new(unprepare)))?;
         let result = StorageRuntime {
             metadata: Mutex::new(StorageConfiguration::new()),
@@ -229,7 +227,10 @@ impl StorageRuntime {
     ) -> Result<Box<dyn Any>, SbroadError> {
         match required.query_type {
             QueryType::DML => helpers::execute_dml(self, required, raw_optional),
-            QueryType::DQL => helpers::execute_dql_with_raw_optional(self, required, raw_optional),
+            QueryType::DQL => {
+                let mut info = EncodedQueryInfo::new(std::mem::take(raw_optional), required);
+                read_or_prepare(self, &mut info)
+            }
         }
     }
 }
diff --git a/sbroad-cartridge/src/storage.lua b/sbroad-cartridge/src/storage.lua
index 0f4629180..3a432adf5 100644
--- a/sbroad-cartridge/src/storage.lua
+++ b/sbroad-cartridge/src/storage.lua
@@ -1,5 +1,4 @@
 require('strict').on()
-require('sbroad.core-storage')
 
 local cartridge = require('cartridge')
 local rust = require("sbroad.rust")
diff --git a/sbroad-core/Cargo.toml b/sbroad-core/Cargo.toml
index 130169505..1e7847507 100644
--- a/sbroad-core/Cargo.toml
+++ b/sbroad-core/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-lazy_static = "1.4.0"
+lazy_static = "1.4"
 ahash = "0.7"
 base64ct = { version = "1.5", features = ["alloc"] }
 bincode = "1.3"
@@ -23,17 +23,27 @@ pest_derive = "2.0"
 rand = "0.8"
 rmp = "0.8"
 rmp-serde = "1.0"
+rmpv = "1.0"
 sbroad-proc = { path = "../sbroad-proc", version = "0.1" }
 serde = { version = "1.0", features = ["derive", "rc"] }
 serde_yaml = "0.8"
-tarantool = { git = "https://git.picodata.io/picodata/picodata/tarantool-module.git" }
 uuid = { version = "1.1", features = ["v4", "fast-rng", "macro-diagnostics"] }
-smol_str = { version = "0.2.1", features = ["serde"] }
+smol_str = { version = "0.2", features = ["serde"] }
 time = { version = ">=0.3.0, <0.3.18", features = ["formatting"] }
 
+[dependencies.tarantool]
+git = "https://git.picodata.io/picodata/picodata/tarantool-module.git"
+version = ">=4.0"
+features = ["picodata"]
+
 [dev-dependencies]
 pretty_assertions = "1.3"
 
+[dev-dependencies.tarantool]
+git = "https://git.picodata.io/picodata/picodata/tarantool-module.git"
+version = ">=4.0"
+features = ["picodata", "standalone_decimal"]
+
 [lib]
 name = "sbroad"
 crate-type = ["cdylib", "rlib"]
diff --git a/sbroad-core/src/backend/sql/ir.rs b/sbroad-core/src/backend/sql/ir.rs
index 35ade444b..bf5c7082b 100644
--- a/sbroad-core/src/backend/sql/ir.rs
+++ b/sbroad-core/src/backend/sql/ir.rs
@@ -28,6 +28,14 @@ pub struct PatternWithParams {
     // Name of the tracer to use
     pub tracer: Option<String>,
 }
+
+impl PatternWithParams {
+    #[must_use]
+    pub fn into_parts(self) -> (String, Vec<Value>) {
+        (self.pattern, self.params)
+    }
+}
+
 impl PartialEq for PatternWithParams {
     fn eq(&self, other: &Self) -> bool {
         self.pattern == other.pattern && self.params == other.params
diff --git a/sbroad-core/src/core-router.lua b/sbroad-core/src/core-router.lua
index 9687f4a56..a821f0ba1 100644
--- a/sbroad-core/src/core-router.lua
+++ b/sbroad-core/src/core-router.lua
@@ -164,6 +164,11 @@ local function multi_storage_dql(uuid_to_args, func, vtable_max_rows, opts)
             local data = res[1]
             if result == nil then
                 result = data
+                if vtable_max_rows ~= 0 and vtable_max_rows < #result.rows then
+                    err = helper.vtable_limit_exceeded(vtable_max_rows, #result.rows)
+                    err_uuid = uuid
+                    goto fail
+                end
             else
                 local new_vt_rows = #data.rows + #result.rows
                 if vtable_max_rows ~= 0 and vtable_max_rows < new_vt_rows then
@@ -243,14 +248,21 @@ _G.dql_on_some = function(uuid_to_args, is_readonly, waiting_timeout, vtable_max
             error(err)
         end
         future:wait_result(waiting_timeout)
-        -- vtable_max_rows limit was checked on
-        -- storage. No need to check it here.
         local res, err = future:result()
         if err ~= nil then
             error(err)
         end
-        -- TODO: explain where this `[1][1]` comes from
+
+        -- proc_sql_execute returns [{rows_count = ..}] tuple.
+        -- But this rust function is wrapped with proc macros that
+        -- add an additional layer of array (see ReturnMsgpack).
         result = helper.unwrap_execute_result(res[1][1])
+
+        -- Check the number of rows in the virtual table.
+        if vtable_max_rows ~= 0 and vtable_max_rows < #result.rows then
+            err = helper.vtable_limit_exceeded(vtable_max_rows, #result.rows)
+            error(err)
+        end
     else
         local err, err_uuid
         local opts = { timeout = waiting_timeout }
@@ -328,7 +340,9 @@ _G.dml_on_some = function(tbl_rs_ir, is_readonly, waiting_timeout)
             error(err)
         end
 
-        -- TODO: explain where this `[1][1]` comes from
+        -- proc_sql_execute returns [{rows_count = ..}] tuple.
+        -- But this rust function is wrapped with proc macros that
+        -- add an additional layer of array (see ReturnMsgpack).
         local next_result = helper.unwrap_execute_result(res[1][1])
         if result == nil then
             result = next_result
@@ -379,7 +393,9 @@ _G.dml_on_all = function(required, optional, is_readonly, waiting_timeout)
             error(err)
         end
 
-        -- TODO: explain where this `[1][1]` comes from
+        -- proc_sql_execute returns [{rows_count = ..}] tuple.
+        -- But this rust function is wrapped with proc macros that
+        -- add an additional layer of array (see ReturnMsgpack).
         local next_result = helper.unwrap_execute_result(res[1][1])
         if result == nil then
             result = next_result
diff --git a/sbroad-core/src/core-storage.lua b/sbroad-core/src/core-storage.lua
deleted file mode 100644
index 3b6e4fae6..000000000
--- a/sbroad-core/src/core-storage.lua
+++ /dev/null
@@ -1,69 +0,0 @@
-local helper = require('sbroad.helper')
-
-_G.prepare = function(pattern)
-    local prep, err = box.prepare(pattern)
-    if err ~= nil then
-        error(string.format("Failed to prepare statement: %s. Error: %s", pattern, err), 1)
-    end
-    return prep.stmt_id
-end
-
-_G.unprepare = function(stmt_id)
-    box.unprepare(stmt_id)
-end
-
-_G.read = function(stmt_id, stmt, params, max_rows, options)
-    local res, err = box.execute(stmt_id, params, options)
-    if err ~= nil then
-        -- We don't have SQL query for retrying,
-        -- so simply return an error
-        if stmt == nil or stmt == '' then
-            error(err)
-        end
-        -- The statement can be evicted from the cache,
-        -- while we were yielding in Lua. So we execute
-        -- it without the cache.
-        res, err = box.execute(stmt, params, options)
-        if err ~= nil then
-            error(err)
-        end
-    end
-
-    if max_rows ~= 0 and #res.rows > max_rows then
-        error(helper.vtable_limit_exceeded(max_rows, #res.rows))
-    end
-
-    local result = {}
-    result.metadata = res.metadata
-    result.rows = {}
-    for _, row in ipairs(res.rows) do
-        local tuple = {}
-        for _, field in ipairs(row) do
-            table.insert(tuple, field)
-        end
-        table.insert(result.rows, tuple)
-    end
-
-    return box.tuple.new{result}
-end
-
-_G.write = function(stmt_id, stmt, params, options)
-    local res, err = box.execute(stmt_id, params, options)
-    if err ~= nil then
-        -- We don't have SQL query for retrying,
-        -- so simply return an error
-        if stmt == nil or stmt == '' then
-            error(err)
-        end
-        -- The statement can be evicted from the cache,
-        -- while we were yielding in Lua. So we execute
-        -- it without the cache.
-        res, err = box.execute(stmt, params, options)
-        if err ~= nil then
-            error(err)
-        end
-    end
-
-    return box.tuple.new{res}
-end
-
diff --git a/sbroad-core/src/executor/engine.rs b/sbroad-core/src/executor/engine.rs
index 71a11570e..1d1ef4c64 100644
--- a/sbroad-core/src/executor/engine.rs
+++ b/sbroad-core/src/executor/engine.rs
@@ -15,7 +15,6 @@ use std::sync::OnceLock;
 
 use crate::errors::SbroadError;
 use crate::executor::bucket::Buckets;
-use crate::executor::engine::helpers::storage::PreparedStmt;
 use crate::executor::ir::ExecutionPlan;
 use crate::executor::protocol::SchemaInfo;
 use crate::executor::vtable::VirtualTable;
@@ -28,6 +27,8 @@ use crate::ir::NodeId;
 use super::ir::{ConnectionType, QueryType};
 use super::protocol::Binary;
 
+use tarantool::sql::Statement;
+
 pub mod helpers;
 #[cfg(feature = "mock")]
 pub mod mock;
@@ -94,7 +95,7 @@ pub trait StorageCache {
     fn put(
         &mut self,
         plan_id: SmolStr,
-        stmt: PreparedStmt,
+        stmt: Statement,
         schema_info: &SchemaInfo,
         table_ids: Vec<NodeId>,
     ) -> Result<(), SbroadError>;
@@ -105,8 +106,7 @@ pub trait StorageCache {
     /// # Errors
     /// - failed to get schema version for some table
     #[allow(clippy::ptr_arg)]
-    fn get(&mut self, plan_id: &SmolStr)
-        -> Result<Option<(&PreparedStmt, &[NodeId])>, SbroadError>;
+    fn get(&mut self, plan_id: &SmolStr) -> Result<Option<(&Statement, &[NodeId])>, SbroadError>;
 
     /// Clears the cache.
     ///
diff --git a/sbroad-core/src/executor/engine/helpers.rs b/sbroad-core/src/executor/engine/helpers.rs
index 3bbaf5f7a..bbbb011ae 100644
--- a/sbroad-core/src/executor/engine/helpers.rs
+++ b/sbroad-core/src/executor/engine/helpers.rs
@@ -18,13 +18,14 @@ use tarantool::{
 use tarantool::{space::Space, tuple::TupleBuffer};
 
 use crate::backend::sql::space::{TableGuard, ADMIN_ID};
-use crate::executor::engine::helpers::storage::runtime::{prepare, read_prepared, read_unprepared};
+use crate::executor::engine::helpers::storage::{execute_prepared, execute_unprepared, prepare};
 use crate::executor::engine::{QueryCache, StorageCache};
 use crate::executor::protocol::{EncodedTables, SchemaInfo};
 use crate::ir::operator::ConflictStrategy;
 use crate::ir::value::{EncodedValue, LuaValue, MsgPackValue};
-use crate::ir::{ExecuteOptions, NodeId};
+use crate::ir::NodeId;
 use crate::otm::child_span;
+use crate::utils::ByteCounter;
 use crate::{
     backend::sql::{
         ir::PatternWithParams,
@@ -287,6 +288,20 @@ fn compile_optional(
     Ok((pwp, guard))
 }
 
+/// Decode dispatched optional data (execution plan, etc.) from msgpack
+/// and compile it into a pattern with parameters and temporary space map.
+///
+/// # Errors
+/// - Failed to decode or compile optional data.
+pub fn compile_encoded_optional(
+    raw_optional: &mut Vec<u8>,
+    template: &str,
+) -> Result<(PatternWithParams, Vec<TableGuard>), SbroadError> {
+    let data = std::mem::take(raw_optional);
+    let mut optional = OptionalData::try_from(EncodedOptionalData::from(data))?;
+    compile_optional(&mut optional, template)
+}
+
 /// Command to build a tuple suitable to be passed into Tarantool API functions.
 /// For more information see `TupleBuilderPattern` docs.
 #[derive(Debug)]
@@ -627,7 +642,7 @@ pub fn empty_query_result(plan: &ExecutionPlan) -> Result<Option<Box<dyn Any>>,
     match query_type {
         QueryType::DML => {
             let result = ConsumerResult::default();
-            let tuple = Tuple::new(&(result,))
+            let tuple = Tuple::new(&[result])
                 .map_err(|e| SbroadError::Invalid(Entity::Tuple, Some(format_smolstr!("{e:?}"))))?;
             Ok(Some(Box::new(tuple) as Box<dyn Any>))
         }
@@ -665,7 +680,7 @@ pub fn empty_query_result(plan: &ExecutionPlan) -> Result<Option<Box<dyn Any>>,
                 ..Default::default()
             };
 
-            let tuple = Tuple::new(&(result,))
+            let tuple = Tuple::new(&[result])
                 .map_err(|e| SbroadError::Invalid(Entity::Tuple, Some(format_smolstr!("{e:?}"))))?;
             Ok(Some(Box::new(tuple) as Box<dyn Any>))
         }
@@ -679,7 +694,7 @@ pub fn empty_query_result(plan: &ExecutionPlan) -> Result<Option<Box<dyn Any>>,
 pub fn explain_format(explain: &str) -> Result<Box<dyn Any>, SbroadError> {
     let e = explain.lines().collect::<Vec<&str>>();
 
-    match Tuple::new(&vec![e]) {
+    match Tuple::new(&[e]) {
         Ok(t) => Ok(Box::new(t)),
         Err(e) => Err(SbroadError::FailedTo(
             Action::Create,
@@ -1122,8 +1137,117 @@ fn truncate_tables(table_ids: &[NodeId], plan_id: &SmolStr) {
     .expect("failed to switch to admin user");
 }
 
+pub trait PlanInfo {
+    /// Extracts the query and the temporary tables from the plan.
+    /// Temporary tables truncate their data in destructor and act
+    /// as a guard.
+    ///
+    /// # Errors
+    /// - Failed to extract query and table guard.
+    fn extract_query_and_table_guard(
+        &mut self,
+    ) -> Result<(PatternWithParams, Vec<TableGuard>), SbroadError>;
+    fn id(&self) -> &SmolStr;
+    fn params(&self) -> &Vec<Value>;
+    fn schema_info(&self) -> &SchemaInfo;
+    fn extract_data(&mut self) -> EncodedTables;
+    fn vdbe_max_steps(&self) -> u64;
+    fn vtable_max_rows(&self) -> u64;
+}
+
+pub struct QueryInfo<'data> {
+    optional: &'data mut OptionalData,
+    required: &'data mut RequiredData,
+}
+
+impl<'data> QueryInfo<'data> {
+    pub fn new(optional: &'data mut OptionalData, required: &'data mut RequiredData) -> Self {
+        Self { optional, required }
+    }
+}
+
+impl PlanInfo for QueryInfo<'_> {
+    fn extract_query_and_table_guard(
+        &mut self,
+    ) -> Result<(PatternWithParams, Vec<TableGuard>), SbroadError> {
+        compile_optional(self.optional, &self.required.plan_id)
+    }
+
+    fn id(&self) -> &SmolStr {
+        &self.required.plan_id
+    }
+
+    fn params(&self) -> &Vec<Value> {
+        &self.required.parameters
+    }
+
+    fn schema_info(&self) -> &SchemaInfo {
+        &self.required.schema_info
+    }
+
+    fn extract_data(&mut self) -> EncodedTables {
+        std::mem::take(&mut self.required.tables)
+    }
+
+    fn vdbe_max_steps(&self) -> u64 {
+        self.required.options.execute_options.vdbe_max_steps()
+    }
+
+    fn vtable_max_rows(&self) -> u64 {
+        self.required.options.execute_options.vtable_max_rows()
+    }
+}
+
+pub struct EncodedQueryInfo<'data> {
+    raw_optional: Vec<u8>,
+    required: &'data mut RequiredData,
+}
+
+impl<'data> EncodedQueryInfo<'data> {
+    pub fn new(raw_optional: Vec<u8>, required: &'data mut RequiredData) -> Self {
+        Self {
+            raw_optional,
+            required,
+        }
+    }
+}
+
+impl PlanInfo for EncodedQueryInfo<'_> {
+    fn extract_query_and_table_guard(
+        &mut self,
+    ) -> Result<(PatternWithParams, Vec<TableGuard>), SbroadError> {
+        let data = std::mem::take(&mut self.raw_optional);
+        let mut optional = OptionalData::try_from(EncodedOptionalData::from(data))?;
+        compile_optional(&mut optional, &self.required.plan_id)
+    }
+
+    fn id(&self) -> &SmolStr {
+        &self.required.plan_id
+    }
+
+    fn params(&self) -> &Vec<Value> {
+        &self.required.parameters
+    }
+
+    fn schema_info(&self) -> &SchemaInfo {
+        &self.required.schema_info
+    }
+
+    fn extract_data(&mut self) -> EncodedTables {
+        std::mem::take(&mut self.required.tables)
+    }
+
+    fn vdbe_max_steps(&self) -> u64 {
+        self.required.options.execute_options.vdbe_max_steps()
+    }
+
+    fn vtable_max_rows(&self) -> u64 {
+        self.required.options.execute_options.vtable_max_rows()
+    }
+}
+
 /// If the statement with given `plan_id` is found in the cache,
-/// execute it and return result. Otherwise, returns `None`.
+/// execute it and return result. Otherwise, returns error.
 ///
 /// This function works only for read statements, and it is a
 /// responsibility of a caller to ensure it.
@@ -1135,15 +1259,14 @@ fn truncate_tables(table_ids: &[NodeId], plan_id: &SmolStr) {
 /// # Panics
 /// - Temporary table could not be truncated.
 /// - Temporary table could not be inserted.
-#[otm_child_span("tarantool.cache.hit.read.prepared")]
-pub fn read_from_cache<R: QueryCache, M: MutexLike<R::Cache>, 'mutex>(
-    locked_cache: &mut M::Guard<'mutex>,
+pub fn read_from_cache<R: QueryCache, M: MutexLike<R::Cache>>(
+    locked_cache: &mut M::Guard<'_>,
     params: &[Value],
     tables: &mut EncodedTables,
     plan_id: &SmolStr,
-    vtable_max_rows: u64,
-    opts: ExecuteOptions,
-) -> Result<Option<Box<dyn Any>>, SbroadError>
+    vdbe_max_steps: u64,
+    max_rows: u64,
+) -> Result<Box<dyn Any>, SbroadError>
 where
     R::Cache: StorageCache,
 {
@@ -1158,39 +1281,77 @@ where
                     break 'dql Err(e);
                 }
             }
-            let stmt_id = stmt.id().expect("failed to get statement id");
-            read_prepared(stmt_id, "", params, vtable_max_rows, opts).map(Some)
+            execute_prepared(stmt, params, vdbe_max_steps, max_rows)
         };
         truncate_tables(table_ids, plan_id);
 
         return result;
     };
-    debug!(
-        Option::from("execute plan"),
-        &format!("Failed to find a plan (id {plan_id}) in the cache."),
-    );
-    Ok(None)
+    Err(SbroadError::FailedTo(
+        Action::Find,
+        Some(Entity::Statement),
+        format_smolstr!("{plan_id} is absent in the storage cache"),
+    ))
+}
+
+#[otm_child_span("tarantool.cache.hit.read.prepared")]
+fn cache_hit<R: QueryCache, M: MutexLike<R::Cache>>(
+    locked_cache: &mut M::Guard<'_>,
+    params: &[Value],
+    tables: &mut EncodedTables,
+    plan_id: &SmolStr,
+    vdbe_max_steps: u64,
+    max_rows: u64,
+) -> Result<Box<dyn Any>, SbroadError>
+where
+    R::Cache: StorageCache,
+{
+    read_from_cache::<R, M>(
+        locked_cache,
+        params,
+        tables,
+        plan_id,
+        vdbe_max_steps,
+        max_rows,
+    )
+}
+
+#[otm_child_span("tarantool.cache.miss.read.prepared")]
+fn cache_miss<R: QueryCache, M: MutexLike<R::Cache>>(
+    locked_cache: &mut M::Guard<'_>,
+    params: &[Value],
+    tables: &mut EncodedTables,
+    plan_id: &SmolStr,
+    vdbe_max_steps: u64,
+    max_rows: u64,
+) -> Result<Box<dyn Any>, SbroadError>
+where
+    R::Cache: StorageCache,
+{
+    read_from_cache::<R, M>(
+        locked_cache,
+        params,
+        tables,
+        plan_id,
+        vdbe_max_steps,
+        max_rows,
+    )
 }
 
 /// Execute a read statement bypassing tarantool cache.
-/// Must be used only while the cache is locked.
 ///
 /// # Errors
 /// - Failed to populate temporary tables.
 /// - Failed to execute the statement.
 /// - Temporary table could not be truncated.
-#[otm_child_span("tarantool.cache.miss.read.prepared")]
-fn read_bypassing_cache<R: QueryCache, M: MutexLike<R::Cache>>(
+fn read_bypassing_cache(
     pattern: &str,
     params: &[Value],
     plan_id: &SmolStr,
     tables: &mut EncodedTables,
-    vtable_max_rows: u64,
-    opts: ExecuteOptions,
-) -> Result<Box<dyn Any>, SbroadError>
-where
-    R::Cache: StorageCache,
-{
+    vdbe_max_steps: u64,
+    max_rows: u64,
+) -> Result<Box<dyn Any>, SbroadError> {
     // Transaction rollbacks are very expensive in Tarantool, so we're going to
     // avoid transactions for DQL queries. We can achieve atomicity by truncating
     // temporary tables. Isolation is guaranteed by keeping a lock on the cache.
@@ -1201,146 +1362,82 @@ where
                 break 'dql Err(e);
             }
         }
-        read_unprepared(pattern, params, vtable_max_rows, opts)
+        execute_unprepared(pattern, params, vdbe_max_steps, max_rows)
     };
     // No need to truncate temporary tables as they would be truncated in the parent function.
     result
 }
 
-/// Tries to prepare read statement and then execute it.
-/// In case `prepare` fails, the statement will be executed anyway.
-///
-/// It is responsibility of the caller, to ensure that it is a
-/// read statement - not write.
+/// Execute a DQL statement or prepare it, put it into the cache and execute.
 ///
 /// # Errors
-/// - Failed to prepare the statement
-/// - Failed to borrow runtime's cache
-/// - Tarantool execution error
-#[allow(unused_variables)]
-pub fn prepare_and_read<R: Vshard + QueryCache, M: MutexLike<R::Cache>>(
-    locked_cache: &mut M::Guard<'_>,
-    pattern_with_params: &PatternWithParams,
-    plan_id: &SmolStr,
-    vtable_max_rows: u64,
-    opts: ExecuteOptions,
-    schema_info: &SchemaInfo,
-    tables_with_data: &mut EncodedTables,
-) -> Result<Box<dyn Any>, SbroadError>
-where
-    R::Cache: StorageCache,
-{
-    match prepare(&pattern_with_params.pattern) {
-        Ok(stmt) => {
-            let stmt_id = stmt.id()?;
-            debug!(
-                Option::from("execute plan"),
-                &format!(
-                    "Created prepared statement {} for the pattern {}",
-                    stmt_id,
-                    stmt.pattern()?
-                ),
-            );
-            let mut stmt_tables: Vec<SmolStr> = Vec::with_capacity(tables_with_data.len());
-            for node_id in tables_with_data.keys() {
-                stmt_tables.push(table_name(plan_id.as_str(), *node_id));
-            }
-            let table_ids = tables_with_data.keys().copied().collect::<Vec<NodeId>>();
-            locked_cache.put(plan_id.clone(), stmt, schema_info, table_ids)?;
-            // The statement was found in the cache, so we can execute it.
-            let Some(res) = read_from_cache::<R, M>(
-                locked_cache,
-                &pattern_with_params.params,
-                tables_with_data,
-                plan_id,
-                vtable_max_rows,
-                opts.clone(),
-            )?
-            else {
-                unreachable!(
-                    "The statement {stmt_id} was just prepared and put into the cache. SQL: {}",
-                    &pattern_with_params.pattern
-                );
-            };
-            Ok(res)
-        }
-        // Possibly the statement is correct, but doesn't fit into
-        // Tarantool's prepared statements cache (`sql_cache_size`).
-        // So we try to execute it bypassing the cache.
-        Err(e) => {
-            // We need to lock the cache though we are not going to use it. If we don't
-            // lock it, the prepared statement made from our pattern can be inserted into
-            // the cache by some other fiber because we have removed some big statements
-            // with LRU and tarantool cache has enough space to store this statement.
-            // And it can cause races in the temporary tables.
-            read_bypassing_cache::<R, R::Mutex>(
-                &pattern_with_params.pattern,
-                &pattern_with_params.params,
-                plan_id,
-                tables_with_data,
-                vtable_max_rows,
-                opts,
-            )
-        }
-    }
-}
-
-/// Execute read statement that can be cached.
-///
-/// If statement is in the runtime's cache it is executed,
-/// otherwise the optional data (plan) is compiled into
-/// the string. Then we try to prepare the statement and
-/// put it into the cache. if prepare fails, the statement
-/// is executed anyway.
-///
-/// # Note
-/// It is responsibility of the caller to check that
-/// statement can be cached or that it is a read statement.
-///
-/// # Errors
-/// - Failed to borrow runtime's cache
-/// - Tarantool execution error for given statement
-/// - Failed to compile the optional data
-/// - Failed to prepare the statement
-#[allow(unused_variables)]
-pub fn execute_dql<R: Vshard + QueryCache>(
+/// - something wrong with the statement in the cache.
+pub fn read_or_prepare<R: QueryCache>(
     runtime: &R,
-    required: &mut RequiredData,
-    optional: &mut OptionalData,
+    info: &mut impl PlanInfo,
 ) -> Result<Box<dyn Any>, SbroadError>
 where
     R::Cache: StorageCache,
 {
-    let opts = std::mem::take(&mut required.options.execute_options);
-    let mut tables = std::mem::take(&mut required.tables);
-    let try_cache = !tables
-        .keys()
-        .any(|node_id| Space::find(&table_name(required.plan_id.as_str(), *node_id)).is_none());
+    let mut tmp_tables = info.extract_data();
+    let plan_id = info.id();
+    let vdbe_max_steps = info.vdbe_max_steps();
+    let max_rows = info.vtable_max_rows();
+    let parameters = info.params();
+
+    // Look for the statement in the cache.
     let mut locked_cache = runtime.cache().lock();
-    if try_cache {
-        if let Some(res) = read_from_cache::<R, R::Mutex>(
+    let is_cached = locked_cache.get(plan_id)?.is_some();
+    if is_cached {
+        // The statement was found in the cache, so we can execute it.
+        let res = cache_hit::<R, R::Mutex>(
             &mut locked_cache,
-            &required.parameters,
-            &mut tables,
-            &required.plan_id,
-            required.options.vtable_max_rows,
-            opts.clone(),
-        )? {
-            return Ok(res);
-        }
+            parameters,
+            &mut tmp_tables,
+            plan_id,
+            vdbe_max_steps,
+            max_rows,
+        )?;
+        return Ok(res);
+    }
+    // The statement was not found in the cache, so we need to prepare it.
+    let (pattern_with_params, mut guards) = info.extract_query_and_table_guard()?;
+    let plan_id = info.id();
+    let (pattern, params) = pattern_with_params.into_parts();
+    if let Ok(stmt) = prepare(pattern.clone()) {
+        let table_ids: Vec<NodeId> = tmp_tables.keys().copied().collect();
+        locked_cache.put(plan_id.clone(), stmt, info.schema_info(), table_ids)?;
+        // It is safe to skip truncating temporary tables here as there are no early
+        // returns after this point that could leave the tables populated with data.
+        guards.iter_mut().for_each(TableGuard::skip_truncate);
+        let res = cache_miss::<R, R::Mutex>(
+            &mut locked_cache,
+            &params,
+            &mut tmp_tables,
+            plan_id,
+            vdbe_max_steps,
+            max_rows,
+        )?;
+        return Ok(res);
     }
-    let (pattern_with_params, mut guards) = compile_optional(optional, &required.plan_id)?;
-    // There were no errors during the compilation, so we can skip truncating
-    // temporary tables in the table guards (prepare_and_read will do it).
-    guards.iter_mut().for_each(TableGuard::skip_truncate);
-    prepare_and_read::<R, R::Mutex>(
-        &mut locked_cache,
-        &pattern_with_params,
-        &required.plan_id,
-        required.options.vtable_max_rows,
-        opts,
-        &required.schema_info,
-        &mut tables,
+
+    // Possibly the statement is correct, but doesn't fit into
+    // Tarantool's prepared statements cache (`sql_cache_size`).
+    // So we try to execute it bypassing the cache.
+
+    // We need the cache to be locked though we are not going to use it. If we don't lock it,
+    // the prepared statement made from our pattern can be inserted into the cache by some
+    // other fiber because we have removed some big statements with LRU and tarantool cache
+    // has enough space to store this statement. And it can cause races in the temporary
+    // tables.
+
+    read_bypassing_cache(
+        &pattern,
+        &params,
+        plan_id,
+        &mut tmp_tables,
+        vdbe_max_steps,
+        max_rows,
     )
 }
 
@@ -1390,7 +1487,8 @@ where
     let plan = optional.exec_plan.get_ir_plan();
     let column_names = plan.get_relational_aliases(subplan_top_id)?;
     optional.exec_plan.get_mut_ir_plan().restore_constants()?;
-    let result = execute_dql(runtime, required, optional)?;
+    let mut info = QueryInfo::new(optional, required);
+    let result = read_or_prepare(runtime, &mut info)?;
     let tuple = result.downcast::<Tuple>().map_err(|e| {
         SbroadError::FailedTo(
             Action::Deserialize,
@@ -1893,65 +1991,11 @@ where
     }
 
     let result = execute_dml_on_storage(runtime, raw_optional, required)?;
-    let tuple = Tuple::new(&(result,))
+    let tuple = Tuple::new(&[result])
         .map_err(|e| SbroadError::Invalid(Entity::Tuple, Some(format_smolstr!("{e:?}"))))?;
     Ok(Box::new(tuple) as Box<dyn Any>)
 }
 
-/// The same as `execute_dql` but accepts raw optional data.
-/// See docs for `execute_dql`
-///
-/// # Errors
-/// - Failed to borrow runtime's cache
-/// - Tarantool execution error for given statement
-/// - Failed to compile the optional data
-/// - Failed to prepare the statement
-#[allow(unused_variables)]
-pub fn execute_dql_with_raw_optional<R: Vshard + QueryCache>(
-    runtime: &R,
-    required: &mut RequiredData,
-    raw_optional: &mut Vec<u8>,
-) -> Result<Box<dyn Any>, SbroadError>
-where
-    R::Cache: StorageCache,
-{
-    let opts = std::mem::take(&mut required.options.execute_options);
-    let mut tables = std::mem::take(&mut required.tables);
-    let try_cache = !tables
-        .keys()
-        .any(|node_id| Space::find(&table_name(&required.plan_id, *node_id)).is_none());
-    let mut locked_cache = runtime.cache().lock();
-    if try_cache {
-        if let Some(res) = read_from_cache::<R, R::Mutex>(
-            &mut locked_cache,
-            &required.parameters,
-            &mut tables,
-            &required.plan_id,
-            required.options.vtable_max_rows,
-            opts.clone(),
-        )? {
-            return Ok(res);
-        }
-    }
-    let (pattern_with_params, mut guards) = {
-        let data = std::mem::take(raw_optional);
-        let mut optional = OptionalData::try_from(EncodedOptionalData::from(data))?;
-        compile_optional(&mut optional, &required.plan_id)?
-    };
-    // There were no errors during the compilation, so we can skip truncating
-    // temporary tables in the table guards (prepare_and_read will do it).
-    guards.iter_mut().for_each(TableGuard::skip_truncate);
-    prepare_and_read::<R, R::Mutex>(
-        &mut locked_cache,
-        &pattern_with_params,
-        &required.plan_id,
-        required.options.vtable_max_rows,
-        opts,
-        &required.schema_info,
-        &mut tables,
-    )
-}
-
 /// A common function for all engines to calculate the sharding key value from a `map`
 /// of { `column_name` -> value }. Used as a helper function of `extract_sharding_keys_from_map`
 /// that is called from `calculate_bucket_id`. `map` must contain a value for each sharding
@@ -2108,29 +2152,8 @@ fn parse_rows(tuple: &Tuple) -> Result<&[u8], SbroadError> {
 }
 
 fn encode_result_tuple(metadata: &[MetadataColumn], rows: &[u8]) -> Result<Tuple, SbroadError> {
-    #[derive(Debug, Default)]
-    struct MpByteCounter(usize);
-
-    impl MpByteCounter {
-        #[must_use]
-        pub fn bytes(&self) -> usize {
-            self.0
-        }
-    }
-
-    impl std::io::Write for MpByteCounter {
-        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
-            self.0 += buf.len();
-            Ok(buf.len())
-        }
-
-        fn flush(&mut self) -> std::io::Result<()> {
-            Ok(())
-        }
-    }
-
     fn count_mp_bytes(v: impl Serialize) -> usize {
-        let mut byte_counter: MpByteCounter = MpByteCounter::default();
+        let mut byte_counter: ByteCounter = ByteCounter::default();
         let mut ser = rmp_serde::Serializer::new(&mut byte_counter);
         v.serialize(&mut ser).expect("counting failed");
         byte_counter.bytes()
diff --git a/sbroad-core/src/executor/engine/helpers/storage.rs b/sbroad-core/src/executor/engine/helpers/storage.rs
index 931c9be38..f4f0aa9db 100644
--- a/sbroad-core/src/executor/engine/helpers/storage.rs
+++ b/sbroad-core/src/executor/engine/helpers/storage.rs
@@ -1,55 +1,194 @@
-use smol_str::{SmolStr, ToSmolStr};
+use rmp::encode::write_array_len;
+use sbroad_proc::otm_child_span;
+use smol_str::{format_smolstr, SmolStr};
+use std::any::Any;
+use std::collections::HashMap;
+use std::io::Read;
+use tarantool::session::with_su;
+use tarantool::space::Space;
+use tarantool::sql::{
+    prepare as tnt_prepare, prepare_and_execute_raw, unprepare as tnt_unprepare, Statement,
+};
+use tarantool::tuple::{Tuple, TupleBuffer};
 
-use crate::errors::{Entity, SbroadError};
+use crate::backend::sql::space::ADMIN_ID;
+use crate::error;
+use crate::errors::SbroadError;
+use crate::executor::lru::DEFAULT_CAPACITY;
+use crate::ir::value::{EncodedValue, Value};
+use crate::ir::NodeId;
+use crate::otm::child_span;
+use crate::utils::ByteCounter;
 
-pub mod meta;
-pub mod runtime;
+use super::table_name;
 
-pub struct Statement {
-    id: u32,
-    pattern: SmolStr,
+const IPROTO_DATA: u8 = 0x30;
+const IPROTO_META: u8 = 0x32;
+
+/// Storage runtime configuration.
+#[allow(clippy::module_name_repetitions)]
+pub struct StorageMetadata {
+    /// Prepared statements cache capacity (on the storage).
+    pub storage_capacity: usize,
+    /// Prepared statements cache size in bytes (on the storage).
+    /// If a new statement is bigger doesn't fit into the cache,
+    /// it would not be cached but executed directly.
+    pub storage_size_bytes: usize,
 }
 
-#[derive(Default)]
-pub struct PreparedStmt(Option<Statement>);
+impl Default for StorageMetadata {
+    fn default() -> Self {
+        Self::new()
+    }
+}
 
-impl PreparedStmt {
-    /// Extract prepared statement from the cache.
-    ///
-    /// # Errors
-    /// - Returns None instead of a regular statement (sentinel node in the cache).
-    pub fn statement(&self) -> Result<&Statement, SbroadError> {
-        self.0.as_ref().ok_or_else(|| {
-            SbroadError::Invalid(
-                Entity::Statement,
-                Some("Statement is not prepared".to_smolstr()),
-            )
-        })
+impl StorageMetadata {
+    #[must_use]
+    pub fn new() -> Self {
+        StorageMetadata {
+            storage_capacity: DEFAULT_CAPACITY,
+            storage_size_bytes: 1024 * DEFAULT_CAPACITY,
+        }
     }
 
-    /// Get the id of the prepared statement.
-    ///
-    /// # Errors
-    /// - Returns sentinel node from the cache (internal error).
-    pub fn id(&self) -> Result<u32, SbroadError> {
-        Ok(self.statement()?.id)
+    #[must_use]
+    pub fn is_empty(&self) -> bool {
+        self.storage_capacity == 0 && self.storage_size_bytes == 0
     }
+}
+
+#[otm_child_span("tarantool.statement.prepare")]
+pub fn prepare(pattern: String) -> Result<Statement, SbroadError> {
+    let stmt = tnt_prepare(pattern).map_err(|e| {
+        error!(Option::from("prepare"), &format!("{e:?}"));
+        SbroadError::from(e)
+    })?;
+    Ok(stmt)
+}
 
-    /// Get the pattern of the prepared statement.
-    ///
-    /// # Errors
-    /// - Returns sentinel node from the cache (internal error).
-    pub fn pattern(&self) -> Result<&str, SbroadError> {
-        Ok(&self.statement()?.pattern)
+#[otm_child_span("tarantool.statement.unprepare")]
+pub fn unprepare(
+    plan_id: &SmolStr,
+    entry: &mut (Statement, Vec<NodeId>),
+) -> Result<(), SbroadError> {
+    let (stmt, table_ids) = std::mem::take(entry);
+
+    // Remove the statement from the instance cache.
+    tnt_unprepare(stmt);
+
+    // Remove temporary tables from the instance.
+    for node_id in table_ids {
+        let table = table_name(plan_id, node_id);
+        Space::find(table.as_str()).map(|space| with_su(ADMIN_ID, || space.drop()));
     }
+
+    Ok(())
 }
 
-impl std::fmt::Debug for PreparedStmt {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        if let Some(ref stmt) = self.0 {
-            write!(f, "PreparedStmt {:?}", stmt.pattern)
-        } else {
-            write!(f, "PreparedStmt None")
+type EncodedMetadata = rmpv::Value;
+type EncodedData = rmpv::Value;
+
+fn parse_dql(stream: &mut (impl Read + Sized)) -> (EncodedMetadata, EncodedData) {
+    let map_len = rmp::decode::read_map_len(stream).expect("failed to read DQL result");
+    assert_eq!(map_len, 2, "invalid format for DQL result");
+    let mut meta = None;
+    let mut data = None;
+    for _ in 0..map_len {
+        let key = rmp::decode::read_pfix(stream).expect("failed to read IPROTO key");
+        match key {
+            IPROTO_META => {
+                meta = Some(rmpv::decode::read_value(stream).expect("failed to read DQL metadata"));
+            }
+            IPROTO_DATA => {
+                data = Some(rmpv::decode::read_value(stream).expect("failed to read DQL data"));
+            }
+            _ => {
+                unreachable!("unexpected IPROTO key: {}", key);
+            }
         }
     }
+    (
+        meta.expect("missing DQL metadata"),
+        data.expect("missing DQL data"),
+    )
+}
+
+fn repack_meta(meta: EncodedMetadata) -> (rmpv::Value, rmpv::Value) {
+    let mut maps = rmpv::ext::from_value::<Vec<HashMap<u32, rmpv::Value>>>(meta)
+        .expect("failed to decode DQL metadata");
+    let mut repacked = Vec::with_capacity(2);
+    for mut map in maps.drain(..) {
+        let col_name = map.remove(&0).expect("missing name in DQL metadata");
+        let col_type = map.remove(&1).expect("missing type in DQL metadata");
+        let inner = vec![("name".into(), col_name), ("type".into(), col_type)];
+        repacked.push(rmpv::Value::Map(inner));
+    }
+    ("metadata".into(), rmpv::Value::Array(repacked))
+}
+
+fn repack_data(
+    data: EncodedData,
+    max_rows: u64,
+) -> Result<(rmpv::Value, rmpv::Value), SbroadError> {
+    let rows = rmpv::ext::from_value::<Vec<rmpv::Value>>(data).expect("failed to decode DQL data");
+    if rows.len() as u64 > max_rows {
+        return Err(SbroadError::UnexpectedNumberOfValues(format_smolstr!(
+            "expected at most {} rows, got {}",
+            max_rows,
+            rows.len()
+        )));
+    }
+    Ok(("rows".into(), rmpv::Value::Array(rows)))
+}
+
+fn dql_result_to_tuple(
+    stream: &mut (impl Read + Sized),
+    max_rows: u64,
+) -> Result<Tuple, SbroadError> {
+    let (meta, data) = parse_dql(stream);
+    let new_meta = repack_meta(meta);
+    let new_data = repack_data(data, max_rows)?;
+    let repacked = rmpv::Value::Map(vec![new_meta, new_data]);
+    // To pre-allocate the buffer, we need to know the size of the encoded value.
+    let mut byte_counter = ByteCounter::default();
+    rmpv::encode::write_value(&mut byte_counter, &repacked).expect("failed to write result");
+    let mut buf = Vec::with_capacity(byte_counter.bytes());
+    write_array_len(&mut buf, 1).expect("failed to write array length");
+    rmpv::encode::write_value(&mut buf, &repacked).expect("failed to write result");
+    let tup_buf = TupleBuffer::try_from_vec(buf).expect("failed to convert to tuple buffer");
+    Ok(Tuple::from(&tup_buf))
+}
+
+fn encoded_params(params: &[Value]) -> Vec<EncodedValue> {
+    params.iter().map(EncodedValue::from).collect()
+}
+
+#[otm_child_span("tarantool.statement.prepared.execute")]
+pub fn execute_prepared(
+    stmt: &Statement,
+    params: &[Value],
+    vdbe_max_steps: u64,
+    max_rows: u64,
+) -> Result<Box<dyn Any>, SbroadError> {
+    let encoded_params = encoded_params(params);
+    let mut stream = with_su(ADMIN_ID, || {
+        stmt.execute_raw(&encoded_params, vdbe_max_steps)
+    })??;
+    let tuple = dql_result_to_tuple(&mut stream, max_rows)?;
+    Ok(Box::new(tuple) as Box<dyn Any>)
+}
+
+#[otm_child_span("tarantool.statement.unprepared.execute")]
+pub fn execute_unprepared(
+    query: &str,
+    params: &[Value],
+    vdbe_max_steps: u64,
+    max_rows: u64,
+) -> Result<Box<dyn Any>, SbroadError> {
+    let encoded_params = encoded_params(params);
+    let mut stream = with_su(ADMIN_ID, || {
+        prepare_and_execute_raw(query, &encoded_params, vdbe_max_steps)
+    })??;
+    let tuple = dql_result_to_tuple(&mut stream, max_rows)?;
+    Ok(Box::new(tuple) as Box<dyn Any>)
 }
diff --git a/sbroad-core/src/executor/engine/helpers/storage/meta.rs b/sbroad-core/src/executor/engine/helpers/storage/meta.rs
deleted file mode 100644
index 6e01195a0..000000000
--- a/sbroad-core/src/executor/engine/helpers/storage/meta.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-use crate::executor::lru::DEFAULT_CAPACITY;
-
-pub const DEFAULT_JAEGER_AGENT_HOST: &str = "localhost";
-pub const DEFAULT_JAEGER_AGENT_PORT: u16 = 6831;
-
-/// Storage runtime configuration.
-#[allow(clippy::module_name_repetitions)]
-pub struct StorageMetadata {
-    /// Prepared statements cache capacity (on the storage).
-    pub storage_capacity: usize,
-    /// Prepared statements cache size in bytes (on the storage).
-    /// If a new statement is bigger doesn't fit into the cache,
-    /// it would not be cached but executed directly.
-    pub storage_size_bytes: usize,
-    /// Jaeger agent host
-    pub jaeger_agent_host: &'static str,
-    /// Jaeger agent port
-    pub jaeger_agent_port: u16,
-}
-
-impl Default for StorageMetadata {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-impl StorageMetadata {
-    #[must_use]
-    pub fn new() -> Self {
-        StorageMetadata {
-            storage_capacity: DEFAULT_CAPACITY,
-            storage_size_bytes: 1024 * DEFAULT_CAPACITY,
-            jaeger_agent_host: DEFAULT_JAEGER_AGENT_HOST,
-            jaeger_agent_port: DEFAULT_JAEGER_AGENT_PORT,
-        }
-    }
-
-    #[must_use]
-    pub fn is_empty(&self) -> bool {
-        self.storage_capacity == 0 && self.storage_size_bytes == 0
-    }
-}
diff --git a/sbroad-core/src/executor/lru.rs b/sbroad-core/src/executor/lru.rs
index b0861d81b..749670b5a 100644
--- a/sbroad-core/src/executor/lru.rs
+++ b/sbroad-core/src/executor/lru.rs
@@ -42,7 +42,7 @@ pub trait Cache<Key, Value> {
 struct LRUNode<Key, Value>
 where
     Key: Clone,
-    Value: Default + Debug,
+    Value: Default,
 {
     /// The value of the node.
     value: Value,
@@ -55,7 +55,7 @@ where
 impl<Key, Value> LRUNode<Key, Value>
 where
     Key: Clone,
-    Value: Default + Debug,
+    Value: Default,
 {
     fn new(value: Value) -> Self {
         LRUNode {
@@ -81,7 +81,7 @@ where
 pub struct LRUCache<Key, Value>
 where
     Key: Clone,
-    Value: Default + Debug,
+    Value: Default,
 {
     /// The capacity of the cache.
     capacity: usize,
@@ -95,7 +95,7 @@ where
 
 impl<Key, Value> LRUCache<Key, Value>
 where
-    Value: Default + Debug,
+    Value: Default,
     Key: Clone + Eq + std::hash::Hash + std::fmt::Debug,
 {
     fn get_node_or_none(&self, key: &Option<Key>) -> Option<&LRUNode<Key, Value>> {
@@ -234,7 +234,7 @@ where
 
 impl<Key, Value> Cache<Key, Value> for LRUCache<Key, Value>
 where
-    Value: Default + Debug,
+    Value: Default,
     Key: Clone + Eq + std::hash::Hash + std::fmt::Debug,
 {
     fn new(capacity: usize, evict_fn: Option<EvictFn<Key, Value>>) -> Result<Self, SbroadError> {
diff --git a/sbroad-core/src/executor/result.rs b/sbroad-core/src/executor/result.rs
index 711924234..b7b49eca8 100644
--- a/sbroad-core/src/executor/result.rs
+++ b/sbroad-core/src/executor/result.rs
@@ -10,9 +10,11 @@
 //! * `row_count` (u64): the number of tuples inserted (that may be equal to 0)
 
 use core::fmt::Debug;
+use serde::de::Error as DeError;
 use serde::ser::{Serialize, SerializeMap, Serializer};
-use serde::Deserialize;
+use serde::{Deserialize, Deserializer};
 use smol_str::{SmolStr, ToSmolStr};
+use std::collections::HashMap;
 use tarantool::tlua::{self, LuaRead};
 use tarantool::tuple::Encode;
 
@@ -27,7 +29,7 @@ use crate::ir::{Node, Plan};
 
 pub type ExecutorTuple = Vec<LuaValue>;
 
-#[derive(LuaRead, Debug, Deserialize, PartialEq, Eq, Clone)]
+#[derive(LuaRead, Debug, PartialEq, Eq, Clone)]
 pub struct MetadataColumn {
     name: String,
     r#type: String,
@@ -52,6 +54,25 @@ impl Serialize for MetadataColumn {
     }
 }
 
+impl<'de> Deserialize<'de> for MetadataColumn {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let map = HashMap::<String, String>::deserialize(deserializer)?;
+        let col_name = map
+            .get("name")
+            .ok_or_else(|| DeError::custom("missing name in DQL metadata"))?;
+        let col_type = map
+            .get("type")
+            .ok_or_else(|| DeError::custom("missing type in DQL metadata"))?;
+        Ok(MetadataColumn::new(
+            col_name.to_string(),
+            col_type.to_string(),
+        ))
+    }
+}
+
 impl TryInto<Column> for &MetadataColumn {
     type Error = SbroadError;
 
diff --git a/sbroad-core/src/executor/vtable.rs b/sbroad-core/src/executor/vtable.rs
index 2577f7184..4ba1916fd 100644
--- a/sbroad-core/src/executor/vtable.rs
+++ b/sbroad-core/src/executor/vtable.rs
@@ -559,7 +559,7 @@ impl VirtualTable {
             rows.push(row);
         }
 
-        let res = vec![ProducerResult { metadata, rows }];
+        let res = [ProducerResult { metadata, rows }];
         #[cfg(feature = "mock")]
         {
             Ok(Box::new(res))
diff --git a/sbroad-core/src/ir.rs b/sbroad-core/src/ir.rs
index ad2cbc2e1..563f0fcca 100644
--- a/sbroad-core/src/ir.rs
+++ b/sbroad-core/src/ir.rs
@@ -306,6 +306,32 @@ impl ExecuteOptions {
     pub fn insert(&mut self, kind: OptionKind, value: Value) -> Option<Value> {
         self.0.insert(kind, value)
     }
+
+    #[must_use]
+    pub fn vdbe_max_steps(&self) -> u64 {
+        self.0
+            .get(&OptionKind::SqlVdbeMaxSteps)
+            .map_or(DEFAULT_VDBE_MAX_STEPS, |v| {
+                if let Value::Unsigned(steps) = v {
+                    *steps
+                } else {
+                    DEFAULT_VDBE_MAX_STEPS
+                }
+            })
+    }
+
+    #[must_use]
+    pub fn vtable_max_rows(&self) -> u64 {
+        self.0
+            .get(&OptionKind::VTableMaxRows)
+            .map_or(DEFAULT_VTABLE_MAX_ROWS, |v| {
+                if let Value::Unsigned(rows) = v {
+                    *rows
+                } else {
+                    DEFAULT_VTABLE_MAX_ROWS
+                }
+            })
+    }
 }
 
 impl<L> tlua::PushInto<L> for ExecuteOptions
-- 
GitLab