Това е малко брадавица в изпълнението на IF NOT EXISTS
за таблици и схеми. По принцип те са опит за изместване и PostgreSQL не се справя чисто с условията на състезание. Безопасно е, но е грозно.
Ако схемата се създава едновременно в друга сесия, но все още не е ангажирана, тогава тя едновременно съществува и не съществува, в зависимост от това кой сте и как изглеждате. Не е възможно други транзакции да "видят" новата схема в системните каталози, защото тя не е ангажирана, така че е запис в pg_namespace
не се вижда от други транзакции. Така че CREATE SCHEMA
/ CREATE TABLE
се опитва да го създаде, защото, що се отнася до него, обектът не съществува.
Това обаче вмъква ред в таблица с уникално ограничение. Уникалните ограничения трябва да могат да виждат необвързани редове, за да функционират. Така вмъкването блокира (спира) до първата транзакция, извършила CREATE
или се ангажира, или се връща назад. Ако се ангажира, втората транзакция се прекъсва, защото се е опитала да вмъкне ред, който нарушава уникално ограничение. CREATE SCHEMA
не е достатъчно умен, за да хване този случай и да опита отново.
За правилно коригиране на това PostgreSQL вероятно ще се нуждае от заключване на предикат, където може да заключи потенциала за ред . Това може да бъде добавено като част от текущата работа за прилагане на UPSERT
.
За тези конкретни команди PostgreSQL вероятно би могъл да извърши мръсно четене на системните каталози, където може да види незавършени промени. След това може да изчака необвързаната транзакция да се ангажира или върне назад, да направи отново мръсното четене, за да види дали някой друг чака, и да опита отново. Но това би имало състояние на състезание, при което някой друг може да създаде схемата между момента, в който извършвате четене, за да проверите за нея, и когато се опитвате да я създадете.
Така че IF NOT EXISTS
вариантите ще трябва да:
- Проверете дали схемата съществува; ако стане, завършете, без да правите нищо.
- Опит за създаване на таблицата
- Ако създаването е неуспешно поради уникална грешка в ограничението, опитайте отново от началото
- Ако създаването на таблица е успешно, завършете
Доколкото знам, никой не го е приложил или са опитали и не е прието. При този подход биха възникнали възможни проблеми със скоростта на изгаряне на идентификатора на транзакция и т.н.
Мисля, че това е някакъв вид грешка, но това е грешка от типа „да, знаем“, а не от типа „ще се заемем да поправим това“. Чувствайте се свободни да публикувате в pgsql-bugs за това; най-малкото в документацията трябва да се споменава това предупреждение относно IF NOT EXISTS
.
Не препоръчвам да правите DDL едновременно по този начин.