Версия:

Вложенный модуль box.space

Вложенный модуль box.space

Общие сведения

Вложенный модуль box.space включает в себя функции по управлению данными select (выборка), insert (вставка), replace (замена), update (обновление), upsert (обновление и вставка), delete (удаление), get (получение), put (выдача). Также в модуле есть такие элементы, как id, и указание на активность спейса. Код вложенного модуля находится в файле src/box/lua/schema.lua.

Индекс

Ниже приведен перечень всех функций и элементов модуля box.space.

Имя Использование
space_object:auto_increment() Генерация ключа + вставка кортежа
space_object:bsize() Подсчет байтов
space_object:count() Подсчет кортежей
space_object:create_index() Создание индекса
space_object:delete() Удаление кортежа
space_object:drop() Удаление спейса
space_object:format() Объявление имен и типов полей
space_object:frommap() Конвертация ассоциативного массива в кортеж или таблицу
space_object:get() Выбор кортежа
space_object:insert() Вставка кортежа
space_object:len() Подсчет кортежей
space_object:on_replace() Создание триггера замены с функцией, которая не может изменять кортеж
space_object:before_replace() Создание триггера замены с функцией, которая может изменять кортеж
space_object:pairs() Подготовка к итерации
space_object:put() Вставка или замена кортежа
space_object:rename() Переименование спейса
space_object:replace() Вставка или замена кортежа
space_object:run_triggers() Включение/отключение триггера замены
space_object:select() Выбор одного или более кортежей
space_object:truncate() Удаление всех кортежей
space_object:update() Обновление кортежа
space_object:upsert() Обновление кортежа
space_object:user_defined() Любая функция / метод, которые хочет добавить любой пользователь
space_object:create_check_constraint() Create a check constraint
space_object.enabled Флаг, если спейс активен – true
space_object.field_count Необходимое количество полей
space_object.id Числовой идентификатор спейса
space_object.index Контейнер для индексов спейса
box.space._cluster (Метаданные) Список наборов реплик
box.space._func (Метаданные) Список кортежей с функциями
box.space._index (Метаданные) Список индексов
box.space._vindex (Метаданные) Список индексов, доступных текущему пользователю
box.space._priv (Метаданные) Список прав
box.space._vpriv (Метаданные) Список прав, доступных текущему пользователю
box.space._schema (Метаданные) Список схем
box.space._sequence (Метаданные) Список последовательностей
box.space._sequence_data (Метаданные) Список последовательностей
box.space._space (Метаданные) Список спейсов
box.space._vspace (Метаданные) Список спейсов, доступных текущему пользователю
box.space._user (Метаданные) Список пользователей
box.space._ck_constraint (Metadata) List of check constraints
box.space._vuser (Метаданные) Список пользователей, доступных текущему пользователю
box.space._collation (Metadata) List of collations
box.space._vcollation (Metadata) List of collations accessible for the current user
object space_object
space_object:auto_increment(tuple)

Вставка нового кортежа, используя первичный ключ с автоматическим увеличением. В спейсе, указанном через space_object должен быть первичный TREE-индекс типа „unsigned“ или „integer“, или „number“. Поле первичного ключа будет увеличиваться перед вставкой.

Данный метод объявлен устаревшим с версии 1.7.5 – лучше использовать последовательности.

Параметры:
  • space_object (space_object) – ссылка на объект
  • tuple (table/tuple) – поля кортежа, не включая поле первичного ключа
возвращается:

вставленный кортеж.

тип возвращаемого значения:
 

кортеж

Факторы сложности Размер индекса, тип индекса, количество кортежей, к которым получен доступ, настройки журнала упреждающей записи (WAL).

Возможные ошибки:

  • неподходящий тип индекса;
  • проиндексированное поле первичного ключа не является числовым.

Пример:

tarantool> box.space.tester:auto_increment{'Fld#1', 'Fld#2'}
---
- [1, 'Fld#1', 'Fld#2']
...
tarantool> box.space.tester:auto_increment{'Fld#3'}
---
- [2, 'Fld#3']
...
space_object:bsize()
Параметры:
возвращается:

Количество байтов в спейсе. Это число, которое хранится во внутренней памяти Tarantool’а, представляет собой общее количество байтов во всех кортежах, включая ключи индекса. Для получения информации об измерении размера индекса, см. index_object:bsize().

Пример:

tarantool> box.space.tester:bsize()
---
- 22
...
space_object:count([key][, iterator])

Возврат количества кортежей. Если сравнивать с len(), то данный метод работает медленнее, поскольку метод count() сканирует весь спейс для подсчета кортежей.

Параметры:
  • space_object (space_object) – ссылка на объект
  • key (scalar/table) – значения поля первичного ключа, которые должны возвращаться в виде Lua-таблицы, если ключ составной
  • iterator – метод сопоставления
возвращается:

Количество кортежей.

Пример:

tarantool> box.space.tester:count(2, {iterator='GE'})
---
- 1
...
space_object:create_index(index-name[, options])

Создание индекса. Индекс обязательно должен создаваться для спейса до вставки в него кортежей или выборки. Первый созданный индекс, который будет использоваться в качестве первичного индекса, должен быть уникальным.

Параметры:
возвращается:

объект индекса

тип возвращаемого значения:
 

объект индекса

Параметры для space_object:create_index()

Имя Эффект Type Значение по умолчанию
type тип индекса строка („HASH“ или „TREE“, или „BITSET“, или „RTREE“) Примечание про движок базы данных: vinyl поддерживает только „TREE“ „TREE“
id уникальный идентификатор число идентификатор последнего индекса +1
unique индекс уникален boolean (логический) true (правда)
if_not_exists (если отсутствует) ошибки нет, если имя дублируется boolean (логический) false (ложь)
parts номера поля + типы {field_no, 'unsigned' or 'string' or 'integer' or 'number' or 'boolean' or 'varbinary' or 'array' or 'scalar', and optional collation or is_nullable value or path} {field = 1, type = 'unsigned'}
dimension только для RTREE число 2
distance только для RTREE строка („euclid“ или „manhattan“) „euclid“ (Евклидова)
bloom_fpr только для vinyl число vinyl_bloom_fpr
page_size только для vinyl число vinyl_page_size
range_size только для vinyl число vinyl_range_size
run_count_per_level только для vinyl число vinyl_run_count_per_level
run_size_ratio только для vinyl число vinyl_run_size_ratio
sequence см. раздел об указании последовательности для create_index() строка или число отсутствует
func functional index string (строка) отсутствует

Параметры в вышеуказанной таблице также применимы к index_object:alter().

Примечание про движок базы данных: в vinyl’е есть дополнительные параметры, которые по умолчанию основаны на конфигурационных параметрах vinyl_bloom_fpr, vinyl_page_size, vinyl_range_size, vinyl_run_count_per_level и vinyl_run_size_ratio – см. описание этих параметров. Текущие значения можно увидеть, сделав выборку из box.space._index.

Building or rebuilding a large index will cause occasional yields so that other requests will not be blocked. If the other requests cause an illegal situation such as a duplicate key in a unique index, the index building or rebuilding will fail.

Возможные ошибки:

  • слишком много частей;
  • индекс „…“ уже существует;
  • первичный ключ должен быть уникальным.
tarantool> s = box.space.tester
---
...
tarantool> s:create_index('primary', {unique = true, parts = {field = 1, type = 'unsigned', field = 2, type = 'string'}})
---
...

Подробнее о типах полей индекса:

The eight index field types (unsigned | string | integer | number | boolean | varbinary | array | scalar) differ depending on what values are allowed, and what index types are allowed.

  • unsigned: беззнаковые целые числа от 0 до 18 446 744 073 709 551 615, т.е. около18 квинтиллионов. Также может называться „uint“ или „num“, но „num“ объявлен устаревшим. Используется в индексах типа TREE или HASH в memtx’е, и в TREE-индексах в vinyl’е.
  • string: строка, то есть любая последовательность октетов до максимальной длины. Также может называться „str“. Используется в индексах типа TREE, HASH или BITSET в memtx’е и в TREE-индексах в vinyl’е. В строке может быть сортировка.
  • integer: целые числа от -9 223 372 036 854 775 808 до 18 446 744 073 709 551 615. Также может называться „int“. Используется в индексах типа TREE или HASH в memtx’е и в TREE-индексах в vinyl’е.
  • number: целые числа от -9 223 372 036 854 775 808 до 18 446 744 073 709 551 615, числа с плавающей запятой с одинарной точностью или с двойной точностью. Используется в индексах типа TREE или HASH в memtx’е и в TREE-индексах в vinyl’е.
  • boolean: логическое значение, true (правда) или false (ложь). Используется в индексах типа TREE или HASH в memtx’е и в TREE-индексах в vinyl’е.
  • varbinary: any set of octets, up to the maximum length. Legal in memtx TREE or HASH indexes, and in vinyl TREE indexes. A varbinary byte sequence does not have a collation because its contents are not UTF-8 characters.
  • array: массив чисел. Используется в RTREE-индексах в memtx’е.
  • scalar: нулевое значение null (ввод msgpack.NULL, yaml.NULL или json.NULL), логические значения (true или false), целые числа от integers between -9 223 372 036 854 775 808 до 18 446 744 073 709 551 615, числа с плавающей запятой с одинарной точностью или с двойной точностью или строки. При использовании нескольких типов порядок ключей должен быть следующим: нулевое значение, затем логические значения, затем числа, затем строки. Используется в индексах типа TREE или HASH в memtx’е и в TREE-индексах в vinyl’е.

Кроме того, допускается нулевое значение nil для любого типа поля, если указана такая возможность is_nullable=true.

Типы полей в индексах для использования в space_object:create_index()

Тип поля для индексирования Чем может быть Где может использоваться Примеры
unsigned целые числа от 0 до 18 446 744 073 709 551 615 индексы типа TREE или HASH в memtx’е,
TREE-индексы в vinyl’е
123456
string строки – любой набор октетов индексы типа TREE или HASH в memtx’е
TREE-индексы в vinyl’е
„A B C“
„\65 \66 \67“
varbinary byte sequences – any set of octets индексы типа TREE или HASH в memtx’е
TREE-индексы в vinyl’е
„\65 \66 \67“
integer целые числа от -9 223 372 036 854 775 808 до 18 446 744 073 709 551 615 индексы типа TREE или HASH в memtx’е,
TREE-индексы в vinyl’е
-2^63
number целые числа от -9 223 372 036 854 775 808 до 18 446 744 073 709 551 615, числа с плавающей запятой с одинарной точностью или с двойной точностью индексы типа TREE или HASH в memtx’е,
TREE-индексы в vinyl’е
1.234
-44
1.447e+44
boolean true или false индексы типа TREE или HASH в memtx’е,
TREE-индексы в vinyl’е
false
true
array массив целых чисел от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 RTREE-индексы в memtx’е {10, 11}
{3, 5, 9, 10}
scalar нулевое значение, логические значения (true или false), целые числа от -9 223 372 036 854 775 808 до 18 446 744 073 709 551 615, числа с плавающей запятой с одинарной точностью или с двойной точностью, строки индексы типа TREE или HASH в memtx’е,
TREE-индексы в vinyl’е
null
true
-1
1.234
„“
„ру“

Разрешение использования нулевых значений для индексируемого ключа: /Если тип индекса – TREE, и индекс не является первичным, то оператор parts={...} может включать в себя is_nullable=true или is_nullable=false (по умолчанию). Если значение параметра is_nullable – true, то можно вставлять nil или аналогичное значение, например msgpack.NULL (или можно не вставлять вообще ничего в завершающие ненулевые поля). В рамках индекса такие нулевые значения считаются равными другим нулевым значениям и всегда меньше ненулевых значений. Нулевые значения могут встречаться несколько раз даже в уникальном индексе. Например:

box.space.tester:create_index('I',{unique=true,parts={{field = 2, type = 'number', is_nullable = true}}})

Предупреждение

Можно создать множество индексов для одного и того же поля с различными значениями is_nullable или вызвать space_object:format() со значением is_nullable, отличным от используемого для индекса. При наличии несоответствий правило такое: запрещается использовать null кроме случаев, когда is_nullable=true для всех индексов и формата спейса.

Использование имен полей вместо номеров полей: в create_index() можно использовать имена полей и/или типы полей, описанные в необязательном операторе space_object:format(). В следующем примере покажем format() для спейса с двумя столбцами под названиями „x“ и „y“, а затем покажем пять вариантов оператора parts={} в create_index(), сначала для столбца „x“, затем для столбцов „x“ и „y“. Варианты включают в себя пропуск типа, использование номеров и добавление дополнительных фигурных скобок.

box.space.tester:format({{name='x', type='scalar'}, {name='y', type='integer'}})
box.space.tester:create_index('I2',{parts={{'x', 'scalar'}}})
box.space.tester:create_index('I3',{parts={{'x','scalar'},{'y','integer'}}})
box.space.tester:create_index('I4',{parts={1,'scalar'}})
box.space.tester:create_index('I5',{parts={1,'scalar',2,'integer'}})
box.space.tester:create_index('I6',{parts={1}})
box.space.tester:create_index('I7',{parts={1,2}})
box.space.tester:create_index('I8',{parts={'x'}})
box.space.tester:create_index('I9',{parts={'x','y'}})
box.space.tester:create_index('I10',{parts={{'x'}}})
box.space.tester:create_index('I11',{parts={{'x'},{'y'}}})

Using the path option for map fields: To create an index for a field that is a map (a path string and a scalar value), specify the path string during index_create, that is, parts={ field-number,'data-type',path = 'path-name' }. The index type must be 'tree' or 'hash' and the field’s contents must always be maps with the same path.

-- Example 1 -- The simplest use of path:
-- Result will be - - [{'age': 44}]
box.schema.space.create('T')
box.space.T:create_index('I',{parts={{field = 1, type = 'scalar', path = 'age'}}})
box.space.T:insert{{age=44}}
box.space.T:select(44)
-- Example 2 -- path plus format() plus JSON syntax to add clarity
-- Result will be: - [1, {'FIO': {'surname': 'Xi', 'firstname': 'Ahmed'}}]
s = box.schema.space.create('T')
format = {{'id', 'unsigned'}, {'data', 'map'}}
s:format(format)
parts = {{'data.FIO["firstname"]', 'str'}, {'data.FIO["surname"]', 'str'}}
i = s:create_index('info', {parts = parts})
s:insert({1, {FIO={firstname='Ahmed', surname='Xi'}}})

Примечание про движок базы данных: vinyl поддерживает только TREE-индексы, и следует создать в vinyl’е вторичные индексы до вставки кортежей.

Using the path option with [*] The string in a path option can contain „[*]“ which is called an array index placeholder. Indexes defined with this are useful for JSON documents that all have the same structure. For example, when creating an index on field#2 for a string document that will start with {'data': [{'name': '...'}, {'name': '...'}], the parts section in the create_index request could look like: parts = {{field = 2, type = 'str', path = 'data[*].name'}}. Then tuples containing names can be retrieved quickly with index_object:select({key-value}). In fact a single field can have multiple keys, as in this example which retrieves the same tuple twice because there are two keys „A“ and „B“ which both match the request:

s = box.schema.space.create('json_documents')
s:create_index('primarykey')
i = s:create_index('multikey', {parts = {{field = 2, type = 'str', path = 'data[*].name'}}})
s:insert({1,
         {data = {{name='A'},
                  {name='B'}},
          extra_field = 1}})
i:select({''},{iterator='GE'})
--  The result of the select request looks like this:
--  tarantool> i:select({''},{iterator='GE'})
--  ---
--  - - [1, {'data': [{'name': 'A'}, {'name': 'B'}], 'extra_field': 1}]
--    - [1, {'data': [{'name': 'A'}, {'name': 'B'}], 'extra_field': 1}]
--  ...

Some restrictions exist: () „[*]“ must be alone or must be at the end of a name in the path; () „[*]“ must not appear twice in the path; () if an index has a path with x[*] then no other index can have a path with x.component; () „[*]“ must not appear in the path of a primary-key ; () if an index has unique=true and has a path with „[*]“ then duplicate keys from different tuples are disallowed but duplicate keys for the same tuple are allowed; () As with Using the path option for map fields, the field’s value must have the structure that the path definition implies, or be nil (nil is not indexed).

Making a functional index with space_object:create_index()

Functional indexes are indexes that call a user-defined function for forming the index key, rather than depending entirely on the Tarantool default formation. Functional indexes are useful for condensing or truncating or reversing or any other way that users want to customize the index.

The function definition must expect a tuple (which has the contents of fields at the time a data-change request happens) and must return a tuple (which has the contents that will actually be put in the index).

The space must have a memtx engine.
The function must be persistent and deterministic.
The key parts must not depend on JSON paths.
The create_index definition must include specification of all key parts, and the function must return a table which has the same number of key parts with the same types.
The function must access key-part values by index, not by field name.
Functional indexes must not be primary-key indexes.
Functional indexes cannot be altered and the function cannot be changed if it is used for an index, so the only way to change them is to drop the index and create it again.

Пример:

A function could make a key using only the first letter of a string field.

-- Step 1: Make the space.
-- The space needs a primary-key field, which is not the field that we
-- will use for the functional index.
box.schema.space.create('x', {engine = 'memtx'})
box.space.x:create_index('i',{parts={field = 1, type = 'string'}})
-- Step 2: Make the function.
-- The function expects a tuple. In this example it will work on tuple[2]
-- because the key souce is field number 2 in what we will insert.
-- Use string.sub() from the string module to get the first character.
lua_code = [[function(tuple) return {string.sub(tuple[2],1,1)} end]]
-- Step 3: Make the function persistent.
-- Use the box.schema.func.create function for this.
box.schema.func.create('F',
    {body = lua_code, is_deterministic = true, is_sandboxed = true})
-- Step 4: Make the functional index.
-- Specify the fields whose values will be passed to the function.
-- Specify the function.
box.space.x:create_index('j',{parts={field = 1, type = 'string'},func = 'F'})
-- Step 5: Test.
-- Insert a few tuples.
-- Select using only the first letter, it will work because that is the key
-- Or, select using the same function as was used for insertion
box.space.x:insert{'a', 'wombat'}
box.space.x:insert{'b', 'rabbit'}
-- Select using only the first letter, it will work because that is the key
-- Or, select using the same function as was used for insertion
box.space.x:insert{'a', 'wombat'}
box.space.x:insert{'b', 'rabbit'}
box.space.x.index.j:select('w')
box.space.x.index.j:select(box.func.F:call({{'x', 'wombat'}}));

The results of the two select requests will look like this:

tarantool>     box.space.x.index.j:select('w')
---
- - ['a', 'wombat']
...

tarantool>     box.space.x.index.j:select(box.func.F:call({{'x','wombat'}}));
---
- - ['a', 'wombat']
...

Functions for functional indexes can return multiple keys.
Such functions are called «multikey» functions.
The box.func.create options must include opts = {is_multikey = true}.
The return value must be a table of tuples.
If a multikey function returns N tuples, then N keys will be added to the index.

Пример:

s = box.schema.space.create('withdata')
s:format({{name = 'name', type = 'string'},
          {name = 'address', type = 'string'}})
pk = s:create_index('name', {parts = {field = 1, type = 'string'}})
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
             end]]
box.schema.func.create('address',
                        {body = lua_code,
                         is_deterministic = true,
                         is_sandboxed = true,
                         opts = {is_multikey = true}})
idx = s:create_index('addr', {unique = false,
                              func = 'address',
                              parts = {{field = 1, type = 'string',
                                      collation = 'unicode_ci'}}})
s:insert({"James", "SIS Building Lambeth London UK"})
s:insert({"Sherlock", "221B Baker St Marylebone London NW1 6XE UK"})
idx:select('Uk')
-- Both tuples will be returned.
space_object:delete(key)

Удаление кортежа по первичному ключу.

Параметры:
  • space_object (space_object) – ссылка на объект
  • key (scalar/table) – значения поля первичного ключа, которые должны возвращаться в виде Lua-таблицы, если ключ составной
возвращается:

удаленный кортеж.

тип возвращаемого значения:
 

кортеж

Факторы сложности: Размер индекса, тип индекса

Примечание про движок базы данных: vinyl вернет nil, а не удаленный кортеж.

Пример:

tarantool> box.space.tester:delete(1)
---
- [1, 'My first tuple']
...
tarantool> box.space.tester:delete(1)
---
...
tarantool> box.space.tester:delete('a')
---
- error: 'Supplied key type of part 0 does not match index part type:
  expected unsigned'
...

Для получения дополнительной информации о сценариях использования и типичных ошибках, см. Пример: использование операций с данными далее в разделе.

space_object:drop()

Удаление спейса.

Параметры:
возвращается:

nil

Возможные ошибки: space_object не существует.

Факторы сложности Размер индекса, тип индекса, количество кортежей, к которым получен доступ, настройки журнала упреждающей записи (WAL).

Пример:

box.space.space_that_does_not_exist:drop()
space_object:format([format-clause])

Объявление имен и типов полей.

Параметры:
возвращается:

nil, если не указан оператор формата

Возможные ошибки:

  • space_object не существует,
  • дублируются имена полей;
  • тип не поддерживается.

Как правило, Tarantool допускает поля без имен и без указания типа. Но с помощью format можно, например, задокументировать, что N-ное поле представляет собой поле для фамилии и должно содержать строковое значение. Также оператор формата можно указать в box.schema.space.create().

Оператор формата для каждого поля содержит определение в фигурных скобках: {name='...',type='...'[,is_nullable=...]}, где:

В кортежах недопустимы значения неправильного типа; например, после box.space.tester:format({{' ',type='number'}}) (тип = число) запрос box.space.tester:insert{'строка-которая-не-является-числом'} вызовет ошибку.

В кортежах недопустимы нулевые значения, если is_nullable=false, что задано по умолчанию; например, после box.space.tester:format({{' ',type='number',is_nullable=false}}) запрос box.space.tester:insert{nil,2} вызовет ошибку.

В кортежах может быть больше полей, чем описано в операторе формата. Чтобы ограничить количество полей, необходимо указать элемент спейса field_count.

В кортежах может быть меньше полей, чем описано в операторе формата, если пропущенные завершающие поля описаны с помощью is_nullable=true; например после box.space.tester:format({{'a',type='number'},{'b',type='number',is_nullable=true}}) запрос box.space.tester:insert{2} не приведет к ошибке формата.

Можно использовать format для спейса, в котором уже определен формат, заменяя таким образом предыдущие определения при условии, что нет конфликта с существующими данными или определениями индекса.

Можно использовать format для того, чтобы изменить значение флага is_nullable; например, после box.space.tester:format({{' ',type='scalar',is_nullable=false}}) запрос box.space.tester:format({{' ',type='scalar',is_nullable=true}}) не вызовет ошибку – и не приведет к перестроению спейса. Но обратное изменение значения is_nullable с true на false может вызвать перестроение и привести к ошибке, если уже есть кортежи с нулевыми значениями.

Пример:

box.space.tester:format({{name='surname',type='string'},{name='IDX',type='array'}})
box.space.tester:format({{name='surname',type='string',is_nullable=true}})

Можно использовать следующие варианты оператора:

  • пропуск и „name=“, и „type=“,
  • пропуск „type=“ и
  • добавление дополнительных фигурных скобок.

В следующем примере иллюстрируются все варианты, первый для поля с именем „x“, второй – для двух полей с именами „x“ и „y“.

box.space.tester:format({{'x'}})
box.space.tester:format({{'x'},{'y'}})
box.space.tester:format({{name='x',type='scalar'}})
box.space.tester:format({{name='x',type='scalar'},{name='y',type='unsigned'}})
box.space.tester:format({{name='x'}})
box.space.tester:format({{name='x'},{name='y'}})
box.space.tester:format({{'x',type='scalar'}})
box.space.tester:format({{'x',type='scalar'},{'y',type='unsigned'}})
box.space.tester:format({{'x','scalar'}})
box.space.tester:format({{'x','scalar'},{'y','unsigned'}})

В следующем примере показывается создание спейса, определение формата для него со всеми возможными типа и вставка данных.

tarantool> box.schema.space.create('t')
--- ...
tarantool> box.space.t:format({{name='1',type='any'},
         >                     {name='2',type='unsigned'},
         >                     {name='3',type='string'},
         >                     {name='4',type='number'},
         >                     {name='5',type='integer'},
         >                     {name='6',type='boolean'},
         >                     {name='7',type='scalar'},
         >                     {name='8',type='array'},
         >                     {name='9',type='map'}})
--- ...
tarantool> box.space.t:create_index('i',{parts={field = 2, type = 'unsigned'}})
--- ...
tarantool> box.space.t:insert{{'a'},      -- any
         >                    1,          -- unsigned
         >                    'W?',       -- string
         >                    5.5,        -- number
         >                    -0,         -- integer
         >                    true,       -- boolean
         >                    true,       -- scalar
         >                    {{'a'}},    -- array
         >                    {val=1}}    -- map
---
- [['a'], 1, 'W?', 5.5, 0, true, true, [['a']], {'val': 1}]
...

Имена, указанные с помощью оператора формата, можно использовать в space_object:get(), в space_object:create_index(), в tuple_object[field-name] и в tuple_object[field-path].

Если оператор формата не указан, то вернется таблица, которая использовалась при предыдущем вызове объект-спейса:format(оператор-формата). Например, после box.space.tester:format({{'x','scalar'}}), box.space.tester:format() вернет [{'name': 'x', 'type': 'scalar'}].

Formatting or reformatting a large space will cause occasional yields so that other requests will not be blocked. If the other requests cause an illegal situation such as a field value of the wrong type, the formatting or reformatting will fail.

space_object:frommap(map[, option])

Конвертация ассоциативного массива в экземпляр кортежа или в таблицу. Ассоциативный массив должен состоять из пар «имя поля = значение». Имена полей и типы значений должны соответствовать именам и типам, ранее заданным для спейса через space_object:format().

Параметры:
  • space_object (space_object) – ссылка на объект
  • map (field-value-pairs) – ряд пар «поле = значение» в любом порядке.
  • option (boolean) – единственный возможный параметр {table = true|false};
    если параметр не указан, или же {table = false}, то возвращается „cdata“ (то есть кортеж);
    если {table = true}, то возвращается таблица.
возвращается:

кортеж или таблица.

тип возвращаемого значения:
 

кортеж или таблица

Возможные ошибки: отсутствует объект спейса space_object, или в спейсе нет формата; «unknown field» (неизвестное поле).

Пример:

-- Создание формата с двумя полями под названиями 'a' и 'b'.
-- Создание спейса с таким форматом.
-- Создание кортежа на основе ассоциативного массива по данному спейсу.
-- Создание таблицы на основе ассоциативного массива по данному спейсу.
tarantool> format1 = {{name='a',type='unsigned'},{name='b',type='scalar'}}
---
...
tarantool> s = box.schema.create_space('test', {format = format1})
---
...
tarantool> s:frommap({b = 'x', a = 123456})
---
- [123456, 'x']
...
tarantool> s:frommap({b = 'x', a = 123456}, {table = true})
---
- - 123456
  - x
...
space_object:get(key)

Поиск кортежа в данном спейсе.

Параметры:
  • space_object (space_object) – ссылка на объект
  • key (scalar/table) – значение должно совпасть с индексным ключом, который может быть составным.
возвращается:

кортеж, ключ индекса в котором совпадает с key или nil.

тип возвращаемого значения:
 

кортеж

Возможные ошибки: space_object не существует.

Факторы сложности Размер индекса, тип индекса, количество кортежей, к которым получен доступ, настройки журнала упреждающей записи (WAL).

Функция box.space...select вернет набор кортежей в виде Lua-таблицы; функция box.space...get вернет самое большее один кортеж. Можно получить первый кортеж в спейсе, добавив [1]. Таким образом, box.space.tester:get{1} эквивалентна box.space.tester:select{1}[1], если найден только один кортеж.

Пример:

box.space.tester:get{1}

Using field names instead of field numbers: get() can use field names described by the optional space_object:format() clause. This is true because the object returned by get() can be used with most of the features described in the Submodule box.tuple description, including tuple_object[field-name].

For example, we can format the tester space with a field named x and use the name x in the index definition:

box.space.tester:format({{name='x',type='scalar'}})
box.space.tester:create_index('I',{parts={'x'}})

Then, if get or select retrieves a single tuple, we can reference the field „x“ in the tuple by its name:

box.space.tester:get{1}['x']
box.space.tester:select{1}[1]['x']
space_object:insert(tuple)

Вставка кортежа в спейс.

Параметры:
возвращается:

вставленный кортеж

тип возвращаемого значения:
 

кортеж

Possible errors: ER_TUPLE_FOUND if a tuple with the same unique-key value already exists.

Пример:

tarantool> box.space.tester:insert{5000,'tuple number five thousand'}
---
- [5000, 'tuple number five thousand']
...

Для получения дополнительной информации о сценариях использования и типичных ошибках, см. Пример: использование операций с данными далее в разделе.

space_object:len()

Возврат количества кортежей в спейсе. Если сравнивать с count(), то данный метод работает быстрее, поскольку метод len() не сканирует весь спейс для подсчета кортежей.

Параметры:
возвращается:

Количество кортежей в спейсе.

Пример:

tarantool> box.space.tester:len()
---
- 2
...

Note re storage engine: vinyl supports len() but the result may be approximate. If an exact result is necessary then use count() or pairs():length().

space_object:on_replace([trigger-function[, old-trigger-function]])

Создание «триггера замены». Функция с триггером trigger-function будет выполняться в случае операции replace() или insert(), или update(), или upsert(), или delete() над кортежем в спейсе <space-name>.

Параметры:
  • trigger-function (function) – function which will become the trigger function; see Example #2 below for details about trigger function parameters
  • old-trigger-function (function) – существующая функция с триггером, которую заменит новая trigger-function
возвращается:

nil или указатель функции

Если указаны параметры (nil, old-trigger-function), старый триггер будет удален.

If both parameters are omitted, then the response is a list of existing trigger functions.

Следует знать, что если активация триггера произошла в случае репликации или определенного вида подключения, функция может ссылаться на box.session.type().

Подробная информация о характеристиках триггера находится в разделе Триггеры.

См. также space_object:before_replace().

Пример №1:

tarantool> function f ()
         >   x = x + 1
         > end
tarantool> box.space.X:on_replace(f)

Примеры:

The trigger-function can have up to four parameters:

  • (tuple) old value which has the contents before the request started,
  • (tuple) new value which has the contents after the request ended,
  • (string) space name,
  • (string) type of request which is „INSERT“, „DELETE“, „UPDATE“, or „REPLACE“.

For example, the following code causes nil and „INSERT“ to be printed when the insert request is processed, and causes [1, „Hi“] and „DELETE“ to be printed when the delete request is processed:

box.schema.space.create('space_1')
box.space.space_1:create_index('space_1_index',{})
function on_replace_function (old, new, s, op) print(old) print(op) end
box.space.space_1:on_replace(on_replace_function)
box.space.space_1:insert{1,'Hi'}
box.space.space_1:delete{1}

Example #3:

Следующая серия запросов создаст спейс, создаст индекс, создаст функцию, которая увеличит содержимое счетчика, создаст триггер, сделает две вставки, удалит спейс и отобразит значение счетчика – 2, поскольку функция выполняется однократно после каждой вставки.

tarantool> s = box.schema.space.create('space53')
tarantool> s:create_index('primary', {parts = {field = 1, type = 'unsigned'}})
tarantool> function replace_trigger()
         >   replace_counter = replace_counter + 1
         > end
tarantool> s:on_replace(replace_trigger)
tarantool> replace_counter = 0
tarantool> t = s:insert{1, 'First replace'}
tarantool> t = s:insert{2, 'Second replace'}
tarantool> s:drop()
tarantool> replace_counter
space_object:before_replace([trigger-function[, old-trigger-function]])

Создание «триггера замены». Функция с триггером trigger-function будет выполняться в случае операции replace() или insert(), или update(), или upsert(), или delete() над кортежем в спейсе <space-name>.

Параметры:
  • trigger-function (function) – function which will become the trigger function; for the trigger function’s optional parameters see the description of on_replace.
  • old-trigger-function (function) – существующая функция с триггером, которую заменит новая trigger-function
возвращается:

nil или указатель функции

Если указаны параметры (nil, old-trigger-function), старый триггер будет удален.

If both parameters are omitted, then the response is a list of existing trigger functions.

Следует знать, что если активация триггера произошла в случае репликации или определенного вида подключения, функция может ссылаться на box.session.type().

Подробная информация о характеристиках триггера находится в разделе Триггеры.

См. также space_object:on_replace().

Администраторы могут создавать триггеры замены с условием после замены on_replace() или до замены before_replace(). Если созданы оба типа, то все триггеры до замены before_replace выполняются до всех триггеров после замены on_replace. Функции для обоих типов триггеров on_replace и before_replace могут вносить изменения в базу данных, гл только функции с триггерами до замены before_replace могут изменять кортеж, который будет заменен.

Поскольку функция с триггером до замены before_replace может вносить дополнительные изменения в старый кортеж, для нее также потребуются дополнительные ресурсы для вызова старого кортежа до внесения изменений. Таким образом, лучше использовать триггер после замены on_replace, если нет необходимости изменять старый кортеж. Тем не менее, это применимо только к движку memtx – что касается движка vinyl, такой вызов произойдет для любого типа триггера. (В memtx’е данные кортежа хранятся вместе с ключом индекса, поэтому нет необходимости в дополнительном поиске; для vinyl’а дело обстоит иначе, поэтому нужен дополнительный поиск.)

Если нет необходимости в дополнительных изменениях, следует использовать on_replace вместо before_replace. Как правило, before_replace используется только для определенных сценариев репликации – в части разрешения конфликтов.

Что случится после возврата значения, которое может вернуть функция с триггером before_replace, зависит от этого значения. А именно:

  • если нет возвращаемого значения, выполнение продолжается со вставкой|заменой нового значения;
  • если значение – nil, то кортеж будет удален;
  • если значение совпадает со старым, то вызывается функция on_replace, и изменение данных не происходит
  • если значение совпадает с новым, то считаем, что вызова функции before_replace не было;
  • если значение другое, выполнение продолжается со вставкой|заменой нового значения.

Тем не менее, если функция с триггером возвращает старый кортеж или вызывает run_triggers(false), это не повлияет на другие триггеры, активируемые в том же запросе вставки, обновления или замены.

Пример:

Далее представлены функции before_replace: не возвращает значение, возвращает nil, возвращает совпадающее со старым значение, возвращает совпадающее с новым значение, возвращает другое значение.

function f1 (old, new) return end
function f2 (old, new) return nil end
function f3 (old, new) return old end
function f4 (old, new) return new end
function f5 (old, new) return box.tuple.new({new[1],'b'}) end
space_object:pairs([key[, iterator]])

Поиск кортежа или набора кортежей в заданном спейсе и итерация по одному кортежу за раз.

Параметры:
  • space_object (space_object) – ссылка на объект
  • key (scalar/table) – значение должно совпасть с индексным ключом, который может быть составным
  • iterator – см. index_object:pairs
возвращается:

итератор, который может использовать в цикле for/end или с функцией totable()

Возможные ошибки:

  • отсутствие такого спейса.
  • неправильный тип.

Факторы сложности: Размер индекса, тип индекса.

Чтобы посмотреть примеры сложных запросов pairs, где можно указать индекс для поиска и используемое условие (например, «больше чем» вместо «равен»), см. раздел далее по тексту index_object:pairs.

For information about iterators“ internal structures see the «Lua Functional library» documentation.

Пример:

tarantool> s = box.schema.space.create('space33')
---
...
tarantool> -- в индексе 'X' количество частей по умолчанию {1, 'unsigned'}
tarantool> s:create_index('X', {})
---
...
tarantool> s:insert{0, 'Hello my '}, s:insert{1, 'Lua world'}
---
- [0, 'Hello my ']
- [1, 'Lua world']
...
tarantool> tmp = ''
---
...
tarantool> for k, v in s:pairs() do
         >   tmp = tmp .. v[2]
         > end
---
...
tarantool> tmp
---
- Hello my Lua world
...
space_object:rename(space-name)

Переименование спейса.

Параметры:
возвращается:

nil

Возможные ошибки: space_object не существует.

Пример:

tarantool> box.space.space55:rename('space56')
---
...
tarantool> box.space.space56:rename('space55')
---
...
space_object:replace(tuple)
space_object:put(tuple)

Вставка кортежа в спейс. Если уже существует кортеж с тем же первичным ключом, box.space...:replace() заменит существующий кортеж новым. Варианты синтаксиса (box.space...:replace() и box.space...:put()) приведут к одному результату, но последний иногда используется как противоположность box.space...:get().

Параметры:
возвращается:

вставленный кортеж.

тип возвращаемого значения:
 

кортеж

Possible errors: ER_TUPLE_FOUND if a different tuple with the same unique-key value already exists. (This will only happen if there is a unique secondary index.)

Факторы сложности Размер индекса, тип индекса, количество кортежей, к которым получен доступ, настройки журнала упреждающей записи (WAL).

Пример:

box.space.tester:replace{5000, 'tuple number five thousand'}

Для получения дополнительной информации о сценариях использования и типичных ошибках, см. Пример: использование операций с данными далее в разделе.

space_object:run_triggers(true|false)

На тот момент, когда триггер определен, он автоматически активируется, то есть он будет исполняться. Триггеры для замены можно отключить с помощью box.space.имя-спейса:run_triggers(false) и повторно активировать с помощью box.space.имя-спейса:run_triggers(true).

возвращается:nil

Пример:

Следующая серия запросов ассоциирует существующую функцию с именем F с существующим спейсом с именем T, ассоциирует функцию во второй раз с тем же спейсом (чтобы вызвать ее дважды), отключит все триггеры на T и удалит каждый триггер, заменив его на nil.

tarantool> box.space.T:on_replace(F)
tarantool> box.space.T:on_replace(F)
tarantool> box.space.T:run_triggers(false)
tarantool> box.space.T:on_replace(nil, F)
tarantool> box.space.T:on_replace(nil, F)
space_object:select([key[, options]])

Поиск кортежа или набора кортежей в заданном спейсе.

Параметры:
  • space_object (space_object) – ссылка на объект
  • key (scalar/table) – значение должно совпасть с индексным ключом, который может быть составным.
  • options (table/nil) – ни один, любой или все параметры, которые допускает index_object:select: * options.iterator (тип итератора) * options.limit (максимальное количество кортежей) * options.offset (количество пропускаемых кортежей)
возвращается:

кортежи, поля первичного ключа в которых равны полям переданного ключа. Если количество переданных полей меньшей количества полей первичного ключа, сопоставляются только переданные поля, то есть для select{1,2} совпадением будет кортеж с первичным ключом {1,2,3}.

тип возвращаемого значения:
 

массив кортежей

Запрос выборки select также можно выполнить со специальными параметрами индекса, которые указаны в index_object:select.

Возможные ошибки:

  • отсутствие такого спейса.
  • неправильный тип.

Факторы сложности: Размер индекса, тип индекса.

Пример:

tarantool> s = box.schema.space.create('tmp', {temporary=true})
---
...
tarantool> s:create_index('primary',{parts = {field = 1, type = 'unsigned', field = 2, type = 'string'}})
---
...
tarantool> s:insert{1,'A'}
---
- [1, 'A']
...
tarantool> s:insert{1,'B'}
---
- [1, 'B']
...
tarantool> s:insert{1,'C'}
---
- [1, 'C']
...
tarantool> s:insert{2,'D'}
---
- [2, 'D']
...
tarantool> -- must equal both primary-key fields
tarantool> s:select{1,'B'}
---
- - [1, 'B']
...
tarantool> -- must equal only one primary-key field
tarantool> s:select{1}
---
- - [1, 'A']
  - [1, 'B']
  - [1, 'C']
...
tarantool> -- must equal 0 fields, so returns all tuples
tarantool> s:select{}
---
- - [1, 'A']
  - [1, 'B']
  - [1, 'C']
  - [2, 'D']
...
tarantool> -- the first field must be greater than 0, and
tarantool> -- skip the first tuple, and return up to
tarantool> -- 2 tuples. This example's options all
tarantool> -- depend on index characteristics so see
tarantool> -- more explanation in index_object:select().
tarantool> s:select({0},{iterator='GT',offset=1,limit=2})
---
- - [1, 'B']
  - [1, 'C']
...

Как показано в последнем запросе вышеприведенного примера, чтобы выполнять сложные запросы выборки select, где можно указать, в каком индексе производится поиск и с какими условиями (например, «больше, чем» вместо «равный»), а также необходимое количество возвращаемых кортежей, необходимо ознакомиться с index_object:select.

Для получения дополнительной информации о сценариях использования и типичных ошибках, см. Пример: использование операций с данными далее в разделе.

space_object:truncate()

Удаление всех кортежей.

Параметры:

Факторы сложности: Размер индекса, тип индекса, количество кортежей, к которым получен доступ.

возвращается:nil

Метод truncate может вызвать только тот пользователь, который создал спейс, или другой пользователь через функцию setuid, созданную пользователем, который создал спейс. Более подробную информацию о функциях setuid можно получить в справочнике по for box.schema.func.create().

Метод truncate нельзя вызвать из транзакции.

Пример:

tarantool> box.space.tester:truncate()
---
...
tarantool> box.space.tester:len()
---
- 0
...
space_object:update(key, {{operator, field_no, value}, ...})

Обновление кортежа.

Функция update поддерживает операции над полями – присваивание, арифметические операции (если поле числовое), вырезание и вставку фрагментов поля, удаление или вставку поля. Несколько операций можно объединить в отдельный запрос обновления, и в таком случае они будут выполняться атомарно и последовательно. Для каждой операции необходимо указать номер поля. Если выполняются несколько операций, то номер поля для каждой операции считается относительно последнего состояния кортежа, то есть как если бы все предыдущие операции в обновлении с несколькими операциями уже были выполнены. Другими словами, всегда лучше объединить несколько вызовов update в один без изменений семантики.

Возможные операторы:

  • + для сложения (значения должны быть числовыми)
  • - для вычитания (значения должны быть числовыми)
  • & для поразрядной операции И (значения должны быть беззнаковыми числами)
  • | для поразрядной операции ИЛИ (значения должны быть беззнаковыми числами)
  • ^ для поразрядной операции Исключающее ИЛИ (значения должны быть беззнаковыми числами)
  • : для разделения строк
  • ! для вставки
  • # для удаления
  • = для присваивания

Для операций ! и = номер поля может быть -1, что означает последнее поле в кортеже.

Параметры:
  • space_object (space_object) – ссылка на объект
  • key (scalar/table) – значения поля первичного ключа, которые должны возвращаться в виде Lua-таблицы, если ключ составной
  • operator (string) – тип операции, представленный строкой
  • field_no (number) – к какому полю применяется операция. Номер поля может быть отрицательным, что означает, что позиция рассчитывается с конца кортежа. (#кортеж + отрицательный номер поля + 1)
  • value (lua_value) – какое значение применяется
возвращается:

обновленный кортеж.

тип возвращаемого значения:
 

кортеж

Возможные ошибки: нельзя изменять поле первичного ключа.

Факторы сложности Размер индекса, тип индекса, количество кортежей, к которым получен доступ, настройки журнала упреждающей записи (WAL).

Таким образом, в инструкции:

s:update(44, {{'+', 1, 55 }, {'=', 3, 'x'}})

значение первичного ключа равно 44, заданы операторы '+' и '=', что означает прибавление значение к полю, а затем присваивание значения полю, первое затронутое поле – это поле 1, к нему прибавляется значение 55, второе затронутое поле – это поле 3, ему присваивается значение 'x'.

Пример:

Предположим, что изначально есть спейс под названием tester с первичным индексом, тип которого – unsigned. Есть один кортеж с полем №1 field[1] = 999 и полем №2 field[2] = 'A'.

В обновлении:
box.space.tester:update(999, {{'=', 2, 'B'}})
Первый аргумент – это tester, то есть обновление происходит в спейсе tester. Второй аргумент – 999, то есть затронутый кортеж определяется по значению первичного ключа = 999. Третий аргумент – =, то есть будет одна операция – присваивание полю. Четвертый аргумент – 2, то есть будет затронуто поле №2 field[2]. Пятый аргумент – 'B', то есть содержимое field[2] изменится на 'B'. Таким образом, после данного обновления field[1] = 999, а field[2] = 'B'.

В обновлении:
box.space.tester:update({999}, {{'=', 2, 'B'}})
Аргументы повторяются за исключением того, что ключ передается в виде Lua-таблицы (в фигурных скобках). В этом нет необходимости, если первичный ключ содержит только одно поле, но было бы необходимо, если бы в первичном ключе было больше одного поля. Таким образом, после данного обновления field[1] = 999, а field[2] = 'B' (без изменений).

В обновлении:
box.space.tester:update({999}, {{'=', 3, 1}})
Аргументы повторяются за исключением того, что четвертым аргументом будет 3, то есть будет затронуто поле №3 field[3]. Ничего страшного, что до этого поле field[3] не существовало. Оно добавится. Таким образом, после данного обновления field[1] = 999, field[2] = 'B', field[3] = 1.

В обновлении:
box.space.tester:update({999}, {{'+', 3, 1}})
Аргументы повторяются за исключением того, что третьим аргументом будет '+', то есть будет операция добавления, а не присваивания. Поскольку``field[3]`` ранее содержало значение 1, это означает, что к 1 прибавится 1. Таким образом, после данного обновления field[1] = 999, field[2] = 'B', field[3] = 2.

В обновлении:
box.space.tester:update({999}, {{'|', 3, 1}, {'=', 2, 'C'}})
Основная идея состоит в том, чтобы изменить одновременно два поля. Форматами будут '|' и =, то есть имеем две операции: ИЛИ и присваивание. Четвертый и пятый аргументы означают, что над полем field[3] проводится операция ИЛИ со значением 1. Седьмой и восьмой аргументы означают, что полю field[2] присваивается 'C'. Таким образом, после данного обновления field[1] = 999, field[2] = 'C', field[3] = 3.

В обновлении:
box.space.tester:update({999}, {{'#', 2, 1}, {'-', 2, 3}})
Основная идея состоит в том, чтобы удалить поле field[2], а затем вычесть 3 из field[3]. Но после удаления, произойдет перенумерация, поэтому поле field[3] становится field[2] до того, как мы вычтем из него 3, вот почему седьмым аргументом будет 2, а не 3. Таким образом, после данного обновления field[1] = 999, field[2] = 0.

В обновлении:
box.space.tester:update({999}, {{'=', 2, 'XYZ'}})
Создаем длинную строку, чтобы в следующем примере сработало разделение. Таким образом, после данного обновления field[1] = 999, field[2] = 'XYZ'.

В обновлении:
box.space.tester:update({999}, {{':', 2, 2, 1, '!!'}})
Третьим аргументом будет ':', то есть это пример разделения. Четвертым аргументом будет 2, поскольку изменение произойдет в поле field[2]. Пятым аргументом будет 2, поскольку удаление начнется со второго байта. Шестым аргументом будет 1, количество удаляемых байтов – 1. Седьмым аргументом будет '!!', поскольку в данном положении будет добавляться '!!'. Таким образом, после данного обновления field[1] = 999, field[2] = 'X!!Z'.

Для получения дополнительной информации о сценариях использования и типичных ошибках, см. Пример: использование операций с данными далее в разделе.

space_object:upsert({tuple}, {{operator, field_no, value}, ...})

Обновление или вставка кортежа.

If there is an existing tuple which matches the key fields of tuple, then the request has the same effect as space_object:update() and the {{operator, field_no, value}, ...} parameter is used. If there is no existing tuple which matches the key fields of tuple, then the request has the same effect as space_object:insert() and the {tuple} parameter is used. However, unlike insert or update, upsert will not read a tuple and perform error checks before returning – this is a design feature which enhances throughput but requires more caution on the part of the user.

Параметры:
  • space_object (space_object) – ссылка на объект
  • tuple (table/tuple) – вставляемый по умолчанию кортеж, если не найдет аналог
  • operator (string) – тип операции, представленный строкой
  • field_no (number) – к какому полю применяется операция. Номер поля может быть отрицательным, что означает, что позиция рассчитывается с конца кортежа. (#кортеж + отрицательный номер поля + 1)
  • value (lua_value) – какое значение применяется
возвращается:

null

Возможные ошибки:

  • Нельзя изменять поле первичного ключа.
  • Нельзя проводить операцию upsert в спейсе, в котором есть уникальный вторичный индекс.

Факторы сложности Размер индекса, тип индекса, количество кортежей, к которым получен доступ, настройки журнала упреждающей записи (WAL).

Пример:

box.space.tester:upsert({12,'c'}, {{'=', 3, 'a'}, {'=', 4, 'b'}})

Для получения дополнительной информации о сценариях использования и типичных ошибках, см. Пример: использование операций с данными далее в разделе.

space_object:user_defined()

Пользователи могут сами определять любые желаемые функции и связывать их со спейсами: фактически они могут создавать собственные методы для работы со спейсом. Это можно сделать так:

  1. создать Lua-функцию,
  2. добавить имя функции в заданную глобальную переменную с типом «таблица» (table),
  3. впоследствии в любое время, пока работает сервер, вызвать функцию с помощью объект_спейса:имя-функции([параметры]).

Задана глобальная переменная box.schema.space_mt. Метод, добавленный в box.schema.space_mt, будет доступен для всех спейсов.

Можно также сделать задаваемый пользователем метод доступным только для одного индекса путем вызова getmetatable(объект_спейса) и последующего добавления имени функции в метатаблицу. См. также пример для index_object:user_defined().

Параметры:

Пример:

-- Доступный для любого спейса, без параметров.
-- После таких запросов значение глобальной переменной global_variable будет 6.
box.schema.space.create('t')
box.space.t:create_index('i')
global_variable = 5
function f(space_arg) global_variable = global_variable + 1 end
box.schema.space_mt.counter = f
box.space.t:counter()
space_object:create_check_constraint(check_constraint_name, expression)

Create a check constraint. A check constraint is a requirement that must be met when a tuple is inserted or updated in a space. Check constraints created with space_object:create_check_constraint have the same effect as check constraints created with an SQL CHECK() clause in a CREATE TABLE statement.

Параметры:
возвращается:

check constraint object

тип возвращаемого значения:
 

check_constraint_object

The space must be formatted with space_object:format() so that the expression can contain field names. The space must be empty. The space must not be a system space.

The expression must return true or false and should be deterministic. The expresion may be any SQL (not Lua) expression containing field names, built-in function names, literals, and operators. Not subqueries. If a field name contains lower case characters, it must be enclosed in «double quotes».

Check constraints are checked before the request is performed, at the same time as Lua before_replace triggers. If there is more than one check constraint or before_replace trigger, then they are ordered according to time of creation. (This is a change from the earlier behavior of check constraints, which caused checking before the tuple was formed.)

Check constraints can be dropped with space_object:check_constraint_name:drop().

Пример:

box.schema.space.create('t')
box.space.t:format({{name = 'f1', type = 'unsigned'},
                    {name = 'f2', type = 'string'},
                    {name = 'f3', type = 'string'}})
box.space.t:create_index('i')
box.space.t:create_check_constraint('c1', [["f2" > 'A']])
box.space.t:create_check_constraint('c2',
                        [["f2"=UPPER("f3") AND NOT "f2" LIKE '__']])
-- This insert will fail, constraint c1 expression returns false
box.space.t:insert{1, 'A', 'A'}
-- This insert will fail, constraint c2 expression returns false
box.space.t:insert{1, 'B', 'c'}
-- This insert will succeed, both constraint expressions return true
box.space.t:insert{1, 'B', 'b'}
-- This update will fail, constraint c2 expression returns false
box.space.t:update(1, {{'=', 2, 'xx'}, {'=', 3, 'xx'}})

A list of check constraints is in space_object._ck_constraint.

space_object.enabled

Определение активности спейса. Значение false указывает на отсутствие индекса.

space_object.field_count

Необходимость подсчета полей всех кортежей в спейсе, который можно изначально задать следующим образом:

box.schema.space.create(..., {
    ... ,
    field_count = field_count_value ,
    ...
})

По умолчанию, будет использоваться значение 0, что указывает на отсутствие необходимости подсчета полей.

Пример:

tarantool> box.space.tester.field_count
---
- 0
...
space_object.id

Порядковый номер спейса. На спейс можно ссылаться либо по имени, либо по номеру. Таким образом, если идентификатором спейса tester будет id = 800, то box.space.tester:insert{0} и box.space[800]:insert{0} представляют собой равнозначные запросы.

Пример:

tarantool> box.space.tester.id
---
- 512
...
box.space.index

Контейнер для всех определенных индексов. Есть Lua-объект типа box.index с методами поиска кортежей и итерации по ним в заданном порядке.

Чтобы сбросить, use box.stat.reset().

тип возвращаемого значения:
 таблица

Пример:

# checking the number of indexes for space 'tester'
tarantool> local counter=0; for i=0,#box.space.tester.index do
  if box.space.tester.index[i]~=nil then counter=counter+1 end
  end; print(counter)
1
---
...
# checking the type of index 'primary'
tarantool> box.space.tester.index.primary.type
---
- TREE
...
box.space._cluster

_cluster – это системный спейс для поддержки функции репликации.

box.space._func

_func is a system space with function tuples made by box.schema.func.create() or box.schema.func.create(func-name [, {options-with-body}]).

Кортежи в данном спейсе включают в себя следующие поля:

  • id (integer identifier),
  • owner (integer identifier),
  • имя функции,
  • the setuid flag,
  • название языка (необязательно): „LUA“ (по умолчанию) or „C“.
  • the body
  • the is_deterministic flag
  • the is_sandboxed flag
  • options

If the function tuple was made in the older way without specification of body, then the _func space will contain default values for the body and the is_deterministic flag and the is_sandboxed flag. Such function tuples are called «not persistent». You continue to create Lua functions in the usual way, by saying function function_name () ... end, without adding anything in the _func space. The _func space only exists for storing function tuples so that their names can be used within grant/revoke functions.

If the function tuple was made the newer way with specification of body, then all the fields may contain non-default values. Such functions are called «persistent». They should be invoked with box.func.func-name:call([parameters]).

Доступны следующие операции:

Пример:

В следующем примере создадим функцию с именем ‘f7’, поместим ее в спейс _func в Tarantool’е и выдадим права на „выполнение“ этой функции пользователю „guest“.

tarantool> function f7()
         >  box.session.uid()
         > end
---
...
tarantool> box.schema.func.create('f7')
---
...
tarantool> box.schema.user.grant('guest', 'execute', 'function', 'f7')
---
...
tarantool> box.schema.user.revoke('guest', 'execute', 'function', 'f7')
---
...
box.space._index

_index – это системный спейс.

Кортежи в данном спейсе включают в себя следующие поля:

  • id (= идентификатор спейса),
  • iid (= номер индекса в спейсе),
  • name,
  • type,
  • opts (например, уникальная опция), [tuple-field-no, tuple-field-type …].

Вот что при обычной установке включает в себя спейс _index:

tarantool> box.space._index:select{}
---
- - [272, 0, 'primary', 'tree', {'unique': true}, [[0, 'string']]]
  - [280, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
  - [280, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
  - [280, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
  - [281, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
  - [281, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
  - [281, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
  - [288, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned'], [1, 'unsigned']]]
  - [288, 2, 'name', 'tree', {'unique': true}, [[0, 'unsigned'], [2, 'string']]]
  - [289, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned'], [1, 'unsigned']]]
  - [289, 2, 'name', 'tree', {'unique': true}, [[0, 'unsigned'], [2, 'string']]]
  - [296, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
  - [296, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
  - [296, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
---
...
box.space._vindex

_vindex – это системный спейс, который реализует виртуальное представление. Структура его кортежей совпадает со структурой кортежей в _index, но права доступа на определенные кортежи ограничены в соответствии с правами пользователя. _vindex содержит только те кортежи, которые доступны текущему пользователю. Для получения более подробной информации о правах пользователя см. раздел Управление доступом.

Если у пользователя есть полный набор прав (как у пользователя „admin“), содержимое _vindex совпадает с содержимым _index. Если же у пользователя доступ ограничен, _vindex содержит только кортежи, которые доступны текущему пользователю.

Примечание

  • _vindex – это виртуальное представление системы, поэтому допускаются только запросы на чтение.
  • Если спейс _index требует наличия соответствующих прав доступа, то любой пользователь всегда может выполнить чтение из _vindex.
box.space._priv

_priv – это системный спейс, где хранятся права.

Кортежи в данном спейсе включают в себя следующие поля:

  • числовой идентификатор пользователя, который выдал права («grantor_id»),
  • числовой идентификатор пользователя, который получил права («grantee_id»),
  • тип объекта: „space“ (спейс), „function“ (функция), „sequence“ (последовательность) или „universe“ (вселенная),
  • числовой идентификатор объекта,
  • тип операции: «read» = 1, «write» = 2, «execute» = 4, «create» = 32, «drop» = 64, «alter» = 128, или их комбинация, например «read,write,execute».

Доступны следующие операции:

Примечание

  • Как правило, права выдаются или отменяются владельцем объекта (пользователем, который создал его) или пользователем „admin“.
  • До удаления любых объектов или пользователей, убедитесь, что отменили все связанные с ними права.
  • Только пользователь „admin“ может выдавать права на „universe“.
  • Только пользователь „admin“ или создатель спейса может удалить, изменить или очистить спейс.
  • Только пользователь „admin“ или создатель спейса может изменять change a different user’s password.
box.space._vpriv

_vpriv – это системный спейс, который реализует виртуальное представление. Структура его кортежей совпадает со структурой кортежей в _priv, но права доступа на определенные кортежи ограничены в соответствии с правами пользователя. _vpriv содержит только те кортежи, которые доступны текущему пользователю. Для получения более подробной информации о правах пользователя см. раздел Управление доступом.

Если у пользователя есть полный набор прав (как у пользователя „admin“), содержимое _vpriv совпадает с содержимым _priv. Если же у пользователя доступ ограничен, _vpriv содержит только кортежи, которые доступны текущему пользователю.

Примечание

  • _vpriv – это виртуальное представление системы, поэтому допускаются только запросы на чтение.
  • Если спейс _priv требует наличия соответствующих прав доступа, то любой пользователь всегда может выполнить чтение из _vpriv.
box.space._schema

_schema – это системный спейс.

Этот спейс включает в себя следующие кортежи:

  • кортеж version с информацией о версии данного экземпляра Tarantool’а,
  • кортеж cluster с идентификатором набора реплик данного экземпляра,
  • кортеж max_id с максимальным ID спейса,
  • кортежи once..., которые соответствуют определенным блокам box.once() из файла инициализации экземпляра. Первое поле в таких кортежах содержит значение ключа key из соответствующего блока box.once() с префиксом „once“ (например, oncehello), поэтому можно легко найти кортеж, который соответствует определенному блоку box.once().

Пример:

Вот что при обычной установке включает в себя спейс _schema (обратите внимание на кортежи для двух блоков box.once(): 'oncebye' и 'oncehello'):

tarantool> box.space._schema:select{}
---
- - ['cluster', 'b4e15788-d962-4442-892e-d6c1dd5d13f2']
  - ['max_id', 512]
  - ['oncebye']
  - ['oncehello']
  - ['version', 1, 7, 2]
box.space._sequence

_sequence – это системный спейс для поддержки последовательностей. Он содержит персистентную информацию, определенную с помощью box.schema.sequence.create() или box.schema.sequence.alter().

box.space._sequence_data

_sequence_data – это системный спейс для поддержки последовательностей.

Каждый кортеж в спейсе _sequence_data содержит два поля:

  • идентификатор последовательности и
  • последнее значение, возвращенное генератором последовательностей (временная информация).

There is no guarantee that this space will be updated immediately after every data-change request.

box.space._space

_space – это системный спейс.

Кортежи в данном спейсе включают в себя следующие поля:

  • id,
  • owner (= идентификатор пользователя, которому принадлежит спейс),
  • name, engine, field_count,
  • flags (например, временный),
  • format (как задано через оператор формата).

Эти поля определены с помощью space.create().

Пример №1:

Следующая функция отобразит все простые поля во всех кортежах спейса _space.

function example()
  local ta = {}
  local i, line
  for k, v in box.space._space:pairs() do
    i = 1
    line = ''
    while i <= #v do
      if type(v[i]) ~= 'table' then
        line = line .. v[i] .. ' '
      end
    i = i + 1
    end
    table.insert(ta, line)
  end
  return ta
end

Вот что при обычной установке вернет example():

tarantool> example()
---
- - '272 1 _schema memtx 0  '
  - '280 1 _space memtx 0  '
  - '281 1 _vspace sysview 0  '
  - '288 1 _index memtx 0  '
  - '296 1 _func memtx 0  '
  - '304 1 _user memtx 0  '
  - '305 1 _vuser sysview 0  '
  - '312 1 _priv memtx 0  '
  - '313 1 _vpriv sysview 0  '
  - '320 1 _cluster memtx 0  '
  - '512 1 tester memtx 0  '
  - '513 1 origin vinyl 0  '
  - '514 1 archive memtx 0  '
...

Примеры:

Следующая серия запросов создаст спейс, используя box.schema.space.create() с оператором формата, затем выберет кортеж из _space для нового спейса. Этот пример иллюстрирует стандартное применение оператора format, показывая рекомендованные имена и типы данных для полей.

tarantool> box.schema.space.create('TM', {
         >   id = 12345,
         >   format = {
         >     [1] = {["name"] = "field_1"},
         >     [2] = {["type"] = "unsigned"}
         >   }
         > })
---
- index: []
  on_replace: 'function: 0x41c67338'
  temporary: false
  id: 12345
  engine: memtx
  enabled: false
  name: TM
  field_count: 0
- created
...
tarantool> box.space._space:select(12345)
---
- - [12345, 1, 'TM', 'memtx', 0, {}, [{'name': 'field_1'}, {'type': 'unsigned'}]]
...
box.space._vspace

_vspace – это системный спейс, который реализует виртуальное представление. Структура его кортежей совпадает со структурой кортежей в _space, но права доступа на определенные кортежи ограничены в соответствии с правами пользователя. _vspace содержит только те кортежи, которые доступны текущему пользователю. Для получения более подробной информации о правах пользователя см. раздел Управление доступом.

Если у пользователя есть полный набор прав (как у пользователя „admin“), содержимое _vspace совпадает с содержимым _space. Если же у пользователя доступ ограничен, _vspace содержит только кортежи, которые доступны текущему пользователю.

Примечание

  • _vspace – это виртуальное представление системы, поэтому допускаются только запросы на чтение.
  • Если спейс _space требует наличия соответствующих прав доступа, то любой пользователь всегда может выполнить чтение из _vspace.
box.space._user

_user – это системный спейс, где хранятся имена пользователей и хеши паролей.

Кортежи в данном спейсе включают в себя следующие поля:

  • числовой идентификатор кортежа («id»),
  • числовой идентификатор создателя кортежа,
  • имя,
  • тип: „user“ (пользователь) или „role“ (роль),
  • пароль по желанию

В спейсе _user есть пять специальных кортежей: „guest“, „admin“, „public“, „replication“ и „super“.

Имя ID Type Описание
guest 0 user (пользователь) Пользователь, который используется по умолчанию при удаленном подключении. Как правило, это не заслуживающий доверия пользователь с небольшим количеством прав.
admin 1 user (пользователь) Пользователь, который используется по умолчанию при работе с Tarantool’ом как с консолью. Как правило, это административный пользователь со всеми правами.
public 2 роль Заданная роль, которая автоматически выдается новым пользователям при их создании методом box.schema.user.create(имя-пользователя). Таким образом, лучше всего выдать права на чтение „read“ спейса „t“ каждому когда-либо созданному пользователю с помощью box.schema.role.grant('public','read','space','t').
replication 3 роль Заданная роль, выдаваемая пользователем „admin“ другим пользователям для использования функций репликации.
super 31 роль Заданная роль, выдаваемая пользователем „admin“ другим пользователям для получения всех прав на все объекты. Для роли „super“ такие права выданы на „universe“: чтение, запись, выполнение, создание, удаление, изменение.

Чтобы выбрать кортеж из спейса _user, используйте box.space._user:select(). Например, при выборке от пользователя с id = 0, который является пользователем „guest“ без пароля по умолчанию, произойдет следующее:

tarantool> box.space._user:select{0}
---
- - [0, 1, 'guest', 'user']
...

Предупреждение

Чтобы изменить кортежи в спейсе _user, не пользуйтесь стандартными функциями box.space для вставки, обновления или удаления. Речь идет об особом спейсе _user, поэтому есть особые функции с соответствующей проверкой на ошибки.

Чтобы создать нового пользователя, используйте box.schema.user.create():

box.schema.user.create(*имя-пользователя*)
box.schema.user.create(*имя-пользователя*, {if_not_exists = true})
box.schema.user.create(*имя-пользователя*, {password = *пароль*})

Чтобы изменить пароль пользователя, воспользуйтесь box.schema.user.password():

-- Чтобы изменить пароль текущего пользователя
box.schema.user.passwd(*пароль*)

-- Чтобы изменить пароль другого пользователя
-- (обычно это может делать только 'admin')
box.schema.user.passwd(*имя-пользователя*, *пароль*)

Чтобы удалить пользователя, используйте box.schema.user.drop():

box.schema.user.drop(*имя-пользователя*)

Чтобы проверить, существует ли пользователь, воспользуйтесь box.schema.user.exists(), которая вернет true (правда) или false (ложь):

box.schema.user.exists(*имя-пользователя*)

Чтобы узнать, какие права есть у пользователя, используйте box.schema.user.info():

box.schema.user.info(*имя-пользователя*)

Примечание

Максимальное количество пользователей – 32.

Пример:

Ниже представлена сессия, в рамках которой создается новый пользователь с надежным паролем, выбирается кортеж из спейса _user, а затем пользователь удаляется.

tarantool> box.schema.user.create('JeanMartin', {password = 'Iwtso_6_os$$'})
---
...
tarantool> box.space._user.index.name:select{'JeanMartin'}
---
- - [17, 1, 'JeanMartin', 'user', {'chap-sha1': 't3xjUpQdrt857O+YRvGbMY5py8Q='}]
...
tarantool> box.schema.user.drop('JeanMartin')
---
...
box.space._ck_constraint

_ck_constraint is a system space where check constraints are stored.

Кортежи в данном спейсе включают в себя следующие поля:

  • the numeric id of the space («space_id»),
  • имя,
  • whether the check is deferred («is_deferred»),
  • the language of the expression, such as „SQL“,
  • the expression («code»)

Пример:

tarantool> box.space._ck_constraint:select()
---
- - [527, 'c1', false, 'SQL', '"f2" > ''A''']
  - [527, 'c2', false, 'SQL', '"f2" == UPPER("f3") AND NOT "f2" LIKE ''__''']
...

Пример: использование функций box.space для чтения кортежей из _space

Функция ниже проиллюстрирует, как обращаться ко всем спейсам, и для каждого отобразит примерное количество кортежей и первое поле первого кортежа. В данной функции используются функции из box.space в Tarantool’е: len() и pairs(). Итерация по спейсам закодирована в форме сканирования системного спейса _space, который содержит метаданные. Третье поле в _space содержит имя спейса, поэтому ключевая команда space_name = v[3] означает, что space_name – это поле space_name в кортеже _space, который мы только что получили с помощью pairs(). Функция возвращает таблицу:

function example()
  local tuple_count, space_name, line
  local ta = {}
  for k, v in box.space._space:pairs() do
    space_name = v[3]
    if box.space[space_name].index[0] ~= nil then
      tuple_count = '1 or more'
    else
      tuple_count = '0'
    end
    line = space_name .. ' tuple_count =' .. tuple_count
    if tuple_count == '1 or more' then
      for k1, v1 in box.space[space_name]:pairs() do
        line = line .. '. first field in first tuple = ' .. v1[1]
        break
      end
    end
    table.insert(ta, line)
  end
  return ta
end

А вот что происходит, когда вызывается функция:

tarantool> example()
---
- - _schema tuple_count =1 or more. first field in first tuple = cluster
  - _space tuple_count =1 or more. first field in first tuple = 272
  - _vspace tuple_count =1 or more. first field in first tuple = 272
  - _index tuple_count =1 or more. first field in first tuple = 272
  - _vindex tuple_count =1 or more. first field in first tuple = 272
  - _func tuple_count =1 or more. first field in first tuple = 1
  - _vfunc tuple_count =1 or more. first field in first tuple = 1
  - _user tuple_count =1 or more. first field in first tuple = 0
  - _vuser tuple_count =1 or more. first field in first tuple = 0
  - _priv tuple_count =1 or more. first field in first tuple = 1
  - _vpriv tuple_count =1 or more. first field in first tuple = 1
  - _cluster tuple_count =1 or more. first field in first tuple = 1
...

Пример: использование функций box.space для организации кортежа из _space

Основная цель – отобразить имена и типы полей системного спейса, то есть использование метаданных для поиска метаданных.

Для начала: как можно сделать выборку кортежа из _space, который описывает _space?

Проще всего проверить постоянные в box.schema, что укажет на наличие элемента под названием SPACE_ID == 288. Таким образом, следующие запросы вернут нужный кортеж:

box.space._space:select{ 288 }
-- или --
box.space._space:select{ box.schema.SPACE_ID }

Также можно обратиться к спейсам в box.space._index, что укажет на наличие вторичного индекса с именем „name“ для спейса под номером 288. Таким образом, следующий запрос также вернет нужный кортеж:

box.space._space.index.name:select{ '_space' }

Однако непросто прочитать информацию из полученного кортежа:

tarantool> box.space._space.index.name:select{'_space'}
---
- - [280, 1, '_space', 'memtx', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'owner',
        'type': 'num'}, {'name': 'name', 'type': 'str'}, {'name': 'engine', 'type': 'str'},
      {'name': 'field_count', 'type': 'num'}, {'name': 'flags', 'type': 'str'}, {
        'name': 'format', 'type': '*'}]]
...

Информация подается бессистемно, поскольку по формату поле №7 содержит рекомендованные имена и типы данных. Как же получить эти данные? Поскольку очевидно, что поле №7 представляет собой ассоциативный массив, цикл for проведет организацию данных:

tarantool> do
         >   local tuple_of_space = box.space._space.index.name:get{'_space'}
         >   for _, field in ipairs(tuple_of_space[7]) do
         >     print(field.name .. ', ' .. field.type)
         >   end
         > end
id, num
owner, num
name, str
engine, str
field_count, num
flags, str
format, *
---
...
box.space._vuser

_vuser – это системный спейс, который реализует виртуальное представление. Структура его кортежей совпадает со структурой кортежей в _user, но права доступа на определенные кортежи ограничены в соответствии с правами пользователя. _vuser содержит только те кортежи, которые доступны текущему пользователю. Для получения более подробной информации о правах пользователя см. раздел Управление доступом.

Если у пользователя есть полный набор прав (как у пользователя „admin“), содержимое _vuser совпадает с содержимым _user. Если же у пользователя доступ ограничен, _vuser содержит только кортежи, которые доступны текущему пользователю.

Чтобы посмотреть, как работать с _vuser, удаленно подключитесь к базе данных Tarantool’а с помощью tarantoolctl и сделайте выборку кортежей из спейса _user в следующих ситуациях: когда пользователь „guest“ имеет и когда он не имеет права выполнять чтение данных из базы.

Для начала запустите Tarantool и выдайте пользователю „guest“ права на чтение, запись и выполнение:

tarantool> box.cfg{listen = 3301}
---
...
tarantool> box.schema.user.grant('guest', 'read,write,execute', 'universe')
---
...

Перейдите на другой терминал, подключитесь к экземпляру Tarantool’а и произведите выборку всех кортежей из спейса _user:

$ tarantoolctl connect 3301
localhost:3301> box.space._user:select{}
---
- - [0, 1, 'guest', 'user', {}]
  - [1, 1, 'admin', 'user', {}]
  - [2, 1, 'public', 'role', {}]
  - [3, 1, 'replication', 'role', {}]
  - [31, 1, 'super', 'role', {}]
...

Результат включает в себя тот же набор пользователей, как если бы вы выполнили запрос от пользователя „admin“ на своем экземпляре Tarantool’а.

Вернитесь в первый терминал и отмените права на чтение пользователю „guest“:

tarantool> box.schema.user.revoke('guest', 'read', 'universe')
---
...

Перейдите на другой терминал, остановите сессию (чтобы остановить tarantoolctl, нажмите Ctrl+C или Ctrl+D) и повторите запрос box.space._user:select{}. В доступе отказано:

$ tarantoolctl connect 3301
localhost:3301> box.space._user:select{}
---
- error: Read access to space '_user' is denied for user 'guest'
...

Тем не менее, если вместо этого произвести выборку из _vuser, отображаются данные пользователей, доступные пользователю „guest“:

localhost:3301> box.space._vuser:select{}
---
- - [0, 1, 'guest', 'user', {}]
...

Примечание

  • _vuser – это виртуальное представление системы, поэтому допускаются только запросы на чтение.
  • Если спейс _user требует наличия соответствующих прав доступа, то любой пользователь всегда может выполнить чтение из _vuser.
box.space._collation

_collation is a system space with a list of collations. There are over 270 built-in collations and users may add more. Here is one example:

localhost:3301> box.space._collation:select(239)
---
- - [239, 'unicode_uk_s2', 1, 'ICU', 'uk', {'strength': 'secondary'}]
...

Explanation of the fields in the example: id = 239 i.e. Tarantool’s primary key is 239, name = „unicode_uk_s2“ i.e. according to Tarantool’s naming convention this is a Unicode collation + it is for the uk locale + it has secondary strength, owner = 1 i.e. the admin user, type = „ICU“ i.e. the rules are according to International Components for Unicode, locale = „uk“ i.e. Ukrainian, opts = „strength:secondary“ i.e. with this collation comparisons use both primary and secondary weights.

box.space._vcollation

_vcollation is a system space with a list of collations. The structure of its tuples is identical to that of box.space._collation, but permissions for certain tuples are limited in accordance with user privileges.

Пример: использование операций с данными

Пример ниже иллюстрирует все возможные сценарии – а также типичные ошибки – для всех операций с данными в Tarantool’е: INSERT, DELETE, UPDATE, UPSERT, REPLACE и SELECT.

-- Bootstrap the database --
box.cfg{}
format = {}
format[1] = {'field1', 'unsigned'}
format[2] = {'field2', 'unsigned'}
format[3] = {'field3', 'unsigned'}
s = box.schema.create_space('test', {format = format})
-- Create a primary index --
pk = s:create_index('pk', {parts = {{field = 'field1'}}})
-- Create a unique secondary index --
sk_uniq = s:create_index('sk_uniq', {parts = {{field = 'field2'}}})
-- Create a non-unique secondary index --
sk_non_uniq = s:create_index('sk_non_uniq', {parts = {{field = 'field3'}}, unique = false})

INSERT

Операция insert (вставка) работает с кортежами с четким форматом и проверяет все ключи на наличие совпадений.

tarantool> -- Уникальные индексы: разрешено --
tarantool> s:insert({1, 1, 1})
---
- [1, 1, 1]
...
tarantool> -- Конфликт первичного ключа: ошибка --
tarantool> s:insert({1, 1, 1})
---
- error: Duplicate key exists in unique index 'pk' in space 'test'
...
tarantool> -- Конфликт уникального вторичного ключа: ошибка --
tarantool> s:insert({2, 1, 1})
---
- error: Duplicate key exists in unique index 'sk_uniq' in space 'test'
...
tarantool> -- Ключ {1} присутствует в индексе sk_non_uniq, но он не уникален: разрешено --
tarantool> s:insert({2, 2, 1})
---
- [2, 2, 1]
...
tarantool> s:truncate()
---
...

DELETE

delete (удаление) работает с полными ключами любого уникального индекса.

space:delete – это псевдоним для операции «удалить по первичному ключу».

tarantool> -- Вставить некоторые тестовые данные --
tarantool> s:insert{3, 4, 5}
---
- [3, 4, 5]
...
tarantool> s:insert{6, 7, 8}
---
- [6, 7, 8]
...
tarantool> s:insert{9, 10, 11}
---
- [9, 10, 11]
...
tarantool> s:insert{12, 13, 14}
---
- [12, 13, 14]
...
tarantool> -- Здесь ничего не происходит: нет ключа {4} в индексе pk --
tarantool> s:delete{4}
---
...
tarantool> s:select{}
---
- - [3, 4, 5]
  - [6, 7, 8]
  - [9, 10, 11]
  - [12, 13, 14]
...
tarantool> -- Удалить по первичному ключу: разрешено --
tarantool> s:delete{3}
---
- [3, 4, 5]
...
tarantool> s:select{}
---
- - [6, 7, 8]
  - [9, 10, 11]
  - [12, 13, 14]
...
tarantool> -- Точно удалить по первичному ключу: разрешено --
tarantool> s.index.pk:delete{6}
---
- [6, 7, 8]
...
tarantool> s:select{}
---
- - [9, 10, 11]
  - [12, 13, 14]
...
tarantool> -- Удалить по уникальному вторичному ключу: разрешено --
s.index.sk_uniq:delete{10}
---
- [9, 10, 11]
...
s:select{}
---
- - [12, 13, 14]
...
tarantool> -- Удалить по неуникальному вторичному индексу: ошибка --
tarantool> s.index.sk_non_uniq:delete{14}
---
- error: Get() doesn't support partial keys and non-unique indexes
...
tarantool> s:select{}
---
- - [12, 13, 14]
...
tarantool> s:truncate()
---
...

Ключ должен быть полным: операция delete не работает с компонентами ключа.

tarantool> s2 = box.schema.create_space('test2')
---
...
tarantool> pk2 = s2:create_index('pk2', {parts = {{field = 1, type = 'unsigned'}, {field = 2, type = 'unsigned'}}})
---
...
tarantool> s2:insert{1, 1}
---
- [1, 1]
...
tarantool> -- Delete by a partial key: error --
tarantool> s2:delete{1}
---
- error: Invalid key part count in an exact match (expected 2, got 1)
...
tarantool> -- Delete by a full key: ok --
tarantool> s2:delete{1, 1}
---
- [1, 1]
...
tarantool> s2:select{}
---
- []
...
tarantool> s2:drop()
---
...

UPDATE

Как и delete, update работает с полными ключами любого уникального индекса, а также выполняет операции.

space:update – это псевдоним для операции «обновить по первичному ключу».

tarantool> -- Вставить некоторые тестовые данные --
tarantool> s:insert{3, 4, 5}
---
- [3, 4, 5]
...
tarantool> s:insert{6, 7, 8}
---
- [6, 7, 8]
...
tarantool> s:insert{9, 10, 11}
---
- [9, 10, 11]
...
tarantool> s:insert{12, 13, 14}
---
- [12, 13, 14]
...
tarantool> -- Здесь ничего не происходит: нет ключа {4} в индексе pk --
s:update({4}, {{'=', 2, 400}})
---
...
tarantool> s:select{}
---
- - [3, 4, 5]
  - [6, 7, 8]
  - [9, 10, 11]
  - [12, 13, 14]
...
tarantool> -- Обновить по первичному ключу: разрешено --
tarantool> s:update({3}, {{'=', 2, 400}})
---
- [3, 400, 5]
...
tarantool> s:select{}
---
- - [3, 400, 5]
  - [6, 7, 8]
  - [9, 10, 11]
  - [12, 13, 14]
...
tarantool> -- Точно обновить по первичному ключу: разрешено --
tarantool> s.index.pk:update({6}, {{'=', 2, 700}})
---
- [6, 700, 8]
...
tarantool> s:select{}
---
- - [3, 400, 5]
  - [6, 700, 8]
  - [9, 10, 11]
  - [12, 13, 14]
...
tarantool> -- Обновить по уникальному вторичному ключу: разрешено --
tarantool> s.index.sk_uniq:update({10}, {{'=', 2, 1000}})
---
- [9, 1000, 11]
...
tarantool> s:select{}
---
- - [3, 400, 5]
  - [6, 700, 8]
  - [9, 1000, 11]
  - [12, 13, 14]
...
tarantool> -- Обновить по неуникальному вторичному ключу: ошибка --
tarantool> s.index.sk_non_uniq:update({14}, {{'=', 2, 1300}})
---
- error: Get() doesn't support partial keys and non-unique indexes
...
tarantool> s:select{}
---
- - [3, 400, 5]
  - [6, 700, 8]
  - [9, 1000, 11]
  - [12, 13, 14]
...
tarantool> s:truncate()
---
...

UPSERT

upsert (обновление и вставка) работает с кортежами с четким форматом и выполняет операции обновления.

Если найден старый кортеж по первичному ключу, то операции обновления применяются к старому кортежу, а новый кортеж игнорируется.

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

Для индексов нет метода upsert – это метод для спейса.

tarantool> s.index.pk.upsert == nil
---
- true
...
tarantool> s.index.sk_uniq.upsert == nil
---
- true
...
tarantool> s.upsert ~= nil
---
- true
...
tarantool> -- В качестве первого аргумента upsert принимает --
tarantool> -- кортеж с четким форматом, НЕ ключ! --
tarantool> s:insert{1, 2, 3}
---
- [1, 2, 3]
...
tarantool> s:upsert({1}, {{'=', 2, 200}})
---
- error: Tuple field count 1 is less than required by space format or defined indexes
    (expected at least 3)
...
tarantool> s:select{}
---
- - [1, 2, 3]
...
tarantool> s:delete{1}
---
- [1, 2, 3]
...

upsert превращается в insert, когда старый кортеж не найден по первичному ключу.

tarantool> s:upsert({1, 2, 3}, {{'=', 2, 200}})
---
...
tarantool> -- Как можно увидеть, произошла вставка {1, 2, 3}, --
tarantool> -- а операции обновления не применились. --
s:select{}
---
- - [1, 2, 3]
...
tarantool> -- Еще одна операция upsert с тем же первичным ключом, --
tarantool> -- но другими значениями прочих полей. --
s:upsert({1, 20, 30}, {{'=', 2, 200}})
---
...
tarantool> -- Старый кортеж был найден по первичному ключу {1}, --
tarantool> -- и применились операции обновления. --
tarantool> -- Новый кортеж игнорируется. --
tarantool> s:select{}
---
- - [1, 200, 3]
...

upsert ищет старый кортеж по первичному индексу, НЕ по вторичному. Это может привести к ошибкам с дубликатами, если новый кортеж нарушает уникальность вторичного индекса.

tarantool> s:upsert({2, 200, 3}, {{'=', 3, 300}})
---
- error: Duplicate key exists in unique index 'sk_uniq' in space 'test'
...
s:select{}
---
- - [1, 200, 3]
...
tarantool> -- Но сработает, если сохраняется уникальность. --
tarantool> s:upsert({2, 0, 0}, {{'=', 3, 300}})
---
...
tarantool> s:select{}
---
- - [1, 200, 3]
  - [2, 0, 0]
...
tarantool> s:truncate()
---
...

REPLACE

replace (замена) работает с кортежами с четким форматом и ищет старый кортеж по первичному ключу нового кортежа.

Если найден старый кортеж, то происходит удаление старого кортежа и вставка нового.

Если старый кортеж не найден, вставляется новый кортеж.

tarantool> s:replace{1, 2, 3}
---
- [1, 2, 3]
...
tarantool> s:select{}
---
- - [1, 2, 3]
...
tarantool> s:replace{1, 3, 4}
---
- [1, 3, 4]
...
tarantool> s:select{}
---
- - [1, 3, 4]
...
tarantool> s:truncate()
---
...

Как и upsert, replace может нарушить требования уникальности.

tarantool> s:insert{1, 1, 1}
---
- [1, 1, 1]
...
tarantool> s:insert{2, 2, 2}
---
- [2, 2, 2]
...
tarantool> -- Такая замена не сработает, поскольку замена новым кортежем {1, 2, 0} --
tarantool> -- старого кортежа по первичному ключу из индекса 'pk' {1, 1, 1}, --
tarantool> -- приведет к созданию дубликата уникального вторичного ключа в индексе 'sk_uniq': --
tarantool> -- ключ {2} используется и в новом кортеже, и в {2, 2, 2}. --
tarantool> s:replace{1, 2, 0}
---
- error: Duplicate key exists in unique index 'sk_uniq' in space 'test'
...
tarantool> s:truncate()
---
...

SELECT

select (выборка) работает с любыми индексами (первичными/вторичными) и с любыми ключами (уникальными/неуникальными, полными/компонентами).

Если задан компонент ключа, select выполняет поиск всех ключей, префикс которых совпадает с указанным компонентом ключа.

tarantool> s:insert{1, 2, 3}
---
- [1, 2, 3]
...
tarantool> s:insert{4, 5, 6}
---
- [4, 5, 6]
...
tarantool> s:insert{7, 8, 9}
---
- [7, 8, 9]
...
tarantool> s:insert{10, 11, 9}
---
- [10, 11, 9]
...
tarantool> s:select{1}
---
- - [1, 2, 3]
...
tarantool> s:select{}
---
- - [1, 2, 3]
  - [4, 5, 6]
  - [7, 8, 9]
  - [10, 11, 9]
...
tarantool> s.index.pk:select{4}
---
- - [4, 5, 6]
...
tarantool> s.index.sk_uniq:select{8}
---
- - [7, 8, 9]
...
tarantool> s.index.sk_non_uniq:select{9}
---
- - [7, 8, 9]
  - [10, 11, 9]
...