Версия:

Вложенный модуль 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() Convert from map to tuple or table
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() Any function / method that any user wants to add
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 (Metadata) List of indexes accessible for the current user
box.space._priv (Метаданные) Список прав
box.space._vpriv (Metadata) List of privileges accessible for the current user
box.space._schema (Метаданные) Список схем
box.space._sequence (Метаданные) Список последовательностей
box.space._sequence_data (Метаданные) Список последовательностей
box.space._space (Метаданные) Список спейсов
box.space._vspace (Metadata) List of spaces accessible for the current user
box.space._user (Метаданные) Список пользователей
box.space._vuser (Metadata) List of users 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“ или „string“, или „integer“, или „number“, или „boolean“, или „array“, или „scalar“, возможна сортировка, возможно значение is_nullable} {1, '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() строка или число отсутствует

Параметры в вышеуказанной таблице также применимы к 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.

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

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

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

Семь типов полей индекса (unsigned | string | integer | number | boolean | array | scalar) отличаются друг от друга возможными значениями и типами индексов, где можно использовать такие поля.

  • 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’е.
  • array: массив чисел. Используется в RTREE-индексах в memtx’е.
  • scalar: логические значения (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“
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’е
true
-1
1.234
„“
„ру“

Allowing null for an indexed key: If the index type is TREE, and the index is not the primary index, then the parts={...} clause may include is_nullable=true or is_nullable=false (the default). If is_nullable is true, then it is legal to insert nil or an equivalent such as msgpack.NULL (or it is legal to insert nothing at all for trailing nullable fields). Within indexes, such «null values» are always treated as equal to other null values, and are always treated as less than non-null values. Nulls may appear multiple times even in a unique index. Example:

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

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

It is legal to create multiple indexes for the same field with different is_nullable values, or to call space_object:format() with a different is_nullable value from what is used for an index. When there is a contradiction, the rule is: null is illegal unless is_nullable=true for every index and for the space format.

Использование имен полей вместо номеров полей: в 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'}}})

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

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``не существует,
  • field names are duplicated;
  • тип не поддерживается.

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

The format clause contains, for each field, a definition within braces: {name='...',type='...'[,is_nullable=...]}, where:

It is not legal for tuples to contain values that have the wrong type; for example after box.space.tester:format({{' ',type='number'}}) the request box.space.tester:insert{'string-which-is-not-a-number'} will cause an error.

It is not legal for tuples to contain null values if is_nullable=false, which is the default; for example after box.space.tester:format({{' ',type='number',is_nullable=false}}) the request box.space.tester:insert{nil,2} will cause an error.

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

It is legal for tuples to have fewer fields than are described by a format clause, if the omitted trailing fields are described with is_nullable=true; for example after box.space.tester:format({{'a',type='number'},{'b',type='number',is_nullable=true}}) the request box.space.tester:insert{2} will not cause a format-related error.

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

It is legal to use format to change the is_nullable flag; for example after box.space.tester:format({{' ',type='scalar',is_nullable=false}}) the request box.space.tester:format({{' ',type='scalar',is_nullable=true}}) will not cause an error – and will not cause rebuilding of the space. But going the other way and changing is_nullable from true to false might cause rebuilding and might cause an error if there are existing tuples with nulls.

Пример:

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={2,'unsigned'}})
           --- ...
           tarantool> box.space.t:insert{{'a'},      -- любой
                    >                    1,          -- без знака
                    >                    'W?',       -- строка
                    >                    5.5,        -- число
                    >                    -0,         -- целое число
                    >                    true,       -- логическое значение
                    >                    true,       -- скаляр
                    >                    {{'a'}},    -- массив
                    >                    {val=1}}    -- ассоциативный массив
           ---
           - [['a'], 1, 'W?', 5.5, 0, true, true, [['a']], {'val': 1}]
           ...

Names specified with the format clause can be used in space_object:get() and in space_object:create_index() and in tuple_object[field-name] and in tuple_object[field-path].

If the format clause is omitted, then the returned value is the table that was used in a previous space_object:format(format-clause) invocation. For example, after box.space.tester:format({{'x','scalar'}}), box.space.tester:format() will return [{'name': 'x', 'type': 'scalar'}].

Note re storage engine: vinyl supports formatting of non-empty spaces. Primary index definition cannot be formatted.

space_object:frommap(map[, option])

Convert a map to a tuple instance or to a table. The map must consist of «field name = value» pairs. The field names and the value types must match names and types stated previously for the space, via space_object:format().

Параметры:
  • space_object (space_object) – ссылка на объект
  • map (field-value-pairs) – a series of «field = value» pairs, in any order.
  • option (boolean) – the only legal option is {table = true|false};
    if the option is omitted or if {table = false}, then return type will be „cdata“ (i.e. tuple);
    if {table = true}, then return type will be „table“.
возвращается:

a tuple instance or table.

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

tuple or table

Possible errors: space_object does not exist or has no format; «unknown field».

Пример:

-- Create a format with two fields named 'a' and 'b'.
-- Create a space with that format.
-- Create a tuple based on a map consistent with that space.
-- Create a table based on a map consistent with that space.
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}

Использование имен полей вместо номеров полей: в get() можно использовать имена полей, описанные в необязательном операторе space_object:format(). Это аналогично стандартной Lua-функции, где на компонент можно ссылаться по имени, а не по номеру. Например, может форматировать спейс tester с полем под названием x и использовать имя x в определении индекса:

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

Тогда если get или select вернут отдельный кортеж, можно сослаться на поле „x“ в кортеже по имени:

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

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

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

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

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

кортеж

Возможные ошибки: Если уже существует кортеж с тем же уникальным значением ключа, возвращается ER_TUPLE_FOUND.

Пример:

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
   ...

Примечание про движок базы данных: vinyl не поддерживает len(). Решением будет использование count() или #select(...).

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

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

Параметры:
  • trigger-function (function) – функция, в которой будет триггер
  • old-trigger-function (function) – существующая функция с триггером, которую заменит новая
возвращается:

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

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

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

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

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

Пример №1:

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

В функции trigger-function могут быть два параметра: старый кортеж, новый кортеж. Например, следующий код вызывает вывод nil при обработке запроса на вставку и вывод [1, „Hi“] при обработке запроса на удаление:

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

Примеры:

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

tarantool> s = box.schema.space.create('space53')
   tarantool> s:create_index('primary', {parts = {1, '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) – функция, в которой будет триггер
  • old-trigger-function (function) – существующая функция с триггером, которую заменит новая trigger-function
возвращается:

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

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

Следует знать, что если активация триггера произошла в случае репликации или определенного вида подключения, функция может ссылаться на 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 не было;
  • если значение другое, выполнение продолжается со вставкой|заменой нового значения.

However, if a trigger function returns an old tuple, or if a trigger function calls run_triggers(false), that will not affect other triggers that are activated for the same insert|update|replace request.

Пример:

Далее представлены функции 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.

Пример:

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().

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

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

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

кортеж

Возможные ошибки: Если уже существует другой кортеж с тем же уникальным значением ключа, возвращается ER_TUPLE_FOUND. (Это случится только в том случае, если есть уникальный вторичный индекс.)

Факторы сложности Размер индекса, тип индекса, количество кортежей, к которым получен доступ, настройки журнала упреждающей записи (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) –

    none, any or all of the same options that index_object:select allows:

    • options.iterator (type of iterator)
    • options.limit (maximum number of tuples)
    • options.offset (number of tuples to skip)
возвращается:

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

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

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

A select request can also be done with a specific index and index options, which are the subject of index_object:select.

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

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

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

Пример:

tarantool> s = box.schema.space.create('tmp', {temporary=true})
---
...
tarantool> s:create_index('primary',{parts = {1,'unsigned', 2, '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']
...

As the last request in the above example shows: to make complex select requests, where you can specify which index to search and what condition to use (for example «greater than» instead of «equal to») and how many tuples to return, it will be necessary to become familiar with index_object:select.

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

space_object:truncate()

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

Параметры:

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

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

The truncate method can only be called by the user who created the space, or from within a setuid function created by the user who created the space. Read more about setuid functions in the reference 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_value, {{operator, field_no, value}, ...})

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

Если существует кортеж, который совпадает с полями ключа tuple_value, запрос приведет к тому же результату, что и space_object:update(), и используется параметр {{operator, field_no, value}, ...}. Если нет кортежа, который совпадает с полями ключа tuple_value, запрос приведет к тому же результату, что и space_object:insert(), и используется параметр {tuple_value}. Однако, в отличие от insert или update, upsert не считывает кортеж и не проверяет на ошибки перед возвратом – это конструктивная особенность, которая увеличивает быстродействие, но требует большей осторожности со стороны пользователя.

Параметры:
  • 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()

Users can define any functions they want, and associate them with spaces: in effect they can make their own space methods. They do this by:

  1. creating a Lua function,
  2. adding the function name to a predefined global variable which has type = table, and
  3. invoking the function any time thereafter, as long as the server is up, by saying space_object:function-name([parameters]).

The predefined global variable is box_schema.space_mt. Adding to box_schema.space_mt makes the method available for all spaces.

Alternatively, user-defined methods can be made available for only one space, by calling getmetatable(space_object) and then adding the function name to the meta table. See also the example for index_object:user_defined().

Параметры:

Пример:

-- Visible to any space, no parameters.
-- After these requests, the value of global_variable will be 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.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 с методами поиска кортежей и итерации по ним в заданном порядке.

To reset, use box.stat.reset().

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

Пример:

# проверка количества индексов для спейса 'tester'
  tarantool> #box.space.tester.index
  ---
  - 1
  ...
  # проверка типа индекса 'primary'
  tarantool> box.space.tester.index.primary.type
  ---
  - TREE
  ...
box.space._cluster

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

box.space._func

_func – это системный спейс, который содержит кортежи с функциями, созданными с помощью box.schema.func.create().

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

  • числовой идентификатор функции, число,
  • имя функции,
  • флаг,
  • название языка (необязательно): „LUA“ (по умолчанию) or „C“.

Спейс _func не содержит саму функцию. Lua-функции создаются по-прежнему с помощью function имя_функции () ... end без каких-либо добавлений в спейс _func. Спейс _func предназначен лишь для хранения кортежей с функциями так, чтобы их имена могли использоваться в функциях выдачи/отмены прав.

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

Пример:

В следующем примере создадим функцию с именем ‘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 is a system space that represents a virtual view. The structure of its tuples is identical to that of _index, but permissions for certain tuples are limited in accordance with user privileges. _vindex contains only those tuples that are accessible to the current user. See Access control for details about user privileges.

If the user has the full set of privileges (like „admin“), the contents of _vindex match the contents of _index. If the user has limited access, _vindex contains only tuples accessible to this user.

Примечание

  • _vindex is a system view, so it allows only read requests.
  • While the _index space requires proper access privileges, any user can always read from _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 is a system space that represents a virtual view. The structure of its tuples is identical to that of _priv, but permissions for certain tuples are limited in accordance with user privileges. _vpriv contains only those tuples that are accessible to the current user. See Access control for details about user privileges.

If the user has the full set of privileges (like „admin“), the contents of _vpriv match the contents of _priv. If the user has limited access, _vpriv contains only tuples accessible to this user.

Примечание

  • _vpriv is a system view, so it allows only read requests.
  • While the _priv space requires proper access privileges, any user can always read from _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 содержит два поля:

  • идентификатор последовательности и
  • последнее значение, возвращенное генератором последовательностей (временная информация).
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 is a system space that represents a virtual view. The structure of its tuples is identical to that of _space, but permissions for certain tuples are limited in accordance with user privileges. _vspace contains only those tuples that are accessible to the current user. See Access control for details about user privileges.

If the user has the full set of privileges (like „admin“), the contents of _vspace match the contents of _space. If the user has limited access, _vspace contains only tuples accessible to this user.

Примечание

  • _vspace is a system view, so it allows only read requests.
  • While the _space space requires proper access privileges, any user can always read from _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 для чтения кортежей из _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

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

To begin: how can one select the _space tuple that describes _space?

A simple way is to look at the constants in box.schema, which tell us that there is an item named SPACE_ID == 288, so these statements will retrieve the correct tuple:

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

Another way is to look at the tuples in box.space._index, which tell us that there is a secondary index named „name“ for space number 288, so this statement also will retrieve the correct tuple:

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 is a system space that represents a virtual view. The structure of its tuples is identical to that of _user, but permissions for certain tuples are limited in accordance with user privileges. _vuser contains only those tuples that are accessible to the current user. See Access control for details about user privileges.

If the user has the full set of privileges (like „admin“), the contents of _vuser match the contents of _user. If the user has limited access, _vuser contains only tuples accessible to this user.

To see how _vuser works, connect to a Tarantool database remotely via tarantoolctl and select all tuples from the _user space, both when the „guest“ user is and is not allowed to read from the database.

First, start Tarantool and grant the „guest“ user with read, write and execute privileges:

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

Switch to the other terminal, connect to the Tarantool instance and select all tuples from the _user space:

$ 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', {}]
...

This result contains the same set of users as if you made the request from your Tarantool instance as „admin“.

Switch to the first terminal and revoke the read privileges from the „guest“ user:

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

Switch to the other terminal, stop the session (to stop tarantoolctl, type Ctrl+C or Ctrl+D) and repeat the box.space._user:select{} request. The access is denied:

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

However, if you select from _vuser instead, the users“ data available for the „guest“ user is displayed:

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

Примечание

  • _vuser is a system view, so it allows only read requests.
  • While the _user space requires proper access privileges, any user can always read from _vuser.

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

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

-- Настройка базы данных --
  box.cfg{}
  format = {}
  format[1] = {'field1', 'unsigned'}
  format[2] = {'field2', 'unsigned'}
  format[3] = {'field3', 'unsigned'}
  s = box.schema.create_space('test', {format = format})
  -- Создание первичного индекса --
  pk = s:create_index('pk', {parts = {{'field1'}}})
  -- Создание уникального вторичного индекса --
  sk_uniq = s:create_index('sk_uniq', {parts = {{'field2'}}})
  -- Создание неуникального вторичного индекса --
  sk_non_uniq = s:create_index('sk_non_uniq', {parts = {{'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 = {{1, 'unsigned'}, {2, 'unsigned'}}})
  ---
  ...
  tarantool> s2:insert{1, 1}
  ---
  - [1, 1]
  ...
  tarantool> -- Удалить по компоненту ключа: ошибка --
  tarantool> s2:delete{1}
  ---
  - error: Invalid key part count in an exact match (expected 2, got 1)
  ...
  tarantool> -- Удалить по ключу целиком: разрешено --
  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]
  ...