Beberapa jawaban menyarankan untuk menggunakan pola: periksa apakah peran tidak ada dan jika tidak maka keluarkan CREATE ROLEperintah. Ini memiliki satu kelemahan: kondisi balapan. Jika orang lain membuat peran baru antara check dan mengeluarkan CREATE ROLEperintah, makaCREATE ROLE jelas gagal dengan kesalahan fatal.
Untuk mengatasi masalah di atas, lebih banyak jawaban lain yang telah disebutkan penggunaan PL/pgSQL, mengeluarkan CREATE ROLEtanpa syarat dan kemudian menangkap pengecualian dari panggilan itu. Hanya ada satu masalah dengan solusi ini. Mereka diam-diam menjatuhkan semua kesalahan, termasuk yang tidak dihasilkan oleh fakta bahwa peran sudah ada. CREATE ROLEdapat membuang juga kesalahan lain dan simulasi IF NOT EXISTSharus membungkam kesalahan hanya jika peran sudah ada.
CREATE ROLEmelempar duplicate_objectkesalahan saat peran sudah ada. Dan penangan pengecualian harus menangkap hanya satu kesalahan ini. Seperti jawaban lain yang disebutkan, sebaiknya ubah kesalahan fatal menjadi pemberitahuan sederhana. IF NOT EXISTSPerintah PostgreSQL lainnya menambahkan, skipping ke dalam pesan mereka, jadi untuk konsistensi saya juga menambahkannya di sini.
Berikut adalah kode SQL lengkap untuk simulasi CREATE ROLE IF NOT EXISTSdengan pengecualian yang benar dan propagasi sqlstate:
DO $$
BEGIN
CREATE ROLE test;
EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;
Output tes (dipanggil dua kali melalui DO dan kemudian secara langsung):
$ 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