Một số câu trả lời được đề xuất để sử dụng mẫu: kiểm tra nếu vai trò không tồn tại và nếu không thì hãy ra CREATE ROLE
lệnh. Điều này có một bất lợi: điều kiện chủng tộc. Nếu ai đó khác tạo một vai trò mới giữa kiểm tra và phát hành CREATE ROLE
lệnh thì CREATE ROLE
rõ ràng là không thành công với lỗi nghiêm trọng.
Để giải quyết vấn đề trên, nhiều câu trả lời khác đã đề cập đến việc sử dụng PL/pgSQL
, phát hành CREATE ROLE
vô điều kiện và sau đó bắt các ngoại lệ từ cuộc gọi đó. Chỉ có một vấn đề với các giải pháp này. Họ âm thầm loại bỏ bất kỳ lỗi nào, bao gồm cả những lỗi không được tạo ra bởi thực tế rằng vai trò đã tồn tại. CREATE ROLE
cũng có thể tạo ra các lỗi khác và mô phỏng IF NOT EXISTS
chỉ nên tắt lỗi khi vai trò đã tồn tại.
CREATE ROLE
ném duplicate_object
lỗi khi vai trò đã tồn tại. Và trình xử lý ngoại lệ chỉ nên bắt một lỗi này. Như các câu trả lời khác đã đề cập, bạn nên chuyển lỗi nghiêm trọng thành thông báo đơn giản. Các IF NOT EXISTS
lệnh PostgreSQL khác thêm , skipping
vào thông điệp của chúng, vì vậy để nhất quán, tôi cũng sẽ thêm nó vào đây.
Đây là mã SQL đầy đủ để mô phỏng CREATE ROLE IF NOT EXISTS
với sự lan truyền ngoại lệ và sqlstate chính xác:
DO $$
BEGIN
CREATE ROLE test;
EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;
Kiểm tra đầu ra (được gọi hai lần qua DO và sau đó trực tiếp):
$ sudo -u postgres psql
psql (9.6.12)
Type "help" for help.
postgres=# \set ON_ERROR_STOP on
postgres=# \set VERBOSITY verbose
postgres=#
postgres=# DO $$
postgres$# BEGIN
postgres$# CREATE ROLE test;
postgres$# EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
DO
postgres=#
postgres=# DO $$
postgres$# BEGIN
postgres$# CREATE ROLE test;
postgres$# EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
NOTICE: 42710: role "test" already exists, skipping
LOCATION: exec_stmt_raise, pl_exec.c:3165
DO
postgres=#
postgres=# CREATE ROLE test;
ERROR: 42710: role "test" already exists
LOCATION: CreateRole, user.c:337