Что означает INSERT 0 1

PostgreSQLНаверное, многие замечали что при вставке в таблицу в PostgreSQL выводится вот такое сообщение:

 

INSERT 0 1

 

Что оно означает?

Тут два числа — ноль и количество добавленных строк. Со вторым числом (количество добавленных строк) всё понятно. А что означает первое?

Я где-то когда-то слышал ответ, понял что так исторически сложилось и с некоторых пор первое число — всегда ноль. А тут решил разобраться что к чему.

Поиск по интернету выдает правильный ответ:

What does «INSERT 0 1» mean?

Обратите внимание на последний абзац:

It represents the OID, which PostgreSQL, in earlier versions, generated by default. Later versions do not do this by default. The zero indicates that you are not generating OID’s for that table.

Он представляет собой OID, который в более ранних версиях PostgreSQL генерировал по умолчанию. Более поздние версии этого не делают. Ноль указывает на то, что вы не генерируете OID для этой таблицы.

А теперь хотелось бы это проверить на практике.

Речь явно пойдет про идентификатор объекта (Object Identifier, OID), так что можно почитать документацию.

В тексте переписки была подсказка — CREATE TABLE …. WITH (OIDS=TRUE). Поэтому посмотрим на команду создания таблицы более внимательно:

Читаем ниже:

WITH ( параметр_хранения [= значение] [, … ] )

Это предложение определяет дополнительные параметры хранения для таблицы или индекса; за подробностями обратитесь к разделу Параметры хранения ниже. В целях обратной совместимости предложение WITH для таблицы также может содержать указание OIDS=FALSE, отмечающее, что строки новой таблицы не должны содержать OID (идентификатор объекта); указание OIDS=TRUE более не поддерживается

Для текущей (15й версии) PostgreSQL — OIDS=TRUE не поддерживается. А до какой версии такое указание поддерживается?

Можно сделать так — в верхней части страницы «пролистывать» версии PostgreSQL назад и проверять, поддерживается ли это указание в соответствующей версии сервера:

PostgreSQL. Список версий

  • В 14 — не поддерживается;
  • В 13 — не поддерживается;
  • В 12 — не поддерживается.

О, в 11 версии описание этого параметра поменялось:

Предложение WITH для таблицы может также включать указание OIDS=TRUE (или просто OIDS), устанавливающее, что каждая строка таблицы должна иметь собственный OID (Object IDentifier, идентификатор объекта).

То есть, в версиях до 12 использовать OID’ы в таблицах было можно. Давайте это проверим. У меня как раз под рукой есть виртуалка с 10 весрией PostgreSQL. Выполним там несколько команд:

postgres=# SELECT version();
                                                   version                                                  
-------------------------------------------------------------------------------------------------------
 PostgreSQL 10.0 on i686-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609, 
32-bit
(1 row)

Создадим обычную таблицу и добавим туда строку:

postgres=# CREATE TABLE t (id integer);
CREATE TABLE
postgres=# INSERT INTO t VALUES (1);
INSERT 0 1

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

А теперь создадим таблицу с OID’ом:

postgres=# CREATE TABLE t_oid (id integer) WITH (OIDS=TRUE);
CREATE TABLE

Добавим в таблицу строку:

postgres=# INSERT INTO t_oid VALUES (1);
INSERT 16416 1

И вот он — не ноль. Добавим еще парочку строк:

postgres=# INSERT INTO t_oid VALUES (1);
INSERT 16417 1
postgres=# INSERT INTO t_oid VALUES (1);
INSERT 16418 1

И посмотрим что у нас находится в таблице:

postgres=# SELECT * FROM t_oid;
 id 
----
  1
  1
  1
(3 rows)

Три строки — всё логично. А где OID?

Это системный столбец (обратите внимание что ссылка на документацию от 11 версии сервера, т. к. в 12 версии oid из списка системных столбов убрали) — скрытый столбец, его нужно явно написать в запросе:

postgres=# SELECT oid,* FROM t_oid;
  oid  | id 
-------+----
 16416 |  1
 16417 |  1
 16418 |  1
(3 rows)

Вот и те идентификаторы, которые были сгенерированы для этой таблицы.

Тут можно немного поэкспериментировать:

postgres=# INSERT INTO t_oid VALUES (2),(2),(2);
INSERT 0 3

Добавили три строки пачкой — первое число ноль. Не сгенерировали oid?

postgres=# SELECT oid,* FROM t_oid;
  oid  | id 
-------+----
 16416 |  1
 16417 |  1
 16418 |  1
 16419 |  2
 16420 |  2
 16421 |  2
(6 rows)

Ан нет, oid’ы на месте.

postgres=# INSERT INTO t_oid SELECT * FROM generate_series(1,3);
INSERT 0 3

Опять пачкой сгенерировали — опять первый ноль. Опять oid’ы не сгенерированы?

postgres=# SELECT oid,* FROM t_oid;
  oid  | id 
-------+----
 16416 |  1
 16417 |  1
 16418 |  1
 16419 |  2
 16420 |  2
 16421 |  2
 16422 |  1
 16423 |  2
 16424 |  3
(9 rows)

Нет конечно, они на месте.

Ну и с транзакциями немного:

postgres=# BEGIN;
BEGIN
postgres=# INSERT INTO t_oid VALUES (1);
INSERT 16425 1
postgres=# INSERT INTO t_oid VALUES (1);
INSERT 16426 1
postgres=# INSERT INTO t_oid VALUES (1);
INSERT 16427 1
postgres=# SELECT oid,* FROM t_oid;
  oid  | id 
-------+----
 16416 |  1
 16417 |  1
 16418 |  1
 16419 |  2
 16420 |  2
 16421 |  2
 16422 |  1
 16423 |  2
 16424 |  3
 16425 |  1
 16426 |  1
 16427 |  1
(12 rows)

postgres=# ROLLBACK;
ROLLBACK
postgres=# SELECT oid,* FROM t_oid;
  oid  | id 
-------+----
 16416 |  1
 16417 |  1
 16418 |  1
 16419 |  2
 16420 |  2
 16421 |  2
 16422 |  1
 16423 |  2
 16424 |  3
(9 rows)

postgres=# INSERT INTO t_oid VALUES (1);
INSERT 16428 1
postgres=# SELECT oid,* FROM t_oid;
  oid  | id 
-------+----
 16416 |  1
 16417 |  1
 16418 |  1
 16419 |  2
 16420 |  2
 16421 |  2
 16422 |  1
 16423 |  2
 16424 |  3
 16428 |  1
(10 rows)

Значение oid увеличилось, ранее выданные не использовались.

Кстати, а если попробовать вывести oid в той таблице, которую мы создавали без указания OID в параметре хранения — получим ошибку:

postgres=# SELECT oid,* FROM t;
2022-11-08 18:47:25.746 MSK [2397] ERROR:  column "oid" does not exist at character 8
2022-11-08 18:47:25.746 MSK [2397] HINT:  Perhaps you meant to reference the column "t.id".
2022-11-08 18:47:25.746 MSK [2397] STATEMENT:  SELECT oid,* FROM t;
ERROR:  column "oid" does not exist
LINE 1: SELECT oid,* FROM t;
               ^
HINT:  Perhaps you meant to reference the column "t.id".

А вот у таблиц системного каталога oid вывести можно:

pavel=# SELECT oid FROM pg_collation LIMIT 3;
 oid 
-----
 100
 950
 951
(3 rows)

Что для 10, что для 13 версий. Только есть небольшая разница — в 10 версии это скрытый столбец (его нужно явно прописать в тексте запроса), а в 13 версии — это часть таблицы, он выводится через SELECT *.

Так что есть небольшая разница. В 10 версии я могу добавить строку в системную таблицу — и oid будет сгенерирован:

postgres=# INSERT INTO pg_collation VALUES ('default2',11,10,'d',-1,'C','','');
INSERT 16433 1

И тут тоже в строке вывода появился не ноль, а сгенерированный oid.

А вот в 13 версии я так же сделать не смог. Если посмотреть описание таблицы pg_collation:

pavel=# \d pg_collation
                Table "pg_catalog.pg_collation"
       Column        |  Type   | Collation | Nullable | Default 
---------------------+---------+-----------+----------+---------
 oid                 | oid     |           | not null | 
 collname            | name    |           | not null | 
 collnamespace       | oid     |           | not null | 
 collowner           | oid     |           | not null | 
 collprovider        | "char"  |           | not null | 
 collisdeterministic | boolean |           | not null | 
 collencoding        | integer |           | not null | 
 collcollate         | name    |           | not null | 
 collctype           | name    |           | not null | 
 collversion         | text    | C         |          | 

Видно что поле oid имеет ограничение not null, как я понимаю — при вставке его прописать нужно (нельзя пропустить как это я сделал в 10ке). Если этого не сделать, будет ошибка:

pavel=# INSERT INTO pg_collation 
(collname,collnamespace,collowner,collprovider,collisdeterministic,collencoding,collcollate,collctype,collversion) 
VALUES ('default2',11,10,'d','t',-1,'C','','');
ERROR:  null value in column "oid" of relation "pg_collation" violates not-null constraint
DETAIL:  Failing row contains (null, default2, 11, 10, d, t, -1, C, , ).

Не получилось в версии выше 11 получить НЕ ноль в строке INSERT 0 1 после вставки.

Поэтому получается, что то описание, которое было в переписке с postgresql.org — верное. Теперь первый ноль — это «так исторически сложилось».


Be the first to comment

Leave a Reply

Ваш Mail не будет опубликован.


*