Версия:

Коннекторы

Коннекторы

В этой главе описаны API для различных языков программирования.

Протокол

Бинарный протокол для передачи данных в Tarantool’е был разработан с учетом потребностей асинхронного ввода-вывода для облегчения интеграции с прокси-серверами. Каждый клиентский запрос начинается с бинарного заголовка переменной длины. В заголовке указывается идентификатор и тип запроса, идентификатор экземпляра, номер записи в журнале и т.д.

Также в заголовке обязательно указывается длина запроса, что облегчает обработку данных. Ответ на запрос посылается по мере готовности. В заголовке ответа указывается тот же идентификатор и тип запроса, что и в изначальном запросе. По идентификатору можно легко соотнести запрос с ответом, даже если ответ был получен не в порядке отсылки запросов.

Вдаваться в тонкости реализации Tarantool-протокола нужно только при разработке нового коннектора для Tarantool’а – см. полное описание бинарного протокола в Tarantool’е в виде аннотированных BNF-диаграмм (Backus-Naur Form). В остальных случаях достаточно взять уже существующий коннектор для нужного вам языка программирования. Такие коннекторы позволяют легко хранить структуры данных из разных языков в формате Tarantool’а.

Пример пакета данных

С помощью API Tarantool’а клиентские программы могут отправлять пакеты с запросами в адрес экземпляра и получать на них ответы. Вот пример для запроса box.space[513]:insert{'A', 'BB'}. Описания компонентов запроса (в виде BNF-диаграмм) вы найдете на странице о бинарном протоколе в Tarantool’е.

Компонент Байт #0 Байт #1 Байт #2 Байт #3
код для вставки 02      
остаток заголовка
число из 2 цифр: ID спейса cd 02 01  
код для кортежа 21      
число из 1 цифры: количество полей = 2 92      
строка из 1 символа: поле[1] a1 41    
строка из 2 символов: поле[2] a2 42 42  

Теперь получившийся пакет можно послать в адрес экземпляра Tarantool’а и затем расшифровать ответ (описания формата пакета ответов и вопросов вы найдете на той же странице о бинарном протоколе в Tarantool’е). Но более простым и верным способом будет вызвать процедуру, которая сформирует готовый пакет с заданными параметрами. Что-то вроде response = tarantool_routine("insert", 513, "A", "B");. Для этого и существуют API для драйверов для Perl, Python, PHP и т.д.

Настройка окружения для примеров работы с коннекторами

В этой главе приводятся примеры того, как можно установить соединение с Tarantool-сервером с помощью коннекторов для языков Perl, PHP, Python, node.js и C. Обратите внимание, что в примерах указаны фиксированные значения, поэтому для корректной работы всех примеров нужно соблюсти следующие условия:

  • экземпляр (Tarantool) запущен на локальной машине (localhost = 127.0.0.1), а прослушивание для него настроено на порту 3301 (box.cfg.listen = '3301'),
  • в базе есть спейс``examples`` с идентификатором 999 (box.space.examples.id = 999), и у него есть первичный индекс, построенный по ключу числового типа (box.space[999].index[0].parts[1].type = "unsigned"),
  • для пользователя „guest“ настроены права на чтение и запись.

Можно легко соблюсти все условия, запустив экземпляр и выполнив следующий скрипт:

box.cfg{listen=3301}
            box.schema.space.create('examples',{id=999})
            box.space.examples:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}})
            box.schema.user.grant('guest','read,write','space','examples')
            box.schema.user.grant('guest','read','space','_space')

Perl

Самый используемый драйвер для Perl – tarantool-perl. Он не входит в репозиторий Tarantool’а, его необходимо устанавливать отдельно. Проще всего установить его путем клонирования с GitHub.

Во избежание незначительных предупреждений, которые может выдать система после первой установки tarantool-perl, начните установку с некоторых других модулей, которые использует tarantool-perl, с CPAN, the Comprehensive Perl Archive Network (Всеобъемлющая сеть архивов Perl):

$ sudo cpan install AnyEvent
          $ sudo cpan install Devel::GlobalDestruction

Затем для установки самого tarantool-perl, выполните:

$ git clone https://github.com/tarantool/tarantool-perl.git tarantool-perl
          $ cd tarantool-perl
          $ git submodule init
          $ git submodule update --recursive
          $ perl Makefile.PL
          $ make
          $ sudo make install

Далее приводится пример полноценной программы на языке Perl, которая осуществляет вставку кортежа [99999,'BB'] в спейс space[999] с помощью API для языка Perl. Перед запуском проверьте, что у экземпляра задан порт для прослушивания на localhost:3301, и в базе создан спейс examples, как описано выше. Чтобы запустить программу, сохраните код в файл с именем example.pl и выполните команду perl example.pl. Программа установит соединение, используя определение спейса для этой цели, откроет сокет для соединения с экземпляром по localhost:3301, пошлет запрос space_object:INSERT, а затем – если всё хорошо – закончит работу без каких-либо сообщений. Если Tarantool не запущен на localhost на прослушивание по порту = 3301, то программа выдаст сообщение об ошибке «Connection refused».

#!/usr/bin/perl
            use DR::Tarantool ':constant', 'tarantool';
            use DR::Tarantool ':all';
            use DR::Tarantool::MsgPack::SyncClient;

            my $tnt = DR::Tarantool::MsgPack::SyncClient->connect(
              host    => '127.0.0.1',                      # поиск Tarantool-сервера по адресу localhost
              port    => 3301,                             # на порту 3301
              user    => 'guest',                          # имя пользователя; здесь же можно добавить 'password=>...'

              spaces  => {
                999 => {                                   # определение спейса  space[999] ...
                  name => 'examples',                      # имя спейса space[999] = 'examples'
                  default_type => 'STR',                   # если тип поля в space[999] не задан, то = 'STR'
                  fields => [ {                            # определение полей в спейсе space[999] ...
                      name => 'field1', type => 'NUM' } ], # имя поля space[999].field[1]='field1', тип ='NUM'
                  indexes => {                             # определение индексов спейса space[999] ...
                    0 => {
                      name => 'primary', fields => [ 'field1' ] } } } } );

            $tnt->insert('examples' => [ 99999, 'BB' ]);

Из-за временных ограничений в языке Perl, вместо полей типа „string“ и „unsigned“ в тестовой программе указаны поля типа „STR“ и „NUM“.

В этой программе мы привели пример использования лишь одного запроса. Для полноценной работы с Tarantool’ом обратитесь к документации из репозитория tarantool-perl.

PHP

tarantool-php is the official PHP connector for Tarantool. It is not supplied as part of the Tarantool repository and must be installed separately (see installation instructions in the connector’s README file).

Here is a complete PHP program that inserts [99999,'BB'] into a space named examples via the PHP API.

Before trying to run, check that the server instance is listening at localhost:3301 and that the space examples exists, as described earlier.

To run, paste the code into a file named example.php and say:

$ php -d extension=~/tarantool-php/modules/tarantool.so example.php

The program will open a socket connection with the Tarantool instance at localhost:3301, then send an INSERT request, then – if all is well – print «Insert succeeded».

If the tuple already exists, the program will print «Duplicate key exists in unique index „primary“ in space „examples“».

<?php
$tarantool = new Tarantool('localhost', 3301);

try {
    $tarantool->insert('examples', [99999, 'BB']);
    echo "Insert succeeded\n";
} catch (Exception $e) {
    echo $e->getMessage(), "\n";
}

В этой программе мы привели пример использования лишь одного запроса. Для полноценной работы с Tarantool’ом обратитесь к документации из проекта tarantool-php на GitHub.

Besides, there is another community-driven GitHub project which includes an alternative connector written in pure PHP, an object mapper, a queue and other packages.

Python

Далее приводится пример полноценной программы на языке Python, которая осуществляет вставку [99999,'Value','Value'] в спейс examples с помощью высокоуровневого API для языка Python.

#!/usr/bin/python
          from tarantool import Connection

          c = Connection("127.0.0.1", 3301)
          result = c.insert("examples",(99999,'Value', 'Value'))
          print result

Для подготовки сохраните код в файл с именем example.py и установите коннектор tarantool-python. Для установки коннектора воспользуйтесь либо командой samp:pip install tarantool>0.4 для установки в директорию /usr (потребуются права уровня root), либо командой pip install tarantool>0.4 --user для установки в директорию ~, т.е. в используемую по умолчанию директорию текущего пользователя. Перед запуском проверьте, что у экземпляра задан порт для прослушивания <cfg_basic-listen>`на``localhost:3301`, и в базе создан спейс examples, как описано выше. Чтобы запустить программу, выполните команду python example.py. Программа установит соединение с Tarantool-сервером, пошлет INSERT-запрос и не выбросит никакого исключения, если всё прошло хорошо. Если такой кортеж уже существует, то программа выбросит исключение tarantool.error.DatabaseError: (3, "Duplicate key exists in unique index 'primary' in space 'examples'").

В этой программе мы привели пример использования лишь одного запроса. Для полноценной работы с Tarantool’ом обратитесь к документации из проекта tarantool-python на GitHub. А на странице проекта queue-python на GitHub вы сможете найти примеры использования Python API для работы с очередями сообщений в Tarantool’е.

Node.js

Самый используемый драйвер для node.js – Node Tarantool driver. Он не входит в репозиторий Tarantool’а, его необходимо устанавливать отдельно. Проще всего установить его вместе с npm. Например, на Ubuntu, когда npm уже установлен, установка драйвера будет выглядеть следующим образом:

$ npm install tarantool-driver --global

Далее приводится пример полноценной программы на языке node.js, которая осуществляет вставку кортежа [99999,'BB'] в спейс space[999] с помощью API для языка node.js. Перед запуском проверьте, что у экземпляра задан порт для прослушивания <cfg_basic-listen>`на``localhost:3301`, и в базе создан спейс examples, как описано выше. Чтобы запустить программу, сохраните код в файл с именем example.rs и выполните команду node example.rs. Программа установит соединение, используя определение спейса для этой цели, откроет сокет для соединения с экземпляром по localhost:3301, отправит INSERT-запрос, а затем – если всё хорошо – выдаст сообщение «Insert succeeded». Если Tarantool не запущен на localhost на прослушивание по порту = 3301, то программа выдаст сообщение об ошибке “Connect failed”. Если у пользователя „guest“ нет прав на соединение, программа выдаст сообщение об ошибке «Auth failed». Если запрос вставки по какой-либо причине не сработает, например поскольку такой кортеж уже существует, то программа выдаст сообщение об ошибке «Insert failed».

var TarantoolConnection = require('tarantool-driver');
          var conn = new TarantoolConnection({port: 3301});
          var insertTuple = [99999, "BB"];
          conn.connect().then(function() {
              conn.auth("guest", "").then(function() {
                  conn.insert(999, insertTuple).then(function() {
                      console.log("Insert succeeded");
                      process.exit(0);
              }, function(e) { console.log("Insert failed");  process.exit(1); });
              }, function(e) { console.log("Auth failed");    process.exit(1); });
              }, function(e) { console.log("Connect failed"); process.exit(1); });

В этой программе мы привели пример использования лишь одного запроса. Для полноценной работы с Tarantool’ом обратитесь к документации из репозитория драйвера для node.js.

C#

Самый используемый драйвер для C# – progaudi.tarantool, который раньше назывался tarantool-csharp. Он не входит в репозиторий Tarantool’а, его необходимо устанавливать отдельно. Создатели драйвера рекомендуют кроссплатформенную установку с помощью Nuget.

Чтобы придерживаться метода оформления других инструкций в данной главе, дадим описание способа установки драйвера напрямую на 16.04.

  1. Установите среду .NET Core от Microsoft. Следуйте инструкциям по установке .NET Core.

Примечание

  • Mono не сработает, как не сработает и .Net от xbuild. Только .NET Core поддерживается на Linux и Mac.
  • Сначала прочитайте Условия лицензионного соглашения с Microsoft, поскольку оно не похоже на обычные соглашения для ПО с открытым кодом, и во время установки система выдаст сообщение о том, что ПО может собирать информацию («This software may collect information about you and your use of the software, and send that to Microsoft.»). Несмотря на это, можно определить переменные окружения, чтобы отказаться от участия в сборе телеметрических данных.
  1. Создайте новый консольный проект.

    $ cd ~
              $ mkdir progaudi.tarantool.test
              $ cd progaudi.tarantool.test
              $ dotnet new console
    
  2. Добавьте ссылку на progaudi.tarantool.

    $ dotnet add package progaudi.tarantool
    
  3. Измените код в Program.cs.

    $ cat <<EOT > Program.cs
              using System;
              using System.Threading.Tasks;
              using ProGaudi.Tarantool.Client;
    
              public class HelloWorld
              {
                static public void Main ()
                {
                  Test().GetAwaiter().GetResult();
                }
                static async Task Test()
                {
                  var box = await Box.Connect("127.0.0.1:3301");
                  var schema = box.GetSchema();
                  var space = await schema.GetSpace("examples");
                  await space.Insert((99999, "BB"));
                }
              }
              EOT
    
  4. Соберите и запустите приложение.

    Перед запуском проверьте, что у экземпляра задан порт для прослушивания на``localhost:3301``, и в базе создан спейс examples, как описано выше.

    $ dotnet restore
              $ dotnet run
    

    Программа:

    • установит соединение, используя определение спейса для этой цели,
    • откроет сокет для соединения с экземпляром по localhost:3301,
    • отправит INSERT-запрос, а затем – если всё хорошо – закончит работу без каких-либо сообщений.

    Если Tarantool не запущен на localhost на прослушивание по порту 3301, или у пользователя „guest“ нет прав на соединение, или запрос вставки по какой-либо причине не сработает, то программа выдаст сообщение об ошибке и другую информацию (трассировку стека и т.д.).

В этой программе мы привели пример использования лишь одного запроса. Для полноценной работы с Tarantool’ом с помощью PHP API, пожалуйста, обратитесь к документации из проекта tarantool-php на GitHub.

C

В этом разделе даны два примера использования высокоуровневого API для Tarantool’а и языка C.

Пример 1

Далее приводится пример полноценной программы на языке C, которая осуществляет вставку кортежа [99999,'B'] в спейс examples с помощью высокоуровневого API для языка C.

#include <stdio.h>
            #include <stdlib.h>

            #include <tarantool/tarantool.h>
            #include <tarantool/tnt_net.h>
            #include <tarantool/tnt_opt.h>

            void main() {
               struct tnt_stream *tnt = tnt_net(NULL);          /* См. ниже = НАСТРОЙКА */
               tnt_set(tnt, TNT_OPT_URI, "localhost:3301");
               if (tnt_connect(tnt) < 0) {                      /* См. ниже = СОЕДИНЕНИЕ */
                   printf("Connection refused\n");
                   exit(-1);
               }
               struct tnt_stream *tuple = tnt_object(NULL);     /* См. ниже = СОЗДАНИЕ ЗАПРОСА */
               tnt_object_format(tuple, "[%d%s]", 99999, "B");
               tnt_insert(tnt, 999, tuple);                     /* См. ниже = ОТПРАВКА ЗАПРОСА */
               tnt_flush(tnt);
               struct tnt_reply reply;  tnt_reply_init(&reply); /* См. ниже = ПОЛУЧЕНИЕ ОТВЕТА */
               tnt->read_reply(tnt, &reply);
               if (reply.code != 0) {
                   printf("Insert failed %lu.\n", reply.code);
               }
               tnt_close(tnt);                                  /* См. ниже = ЗАВЕРШЕНИЕ */
               tnt_stream_free(tuple);
               tnt_stream_free(tnt);
            }

Скопируйте исходный код программы в файл с именем example.c и установите коннектор tarantool-c. Вот один из способов установки tarantool-c (под Ubuntu):

$ git clone git://github.com/tarantool/tarantool-c.git ~/tarantool-c
            $ cd ~/tarantool-c
            $ git submodule init
            $ git submodule update
            $ cmake .
            $ make
            $ make install

Чтобы скомпилировать и слинковать тестовую программу, выполните следующую команду:

$ # иногда это необходимо:
            $ export LD_LIBRARY_PATH=/usr/local/lib
            $ gcc -o example example.c -ltarantool

Before trying to run, check that a server instance is listening at localhost:3301 and that the space examples exists, as described earlier. To run the program, say ./example. The program will connect to the Tarantool instance, and will send the request. If Tarantool is not running on localhost with listen address = 3301, the program will print “Connection refused”. If the insert fails, the program will print «Insert failed» and an error number (see all error codes in the source file /src/box/errcode.h).

Далее следуют примечания, на которые мы ссылались в комментариях к исходному коду тестовой программы.

НАСТРОЙКА: Настройка начинается с создания потока (tnt_stream).

struct tnt_stream *tnt = tnt_net(NULL);
            tnt_set(tnt, TNT_OPT_URI, "localhost:3301");

В нашей программе поток назван tnt. Перед установкой соединения с потоком tnt нужно задать ряд опций. Самая важная из них – TNT_OPT_URI. Для этой опции указан URI localhost:3301, т.е. адрес, по которому должно быть настроено :ref:`прослушивание <cfg_basic-listen>`на стороне экземпляра Tarantool’а.

Описание функции:

struct tnt_stream *tnt_net(struct tnt_stream *s)
          int tnt_set(struct tnt_stream *s, int option, variant option-value)

СОЕДИНЕНИЕ: Теперь когда мы создали поток с именем tnt и связали его с конкретным URI, наша программа может устанавливать соединение с экземпляром.

if (tnt_connect(tnt) < 0)
               { printf("Connection refused\n"); exit(-1); }

Описание функции:

int tnt_connect(struct tnt_stream \*s)

Попытка соединения может и не удаться по разным причинам, например если Tarantool-сервер не запущен или в URI-строке указан неверный пароль. В случае неудачи функция вернет -1.

СОЗДАНИЕ ЗАПРОСА: В большинстве запросов требуется передавать структурированные данные, например содержимое кортежа.

struct tnt_stream *tuple = tnt_object(NULL);
            tnt_object_format(tuple, "[%d%s]", 99999, "B");

В данной программе мы используем запрос INSERT, а кортеж содержит целое число и строку. Это простой набор значений без каких-либо вложенных структур или массивов. И передаваемые значения мы можем указать самым простым образом – аналогично тому, как это сделано в стандартной C-функции printf(): %d для обозначения целого числа, %s для обозначения строки, затем числовое значение, затем указатель на строковое значение.

Описание функции:

ssize_t tnt_object_format(struct tnt_stream \*s, const char \*fmt, ...)

ОТПРАВКА ЗАПРОСА: Отправка запросов на изменение данных в базе делается аналогично тому, как это делается в Tarantool-библиотеке box.

tnt_insert(tnt, 999, tuple);
            tnt_flush(tnt);

В данной программе мы делаем INSERT-запрос. В этом запросе мы передаем поток tnt, который ранее использовали для установки соединения, и поток tuple, который также ранее настроили с помощью функции tnt_object_format().

Описание функции:

ssize_t tnt_insert(struct tnt_stream \*s, uint32_t space, struct tnt_stream \*tuple)
            ssize_t tnt_replace(struct tnt_stream \*s, uint32_t space, struct tnt_stream \*tuple)
            ssize_t tnt_select(struct tnt_stream \*s, uint32_t space, uint32_t index,
                               uint32_t limit, uint32_t offset, uint8_t iterator,
                               struct tnt_stream \*key)
            ssize_t tnt_update(struct tnt_stream \*s, uint32_t space, uint32_t index,
                               struct tnt_stream \*key, struct tnt_stream \*ops)

ПОЛУЧЕНИЕ ОТВЕТА: На большинство запросов клиент получает ответ, который содержит информацию о том, был ли данный запрос успешно выполнен, а также содержит набор кортежей.

struct tnt_reply reply;  tnt_reply_init(&reply);
            tnt->read_reply(tnt, &reply);
            if (reply.code != 0)
               { printf("Insert failed %lu.\n", reply.code); }

Данная программа проверяет, был ли запрос выполнен успешно, но никак не интерпретирует оставшуюся часть ответа.

Описание функции:

struct tnt_reply \*tnt_reply_init(struct tnt_reply \*r)
            tnt->read_reply(struct tnt_stream \*s, struct tnt_reply \*r)
            void tnt_reply_free(struct tnt_reply \*r)

ЗАВЕРШЕНИЕ: По окончании сессии нам нужно закрыть соединение, созданное с помощью функции tnt_connect(), и удалить объекты, созданные на этапе настройки.

tnt_close(tnt);
            tnt_stream_free(tuple);
            tnt_stream_free(tnt);

Описание функции:

void tnt_close(struct tnt_stream \*s)
            void tnt_stream_free(struct tnt_stream \*s)

Пример 2

Далее приводится еще один пример полноценной программы на языке C, которая осуществляет выборку по индекс-ключу [99999] из спейса examples с помощью высокоуровневого Tarantool API для языка C. Для вывода результатов в этой программе используются функции из библиотеки MsgPuck. Эти функции нужны для декодирования массивов значений в формате MessagePack.

#include <stdio.h>
            #include <stdlib.h>
            #include <tarantool/tarantool.h>
            #include <tarantool/tnt_net.h>
            #include <tarantool/tnt_opt.h>

            #define MP_SOURCE 1
            #include <msgpuck.h>

            void main() {
                struct tnt_stream *tnt = tnt_net(NULL);
                tnt_set(tnt, TNT_OPT_URI, "localhost:3301");
                if (tnt_connect(tnt) < 0) {
                    printf("Connection refused\n");
                    exit(1);
                }
                struct tnt_stream *tuple = tnt_object(NULL);
                tnt_object_format(tuple, "[%d]", 99999); /* кортеж tuple = ключ для  поиска */
                tnt_select(tnt, 999, 0, (2^32) - 1, 0, 0, tuple);
                tnt_flush(tnt);
                struct tnt_reply reply; tnt_reply_init(&reply);
                tnt->read_reply(tnt, &reply);
                if (reply.code != 0) {
                    printf("Select failed.\n");
                    exit(1);
                }
                char field_type;
                field_type = mp_typeof(*reply.data);
                if (field_type != MP_ARRAY) {
                    printf("no tuple array\n");
                    exit(1);
                }
                long unsigned int row_count;
                uint32_t tuple_count = mp_decode_array(&reply.data);
                printf("tuple count=%u\n", tuple_count);
                unsigned int i, j;
                for (i = 0; i < tuple_count; ++i) {
                    field_type = mp_typeof(*reply.data);
                    if (field_type != MP_ARRAY) {
                        printf("no field array\n");
                        exit(1);
                    }
                    uint32_t field_count = mp_decode_array(&reply.data);
                    printf("  field count=%u\n", field_count);
                    for (j = 0; j < field_count; ++j) {
                        field_type = mp_typeof(*reply.data);
                        if (field_type == MP_UINT) {
                            uint64_t num_value = mp_decode_uint(&reply.data);
                            printf("    value=%lu.\n", num_value);
                        } else if (field_type == MP_STR) {
                            const char *str_value;
                            uint32_t str_value_length;
                            str_value = mp_decode_str(&reply.data, &str_value_length);
                            printf("    value=%.*s.\n", str_value_length, str_value);
                        } else {
                            printf("wrong field type\n");
                            exit(1);
                        }
                    }
                }
                tnt_close(tnt);
                tnt_stream_free(tuple);
                tnt_stream_free(tnt);
            }

Аналогично первому примеру, сохраните исходный код программы в файле с именем example2.c.

Чтобы скомпилировать и слинковать тестовую программу, выполните следующую команду:

$ gcc -o example2 example2.c -ltarantool

Для запуска программы выполните команду ./example2.

В этих двух программах мы привели пример использования лишь двух запросов. Для полноценной работы с Tarantool’ом с помощью C API, пожалуйста, обратитесь к документации из проекта tarantool-c на GitHub.

Интерпретация возвращаемых значений

При работе с любым Tarantool-коннектором функции, вызванные с помощью Tarantool’а, возвращают значения в формате MsgPack. Если функция была вызвана через API коннектора, то формат возвращаемых значений будет следующим: скалярные значения возвращаются в виде кортежей (сначала идет идентификатор типа из формата MsgPack, а затем идет значение); все прочие (не скалярные) значения возвращаются в виде групп кортежей (сначала идет идентификатор массива в формате MsgPack, а затем идут скалярные значения). Но если функция была вызвана в рамках бинарного протокола (с помощью команды eval), а не через API коннектора, то подобных изменений формата возвращаемых значений не происходит.

Далее приводится пример создания Lua-функции. Поскольку эту функцию будет вызывать внешний пользователь „guest“ user, то нужно настроить права на исполнение с помощью grant. Эта функция возвращает пустой массив, строку-скаляр, два логических значения и короткое целое число. Значение будут теми же, что описаны в разделе про MsgPack в таблице Стандартные типы в MsgPack-кодировке.

tarantool> box.cfg{listen=3301}
            2016-03-03 18:45:52.802 [27381] main/101/interactive I> ready to accept requests
            ---
            ...
            tarantool> function f() return {},'a',false,true,127; end
            ---
            ...
            tarantool> box.schema.func.create('f')
            ---
            ...
            tarantool> box.schema.user.grant('guest','execute','function','f')
            ---
            ...

Далее идет пример программы на C, из который мы вызываем эту Lua-функцию. Хотя в примере использован код на C, результат будет одинаковым, на каком бы языке ни была написана вызываемая программа: Perl, PHP, Python, Go или Java.

#include <stdio.h>
            #include <stdlib.h>
            #include <tarantool/tarantool.h>
            #include <tarantool/tnt_net.h>
            #include <tarantool/tnt_opt.h>
            void main() {
              struct tnt_stream *tnt = tnt_net(NULL);            /* НАСТРОЙКА */
              tnt_set(tnt, TNT_OPT_URI, "localhost:3301");
               if (tnt_connect(tnt) < 0) {                        /* СОЕДИНЕНИЕ */
                   printf("Connection refused\n");
                   exit(-1);
               }
               struct tnt_stream *tuple = tnt_object(NULL);       /* СОЗДАНИЕ ЗАПРОСА  */
               struct tnt_stream *arg; arg = tnt_object(NULL);
               tnt_object_add_array(arg, 0);
               struct tnt_request *req1 = tnt_request_call(NULL); /* ВЫЗОВ function f() */
               tnt_request_set_funcz(req1, "f");
               tnt_request_set_tuple(req1, arg);
               uint64_t sync1 = tnt_request_compile(tnt, req1);
               tnt_flush(tnt);                                    /* ОТПРАВКА ЗАПРОСА  */
               struct tnt_reply reply;  tnt_reply_init(&reply);   /* ПОЛУЧЕНИЕ ОТВЕТА  */
               tnt->read_reply(tnt, &reply);
               if (reply.code != 0) {
                 printf("Call failed %lu.\n", reply.code);
                 exit(-1);
               }
               const unsigned char *p= (unsigned char*)reply.data;/* ВЫВОД ОТВЕТА */
               while (p < (unsigned char *) reply.data_end)
               {
                 printf("%x ", *p);
                 ++p;
               }
               printf("\n");
               tnt_close(tnt);                                    /* ЗАВЕРШЕНИЕ */
               tnt_stream_free(tuple);
               tnt_stream_free(tnt);
            }

По завершении программа выведет на экран следующие значения:

dd 0 0 0 5 90 91 a1 61 91 c2 91 c3 91 7f

Первые пять байт – dd 0 0 0 5 – это фрагмент данных в формате MsgPack, означающий «32-битный заголовок массива со значением 5» (см. спецификацию на формат MsgPack). Остальные значения описаны в таблице Стандартные типы в MsgPack-кодировке.