From aa4111ad6ae8f2c4b25e236f63c371eae89ed826 Mon Sep 17 00:00:00 2001
From: Georgy Moshkin <gmoshkin@picodata.io>
Date: Mon, 22 Jan 2024 18:13:06 +0300
Subject: [PATCH] fix: support for compat.c_func_iproto_multireturn = 'new'

---
 sbroad-core/src/core-router.lua | 15 ++++++++++-----
 sbroad-core/src/helper.lua      | 25 +++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/sbroad-core/src/core-router.lua b/sbroad-core/src/core-router.lua
index 685c61e4bc..efe14aa4fc 100644
--- a/sbroad-core/src/core-router.lua
+++ b/sbroad-core/src/core-router.lua
@@ -247,7 +247,8 @@ _G.dql_on_some = function(uuid_to_args, is_readonly, waiting_timeout, vtable_max
         if err ~= nil then
             error(err)
         end
-        result = res[1][1][1]
+        -- TODO: explain where this `[1][1]` comes from
+        result = helper.unwrap_execute_result(res[1][1])
     else
         local err, err_uuid
         local opts = { map_timeout = waiting_timeout, ref_timeout = waiting_timeout }
@@ -320,10 +321,12 @@ _G.dml_on_some = function(tbl_rs_ir, is_readonly, waiting_timeout)
             error(err)
         end
 
+        -- TODO: explain where this `[1][1]` comes from
+        local next_result = helper.unwrap_execute_result(res[1][1])
         if result == nil then
-            result = res[1][1][1]
+            result = next_result
         else
-            result.row_count = result.row_count + res[1][1][1].row_count
+            result.row_count = result.row_count + next_result.row_count
         end
     end
 
@@ -369,10 +372,12 @@ _G.dml_on_all = function(required, optional, is_readonly, waiting_timeout)
             error(err)
         end
 
+        -- TODO: explain where this `[1][1]` comes from
+        local next_result = helper.unwrap_execute_result(res[1][1])
         if result == nil then
-            result = res[1][1][1]
+            result = next_result
         else
-            result.row_count = result.row_count + res[1][1][1].row_count
+            result.row_count = result.row_count + next_result.row_count
         end
     end
 
diff --git a/sbroad-core/src/helper.lua b/sbroad-core/src/helper.lua
index 3e6c18bc8e..56fb73eba7 100644
--- a/sbroad-core/src/helper.lua
+++ b/sbroad-core/src/helper.lua
@@ -1,3 +1,6 @@
+local compat = require('compat')
+local compat_mt = compat ~= nil and getmetatable(compat) or nil
+
 -- Make table read-only
 local function protect(tbl)
     return setmetatable({}, {
@@ -64,10 +67,32 @@ local function dql_error(err, rs_uuid)
     error(err)
 end
 
+local function unwrap_execute_result(result)
+    if compat_mt == nil then
+        return result[1]
+    end
+    -- We want to just call `compat.c_func_iproto_multireturn:is_new()`,
+    -- but it throws an exception when the option is unknown.
+    local ok, opt = pcall(compat_mt.__index, compat, 'c_func_iproto_multireturn')
+    if ok and opt:is_new() then
+        -- On older versions of tarantool there was a bug which made all FFI
+        -- stored procedures' wrap their return values into an additional
+        -- msgpack array (they call it "multireturn", but you couldn't put
+        -- multiple values in there, it was hard-coded to be 1 element). But
+        -- thankfully it was fixed and now we get to rewrite all of our code...
+        -- Yay!
+        -- See https://github.com/tarantool/tarantool/issues/4799
+        return result
+    else
+        return result[1]
+    end
+end
+
 return {
     module_name = module_name,
     vtable_limit_exceeded = vtable_limit_exceeded,
     dql_error = dql_error,
     format_result = format_result,
+    unwrap_execute_result = unwrap_execute_result,
     constants = constants
 }
-- 
GitLab