Вложенный модуль box.space¶
Общие сведения¶
CRUD operations in Tarantool are implemented by the box.space
submodule.
It has the data-manipulation functions select
, insert
, replace
,
update
, upsert
, delete
, get
, put
. It also has members,
such as id, and whether or not a space is enabled. Submodule source code
is available in file
src/box/lua/schema.lua.
Индекс¶
Ниже приведен перечень всех функций и элементов модуля box.space
.
Имя | Использование |
---|---|
space_object:auto_increment() | Генерация ключа + вставка кортежа |
space_object:bsize() | Подсчет байтов |
space_object:count() | Подсчет кортежей |
space_object:create_index()
* Details about index field types * Index field types to use in space_object:create_index() * Allowing null for an indexed key * Using field names instead of field numbers * Using the path option for map fields (JSON-indexes) * Using the path option with [*] * Making a functional index with 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
()¶ Параметры: - space_object (space_object) – ссылка на объект
возвращается: Количество байтов в спейсе. Это число, которое хранится во внутренней памяти 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 (space_object) – ссылка на объект
- index_name (string) – имя индекса, которое должно соответствовать правилам именования объектов
- options (table) – см. «Параметры для space_object:create_index()» ниже
возвращается: объект индекса
тип возвращаемого значения: объект индекса
Параметры для 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'}} }) --- ...
Подробнее о типах полей индекса:
Восемь типов полей индекса (unsigned | string | integer | number | boolean | varbinary | 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’е.
- 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 (input with
msgpack.NULL
oryaml.NULL
orjson.NULL
), booleans (true or false), or integers between -9223372036854775808 and 18446744073709551615, or single-precision floating point numbers, or double-precison floating-point numbers, or strings. When there is a mix of types, the key order is: null, then booleans, then numbers, then strings. Legal in memtx TREE or HASH indexes, and in vinyl TREE indexes.
Кроме того, допускается нулевое значение 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 последовательности байтов – любой набор октетов индексы типа 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+44boolean true или false индексы типа TREE или HASH в memtx’е,
TREE-индексы в vinyl’еfalse
truearray массив целых чисел от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 RTREE-индексы в memtx’е {10, 11}
{3, 5, 9, 10}scalar null, booleans (true or false), integers between -9223372036854775808 and 18446744073709551615, single-precision floating point numbers, double-precision floating point numbers, strings индексы типа 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 (JSON-indexes): 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 withindex_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.
Thecreate_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.
Only sandboxed functions are suitable for functional indexes.Пример:
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'} 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.
Thebox.func.create
options must includeopts = {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
()¶ Удаление спейса. Метод реализуется в фоновом режиме и не блокирует последующие запросы.
Параметры: - space_object (space_object) – ссылка на объект
возвращается: nil
Возможные ошибки:
space_object
не существует.Факторы сложности Размер индекса, тип индекса, количество кортежей, к которым получен доступ, настройки журнала упреждающей записи (WAL).
Пример:
box.space.space_that_does_not_exist:drop()
-
space_object:
format
([format-clause])¶ Объявление имен и типов полей.
Параметры: - space_object (space_object) – ссылка на объект
- format-clause (table) – список имен и типов полей
возвращается: nil, если не указан оператор формата
Возможные ошибки:
space_object
не существует,- дублируются имена полей;
- тип не поддерживается.
Как правило, Tarantool допускает поля без имен и без указания типа. Но с помощью
format
можно, например, задокументировать, что N-ное поле представляет собой поле для фамилии и должно содержать строковое значение. Также оператор формата можно указать в box.schema.space.create().Оператор формата для каждого поля содержит определение в фигурных скобках:
{name='...',type='...'[,is_nullable=...]}
, где:- значение
name
может представлять собой любую строку при условии, что у двух полей не будет одинаковых имен; - значением
type
может быть любой из разрешенных типов: any | unsigned | string | integer | number | boolean | array | map | scalar, но для создания индекса следует использовать только индексируемые типы; - значение необязательного параметра
is_nullable
может бытьtrue
илиfalse
(такое же требование, как для «Параметров для space_object:create_index»). См. также предупреждение в разделе Разрешение использования нулевых значений для индексируемого ключа.
В кортежах недопустимы значения неправильного типа; например, после
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
orselect
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)¶ Вставка кортежа в спейс.
Параметры: - space_object (space_object) – ссылка на объект
- tuple (tuple/table) – вставляемый кортеж.
возвращается: вставленный кортеж
тип возвращаемого значения: кортеж
Возможные ошибки: ошибка
ER_TUPLE_FOUND
, если уже существует кортеж с тем же уникальным значением ключа.Пример:
tarantool> box.space.tester:insert{5000,'tuple number five thousand'} --- - [5000, 'tuple number five thousand'] ...
Для получения дополнительной информации о сценариях использования и типичных ошибках, см. Пример: использование операций с данными далее в разделе.
-
space_object:
len
()¶ Возврат количества кортежей в спейсе. Если сравнивать с count(), то данный метод работает быстрее, поскольку метод
len()
не сканирует весь спейс для подсчета кортежей.Параметры: - space_object (space_object) – ссылка на объект
возвращается: Количество кортежей в спейсе.
Пример:
tarantool> box.space.tester:len() --- - 2 ...
Примечание про движок базы данных: vinyl поддерживает
len()
, но результат может быть неточным. Если необходим точный результат, используйте count() или pairs():length().
-
space_object:
on_replace
([trigger-function[, old-trigger-function]])¶ Создание «триггера замены». Функция с триггером
trigger-function
будет выполняться в случае операцииreplace()
илиinsert()
, илиupdate()
, илиupsert()
, илиdelete()
над кортежем в спейсе<space-name>
.Параметры: - trigger-function (function) – функция, в которой будет триггер; для получения информации о параметрах функции с триггером см. Пример №2 ниже
- old-trigger-function (function) – существующая функция с триггером, которую заменит новая
trigger-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)
Пример №2:
В функции с триггером может быть до 4 параметров:
- (кортеж) старое значение до начала запроса,
- (кортеж) новое значение после окончания выполнения запроса,
- (строка) имя спейса,
- (строка) тип запроса: „INSERT“ (вставка), „DELETE“ (удаление), „UPDATE“ (обновление) или „REPLACE“ (замена).
Например, следующий код вызывает вывод nil и „INSERT“ (вставка) при обработке запроса на вставку и вывод [1, „Hi“] и „DELETE“ (удаление) при обработке запроса на удаление:
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}
Пример №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
Примечание
В тригер-функциях для
on_replace
иbefore_replace
не следует использовать- транзакции,
- операции, передающие управление (yield-operations, явные или нет),
- действия, которые не разрешено использовать в транзакциях (см. правило №2)
потому что все, что выполняется внутри триггеров, уже находится в транзакции.
Пример:
tarantool> box.space.test:on_replace(fiber.yield) tarantool> box.space.test:replace{1, 2, 3} 2020-02-02 21:22:03.073 [73185] main/102/init.lua txn.c:532 E> ER_TRANSACTION_YIELD: Transaction has been aborted by a fiber yield --- - error: Transaction has been aborted by a fiber yield ...
-
space_object:
before_replace
([trigger-function[, old-trigger-function]])¶ Создание «триггера замены». Функция с триггером
trigger-function
будет выполняться в случае операцииreplace()
илиinsert()
, илиupdate()
, илиupsert()
, илиdelete()
над кортежем в спейсе<space-name>
.Параметры: - trigger-function (function) – функция, в которой будет триггер; необязательные параметры функции с триггером см. в описании on_replace.
- 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
не было; - если значение другое, выполнение продолжается со вставкой/заменой нового значения.
Тем не менее, если функция с триггером возвращает старый кортеж или вызывает 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.Для получения информации о внутренней структуре итераторов см. документацию по библиотеке для функционального программирования в Lua «Lua Functional library».
Пример:
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)¶ Переименование спейса.
Параметры: - space_object (space_object) – ссылка на объект
- space-name (string) – новое имя спейса
возвращается: 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()
.Параметры: - space_object (space_object) – ссылка на объект
- tuple (table/tuple) – вставляемый кортеж
возвращается: вставленный кортеж.
тип возвращаемого значения: кортеж
Возможные ошибки: ошибка
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) – ни один, любой или все параметры, которые допускает 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
()¶ Удаление всех кортежей. Метод выполняется в фоновом режиме и не блокирует последующие запросы.
Параметры: - space_object (space_object) – ссылка на объект
Факторы сложности: Размер индекса, тип индекса, количество кортежей, к которым получен доступ.
возвращается: 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) – какое значение применяется
возвращается: - обновленный кортеж
- nil, если ключ не найден
тип возвращаемого значения: кортеж или nil
Возможные ошибки: нельзя изменять поле первичного ключа.
Факторы сложности Размер индекса, тип индекса, количество кортежей, к которым получен доступ, настройки журнала упреждающей записи (WAL).
Таким образом, в инструкции:
s:update(44, {{'+', 1, 55 }, {'=', 3, 'x'}})
значение первичного ключа равно
44
, заданы операторы'+'
и'='
, что означает прибавление значение к полю, а затем присваивание значения полю, первое затронутое поле – это поле1
, к нему прибавляется значение55
, второе затронутое поле – это поле3
, ему присваивается значение'x'
.Пример:
Предположим, что изначально есть спейс под названием
tester
с первичным индексом, тип которого –unsigned
. Есть один кортеж с полем №1field[1]
=999
и полем №2field[2]
='A'
.В обновлении:
box.space.tester:update(999, {{'=', 2, 'B'}})
Первый аргумент – этоtester
, то есть обновление происходит в спейсеtester
. Второй аргумент –999
, то есть затронутый кортеж определяется по значению первичного ключа = 999. Третий аргумент –=
, то есть будет одна операция – присваивание полю. Четвертый аргумент –2
, то есть будет затронуто поле №2field[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
, то есть будет затронуто поле №3field[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}, ...})¶ Обновление или вставка кортежа.
Если существует кортеж, который совпадает с полями ключа
tuple
, запрос приведет к тому же результату, что и space_object:update(), и используется параметр{{operator, field_no, value}, ...}
. Если нет кортежа, который совпадает с полями ключаtuple
, запрос приведет к тому же результату, что и space_object:insert(), и используется параметр{tuple}
. Однако, в отличие от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
()¶ Пользователи могут сами определять любые желаемые функции и связывать их со спейсами: фактически они могут создавать собственные методы для работы со спейсом. Это можно сделать так:
- создать Lua-функцию,
- добавить имя функции в заданную глобальную переменную с типом «таблица» (table),
- впоследствии в любое время, пока работает сервер, вызвать функцию с помощью
объект_спейса:имя-функции([параметры])
.
Задана глобальная переменная
box.schema.space_mt
. Метод, добавленный вbox.schema.space_mt
, будет доступен для всех спейсов.Можно также сделать задаваемый пользователем метод доступным только для одного индекса путем вызова
getmetatable(объект_спейса)
и последующего добавления имени функции в метатаблицу. См. также пример для index_object:user_defined().Параметры: - index_object (index_object) – ссылка на объект.
- any-name (any-type) – то, что определяет пользователь
Пример:
-- Доступный для любого спейса, без параметров. -- После таких запросов значение глобальной переменной 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.Параметры: - space_object (space_object) – ссылка на объект
- check_constraint_name (string) – name of check constraint, which should conform to the rules for object names
- expression (string) – SQL code of an expression which must return a boolean result
возвращается: 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 (цельночисленный идентификатор),
- владелец (целочисленный идентификатор)
- имя функции,
- флаг setuid,
- название языка (необязательно): „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 sayingfunction 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 withbox.func.func-name:call([parameters])
.Доступны следующие операции:
- Создание кортежа в
_func
с помощью box.schema.func.create(), - Удаление кортежа в
_func
с помощью box.schema.func.drop(), - Проверка наличия кортежа в
_func
с помощью box.schema.func.exists().
Пример:
В следующем примере создадим функцию с именем ‘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»),
- the type of object: „space“, „index“, „function“, „sequence“, „user“, „role“, or „universe“,
- числовой идентификатор объекта,
- тип операции: «read» = 1, «write» = 2, «execute» = 4, «create» = 32, «drop» = 64, «alter» = 128, или их комбинация, например «read,write,execute».
Доступны следующие операции:
- Выдача прав с помощью box.schema.user.grant().
- Отмена прав с помощью box.schema.user.revoke().
Примечание
- Как правило, права выдаются или отменяются владельцем объекта (пользователем, который создал его) или пользователем „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
– это системный спейс. Он содержит информацию о всех спейсах, хранящихся в данном экземпляре Tarantool - как системные, так и созданные пользователями.Кортежи в данном спейсе включают в себя следующие поля:
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 ' ...
Пример №2:
Следующая серия запросов создаст спейс, используя
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]
...