Tarantool 2.2.1 | Tarantool
Release notes / Tarantool 2.2.1
Release notes / Tarantool 2.2.1

Tarantool 2.2.1

Tarantool 2.2.1

Tarantool 2.x is backward compatible with Tarantool 1.10.x in binary data layout, client-server protocol and replication protocol. You can upgrade using the box.schema.upgrade() procedure.

Release 2.4.1


  • (SQL) SESSION will be a reserved word so objects named SESSION will be illegal. Part of issue 4711.
  • In box.session.push() the use of the sync parameter will cause a warning in version 2.4.1 and will cause an error in later versions. Part of issue 4689.

Release 2.2.1

Release type: beta. Release date: 2019-08-02.


This is a beta version of the 2.2 series. The label “beta” means we have no critical issues and all planned features are there.

The goal of this release is to introduce new indexing features, extend SQL feature set, and improve integration with the core.

Functionality added or changed:

  • (SQL) ALTER now allows to add a constraint:

  • (SQL) CHECK constraints are validated during DML operations performed from the Lua land:

    s ='withdata')
    pk = s:create_index('pk')
    s:format({{'idx', 'number'}})
    s:create_check_constraint('le10', '"idx" < 10')
    tarantool> s:insert({11})
    - error: 'Check constraint failed ''le10'': "idx" < 10'
  • (SQL) New SQL types introduced: VARBINARY, UNSIGNED, and BOOLEAN.

  • (SQL) CREATE TABLE statement (and all other data definition statements) are now truly transactional.

  • (SQL) SQL now uses Tarantool diagnostics API to set errors, so error reporting now provides an error code in addition to error message.

  • (SQL) Multiple improvements to the type system to make it more consistent.

  • (SQL) Added aliases for LENGTH() from ANSI SQL: CHAR_LENGTH() and CHARACTER_LENGTH().

  • (SQL) It is possible to use HAVING without GROUP BY.

  • (Server) New fixed point type (DECIMAL) introduced to Tarantool:

    decimal = require('decimal')
    tarantool> a ='123.456789')
    tarantool> decimal.precision(a)
    - 9
    tarantool> decimal.scale(a)
    - 6
    tarantool> decimal.round(a, 4)
    - '123.4568'
  • (Server) Multikey index support:

    -- Multikey indexes (for memtx tree & vinyl);
    -- cannot be primary; may be non-unique
    s ='clients', {engine = 'vinyl'})
    pk = s:create_index('pk')
    phone_type = s:create_index('phone_type', {
        unique = false,
        parts = {{'[3][*].type', 'str'}}})
    s:insert({1, 'James',
             {{type = 'home', number = '999'},
              {type = 'work', number = '777'}
    s:insert({2, 'Bob',
              {{type = 'work', number = '888'}}})
    s:insert({3, 'Alice', {{type = 'home', number = '333'}}})
    tarantool> phone_type:select('work')
    - - [1, 'James', [{'type': 'home', 'number': '999'},
                      {'type': 'work', 'number': '777'}]]
      - [2, 'Bob', [{'type': 'work', 'number': '888'}]]
  • (Server) Now it is possible to make functions persistent:

                          {body = [[function(a,b) return a+b end]],
                          is_deterministic = true})
    tarantool> box.func.summarize
    - aggregate: none
      returns: any
        lua: true
        sql: false
      id: 66
      is_sandboxed: false
      setuid: false
      is_multikey: false
      is_deterministic: true
      body: function(a,b) return a+b end
      name: summarize
      language: LUA
    tarantool> box.func.summarize:call({1, 2})
    - 3
  • (Server) Functional indexes implemented:

    -- Functional multikey indexes: define is_multikey = true
    -- in function definition and return a table of keys from function
    lua_code = [[function(tuple)
                    local address = string.split(tuple[2])
                    local ret = {}
                    for _, v in pairs(address) do table.insert(ret, {utf8.upper(v)}) end
                    return ret
    box.schema.func.create('addr_extractor', {body = lua_code,
                                              is_deterministic = true,
                                              is_sandboxed = true,
                                              opts = {is_multikey = true}})
    s ='withdata')
    pk = s:create_index('name', {parts = {1, 'string'}})
    idx = s:create_index('addr', {unique = false, func =, parts = {{1, 'string', collation = 'unicode_ci'}}})
    s:insert({"James", "SIS Building Lambeth London UK"})
    s:insert({"Sherlock", "221B Baker St Marylebone London NW1 6XE UK"})
    tarantool>  idx:select('Sis')
    - - ['James', 'SIS Building Lambeth London UK']
  • Partial core dumps, which are now on by default. It is now possible to avoid dumping tuples at all during core dump.

  • Data definition statements, such as create or alter index, which do not yield, can now be used in a transaction. This in practice includes all statements except creating an index on a non-empty space, or changing a format on a non-empty space.

  • It is now possible to set a sequence not only for the first part of the index:{sequence = {field = 2}}
  • Allow to call box.session.exists() and box.session.fd() without any arguments.

  • New function introduced to get an index key from a tuple:

    s ='withdata')
    pk = s:create_index('pk')
    sk = s:create_index('sk', {parts = {
          {2, 'number', path = 'a'},
          {2, 'number', path = 'b'}}})
    s:insert{1, {a = 1, b = 1}}
    s:insert{2, {a = 1, b = 2}}
    s:insert{3, {a = 3, b = 3}}
    key_def_lib = require('key_def')
    key_def =
    for _, tuple in sk:pairs({1}) do
        local key = key_def:extract_key(tuple)
  • (Engines) New protocol (called SWIM) implemented to keep a table of cluster members.

  • (Engines) Removed yields from Vinyl DDL on commit triggers.

  • (Engines) Improved performance of SELECT-s on memtx spaces. The drawback is that now every memtx-tree tuple consumes extra 8 bytes for a search hint.

  • (Engines) Indexes of memtx spaces are now built in background fibers. This means that we do not block the event loop during index build anymore.

  • Replication applier now can apply transactions which were concurrent on the master concurrently on replica. This dramatically improves replication peak performance, from ~50K writes per second to 200K writes per second and higher on a single instance.

  • Transaction boundaries introduced to replication protocol. This means that Tarantool replication is now transaction-safe, and also reduces load on replica write ahead log in case the master uses a lot of multi-statement transactions.

  • Tuple access by field name for

    box.cfg{listen = 3302}
    box.schema.user.grant('guest','read, write, execute', 'space')
    box.schema.user.grant('guest', 'create', 'space')
    box.schema.create_space("named", {format = {{name = "id"}}})'id', {parts = {{1, 'unsigned'}}}){1})
    require('').connect('localhost', 3302).space.named:get(1).id
  • Cluster id check is now the slave’s responsibility.

  • It is now possible to set the output format to Lua instead of YAML in the interactive console.

  • Multiple new collations added. New collations follow this naming pattern:


    Three strengths are used:

    • Primary - “s1”
    • Secondary - “s2”
    • Tertiary - “s3”

    The following list contains so-called “stable” collations - the ones whose sort order doesn’t depend on the ICU version:

  • New function utime() introduced to the fio module.

  • Merger for tuples streams added.