পোস্টগ্র্রেএসকিউএল রোল (ব্যবহারকারী) তৈরি না থাকলে এটি উপস্থিত নেই


122

পোস্টগ্রিজএসকিউএল 9.1 এ কোনও রোল তৈরি করতে আমি কীভাবে এসকিউএল স্ক্রিপ্ট লিখব, তবে যদি ইতিমধ্যে উপস্থিত থাকে তবে ত্রুটি বাড়ানো ছাড়া?

বর্তমান স্ক্রিপ্টটি সহজভাবে রয়েছে:

CREATE ROLE my_user LOGIN PASSWORD 'my_password';

ব্যবহারকারী ইতিমধ্যে উপস্থিত থাকলে এটি ব্যর্থ হয়। আমি এর মতো কিছু চাই:

IF NOT EXISTS (SELECT * FROM pg_user WHERE username = 'my_user')
BEGIN
    CREATE ROLE my_user LOGIN PASSWORD 'my_password';
END;

... তবে এটি কাজ করে না - IFপ্লেইন এসকিউএলে সমর্থিত বলে মনে হচ্ছে না।

আমার একটি ব্যাচ ফাইল রয়েছে যা একটি পোস্টগ্র্যাসকিউএল 9.1 ডাটাবেস, ভূমিকা এবং অন্যান্য কিছু জিনিস তৈরি করে। এটি psql.exe কল করে, চালানোর জন্য একটি এসকিউএল স্ক্রিপ্টের নামে পাস করে। এখন পর্যন্ত এই সমস্ত স্ক্রিপ্টগুলি সরল এসকিউএল এবং আমি পিএল / পিজিএসকিউএল এবং যদি সম্ভব হয় তবে এড়াতে চাই।

উত্তর:


156

আপনি যা মনে রেখেছিলেন তার অনুরূপ ফ্যাশনে সরল করুন:

DO
$do$
BEGIN
   IF NOT EXISTS (
      SELECT FROM pg_catalog.pg_roles  -- SELECT list can be empty for this
      WHERE  rolname = 'my_user') THEN

      CREATE ROLE my_user LOGIN PASSWORD 'my_password';
   END IF;
END
$do$;

( @ গ্রেডের মন্তব্যে @ এ_ ঘোড়া_বিহীন_নামের উত্তরে বিল্ডিং এবং উন্নত ।)

উদাহরণস্বরূপ, এর বিপরীতে CREATE TABLEকোনও IF NOT EXISTSদফা নেই CREATE ROLE(কমপক্ষে pg 12 অবধি)। এবং আপনি সরল এসকিউএল এ গতিশীল ডিডিএল বিবৃতি কার্যকর করতে পারবেন না

"পিএল / পিজিএসকিউএল এড়ানোর" জন্য আপনার অনুরোধ অন্য একটি পিএল ব্যবহার না করেই অসম্ভব। DOবিবৃতি ব্যবহারসমূহ ডিফল্ট পদ্ধতিগত ভাষা হিসেবে plpgsql। বাক্য গঠনটি সুস্পষ্ট ঘোষণা বাদ দিতে দেয়:

DO [ LANGUAGE lang_name ] code
... কোডটিতে প্রক্রিয়াকরণী ভাষার নাম লেখা আছে om যদি বাদ দেওয়া হয়, তবে ডিফল্ট হয় ।
lang_name
plpgsql


1
@ অ্যালবার্তো : পিজি_উজার এবং পিজি_রোলেস উভয়ই সঠিক। এখনও বর্তমান সংস্করণ 9.3 এ কেস এবং এটি শীঘ্রই যে কোনও সময় পরিবর্তন করতে যাচ্ছে না।
এরউইন ব্র্যান্ডস্টেটার

2
@ কেন: $আপনার ক্লায়েন্টের যদি বিশেষ অর্থ থাকে তবে আপনার ক্লায়েন্টের সিনট্যাক্স নিয়ম অনুসারে আপনাকে এড়াতে হবে। লিনাক্স শেলটি $দিয়ে পালানোর চেষ্টা করুন \$। বা একটি নতুন প্রশ্ন শুরু করুন - মন্তব্যগুলি জায়গা নয়। আপনি প্রসঙ্গের জন্য সর্বদা এটির সাথে লিঙ্ক করতে পারেন।
এরউইন ব্র্যান্ডস্টেটার

1
আমি .6. using ব্যবহার করছি, এবং যদি কোনও ব্যবহারকারী নলোগিন দিয়ে তৈরি করা হয়েছিল, তারা pg_user সারণীতে প্রদর্শিত হবে না, তবে pg_roles সারণীতে প্রদর্শিত হবে। Pg_roles এখানে কি আরও ভাল সমাধান হতে পারে?
জেস

2
@ এরউইন ব্র্যান্ডসটেটার এই নোলোগিনের ভূমিকাগুলির জন্য কাজ করে না। তারা pg_roles এ দেখায় তবে pg_user এ নয়।
গ্রেগরি অ্যারেনিয়াস

2
এই সমাধানটি একটি রেস-শর্তে ভুগছে। একটি নিরাপদ রূপটি এই উত্তরে নথিভুক্ত করা হয়েছে
blubb

60

যদি ক্রমাগত-সংহতকরণ পরিবেশে সাধারণ যেমন একই পোস্টগ্রিজ ক্লাস্টারে (ডিবি সার্ভার) একই সাথে দুটি স্ক্রিপ্ট কার্যকর করা হয় তবে গ্রহণযোগ্য উত্তরটি রেসের শর্তে ভুগছে ।

ভূমিকাটি তৈরি করার চেষ্টা করা সাধারণভাবে নিরাপদ এবং যখন এটি তৈরি করা হয় তখন সমস্যার সাথে করণীয় সহকারে ডিল করুন:

DO $$
BEGIN
  CREATE ROLE my_role WITH NOLOGIN;
  EXCEPTION WHEN DUPLICATE_OBJECT THEN
  RAISE NOTICE 'not creating role my_role -- it already exists';
END
$$;

2
আমি এইভাবে এটি উপস্থিত থাকা লক্ষণীয় বীচুস পছন্দ করি।
মাতিয়াস বারোন

2
DUPLICATE_OBJECTএই ক্ষেত্রে সুনির্দিষ্ট শর্ত হ'ল, যদি আপনি কেবল সমস্ত শর্তের সাথেই ধরতে চান না OTHERS
ডানেক ডুভাল

43

বা ভূমিকা যদি কোনও ডিবি অবজেক্টের মালিক না হয় তবে যে কেউ এটি ব্যবহার করতে পারবেন:

DROP ROLE IF EXISTS my_user;
CREATE ROLE my_user LOGIN PASSWORD 'my_password';

তবে কেবলমাত্র এই ব্যবহারকারীকে বাদ দিলে কোনও ক্ষতি হবে না।


10

বাশ বিকল্প ( বাশ স্ক্রিপ্টিং জন্য ):

psql -h localhost -U postgres -tc \
"SELECT 1 FROM pg_user WHERE usename = 'my_user'" \
| grep -q 1 \
|| psql -h localhost -U postgres \
-c "CREATE ROLE my_user LOGIN PASSWORD 'my_password';"

(প্রশ্নের উত্তর নয়! এটি কেবল তাদের পক্ষে যারা দরকারী হতে পারে)


3
এটি FROM pg_roles WHERE rolnameপরিবর্তে পড়তে হবেFROM pg_user WHERE usename
বার্থ

8

এখানে plpgsql ব্যবহার করে একটি জেনেরিক সমাধান দেওয়া হয়েছে:

CREATE OR REPLACE FUNCTION create_role_if_not_exists(rolename NAME) RETURNS TEXT AS
$$
BEGIN
    IF NOT EXISTS (SELECT * FROM pg_roles WHERE rolname = rolename) THEN
        EXECUTE format('CREATE ROLE %I', rolename);
        RETURN 'CREATE ROLE';
    ELSE
        RETURN format('ROLE ''%I'' ALREADY EXISTS', rolename);
    END IF;
END;
$$
LANGUAGE plpgsql;

ব্যবহার:

posgres=# SELECT create_role_if_not_exists('ri');
 create_role_if_not_exists 
---------------------------
 CREATE ROLE
(1 row)
posgres=# SELECT create_role_if_not_exists('ri');
 create_role_if_not_exists 
---------------------------
 ROLE 'ri' ALREADY EXISTS
(1 row)

8

কিছু উত্তর প্যাটার্ন ব্যবহার করার পরামর্শ দিয়েছে: ভূমিকাটির অস্তিত্ব নেই কিনা তা পরীক্ষা করুন এবং তা না হলে CREATE ROLEকমান্ড জারি করুন । এটির একটি অসুবিধা রয়েছে: জাতির শর্ত। যদি অন্য কেউ চেক এবং CREATE ROLEকমান্ড জারি করার মধ্যে একটি নতুন ভূমিকা তৈরি করে তবে CREATE ROLEঅবশ্যই মারাত্মক ত্রুটিতে ব্যর্থ হয়।

উপরের সমস্যা সমাধানের জন্য, আরও অন্যান্য উত্তর ইতিমধ্যে ব্যবহারের কথা উল্লেখ করেছে PL/pgSQL, CREATE ROLEনিঃশর্ত জারি করে এবং তারপরে সেই কল থেকে ব্যতিক্রম ধরা। এই সমাধানগুলির সাথে একটি মাত্র সমস্যা আছে। তারা নিঃশব্দে যে কোনও ত্রুটি বাদ দেয়, সেগুলি সহ যেগুলি ইতিমধ্যে ভূমিকাটি বিদ্যমান রয়েছে তা দ্বারা উত্পন্ন হয় না। CREATE ROLEঅন্যান্য ত্রুটিগুলিও ফেলে দিতে পারে এবং IF NOT EXISTSভূমিকা ইতিমধ্যে উপস্থিত থাকলে সিমুলেশনটি কেবল ত্রুটিটি নিঃশব্দ করা উচিত।

CREATE ROLEduplicate_objectভূমিকা ইতিমধ্যে উপস্থিত থাকলে ত্রুটি নিক্ষেপ করুন । এবং ব্যতিক্রম হ্যান্ডলার কেবল এই একটি ত্রুটি ধরা উচিত। অন্যান্য উত্তরের হিসাবে উল্লেখ করা হয়েছে যে মারাত্মক ত্রুটিটিকে সাধারণ নোটিশে রূপান্তর করা ভাল ধারণা। অন্যান্য PostgreSQL IF NOT EXISTSকমান্ডগুলি , skippingতাদের বার্তায় যুক্ত করে, তাই ধারাবাহিকতার জন্য আমি এটি এখানেও যুক্ত করছি।

CREATE ROLE IF NOT EXISTSসঠিক ব্যতিক্রম এবং স্ক্যালস্টেট প্রচারের সিমুলেশন করার জন্য এখানে সম্পূর্ণ এসকিউএল কোড রয়েছে :

DO $$
BEGIN
CREATE ROLE test;
EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;

পরীক্ষার আউটপুট (ডিও এর মাধ্যমে দু'বার বলা হয় এবং তারপরে সরাসরি):

$ 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

2
ধন্যবাদ. কোনও রেসের শর্ত নেই, শক্ত ব্যতিক্রম ধরা নেই, নিজের লেখার পরিবর্তে পোস্টগ্রিসের নিজস্ব বার্তা মোড়ানো।
স্টেফানো তাসচিনি

1
প্রকৃতপক্ষে! এটি বর্তমানে এখানে একমাত্র সঠিক উত্তর, যা জাতিদের শর্তে ভুগছে না এবং প্রয়োজনীয় নির্বাচনী ত্রুটি পরিচালনা পরিচালনা করে। এটি সত্যই দুঃখের বিষয় যে এই উত্তরটি (সম্পূর্ণ সঠিক নয়) শীর্ষ উত্তরটি আরও 100 পয়েন্ট সংগ্রহ করার পরে উপস্থিত হয়েছিল।
vog

1
আপনাকে স্বাগতম! আমার সমাধানটি এসকিউএলস্টেটকেও প্রচার করে তাই আপনি যদি অন্য পিএল / এসকিউএল স্ক্রিপ্টের বিবৃতি বা এসকিউএল সংযোজকের সাথে অন্য কোনও ভাষা থেকে কল করেন তবে আপনি সঠিক এসকিউএলস্টেট পাবেন।
পালি

6

আপনি যখন 9.x এ আছেন, আপনি এটি একটি ডিও বিবৃতিতে গুটিয়ে রাখতে পারেন:

do 
$body$
declare 
  num_users integer;
begin
   SELECT count(*) 
     into num_users
   FROM pg_user
   WHERE usename = 'my_user';

   IF num_users = 0 THEN
      CREATE ROLE my_user LOGIN PASSWORD 'my_password';
   END IF;
end
$body$
;

নির্বাচন করা উচিত p নির্বাচিত গণনা (*) থেকে নাম_উজারগুলিতে পিগ_রোলে যেখানে রোলনাম = 'ডেটা_আরডব্লিউ'; `অন্যথায় এটি কাজ করবে না
মিরো

6

আমার দলটি একটি সার্ভারে একাধিক ডাটাবেস নিয়ে একটি পরিস্থিতি SELECT * FROM pg_catalog.pg_userছুঁড়েছিল , আপনি কোন ডাটাবেসের সাথে সংযুক্ত ছিলেন তার উপর নির্ভর করে @ আরউইন-ব্র্যান্ডসেটটার এবং @ এ_হর্স_উইথ_নো নাম দ্বারা প্রস্তাবিত, আরওএল কোনও ফেরত দেয়নি। শর্তসাপেক্ষ ব্লক কার্যকর করা হয়েছে, এবং আমরা আঘাত role "my_user" already exists

দুর্ভাগ্যক্রমে আমরা সঠিক অবস্থার বিষয়ে নিশ্চিত নই, তবে এই সমাধানটি সমস্যাটি ঘিরে কাজ করে:

        DO  
        $body$
        BEGIN
            CREATE ROLE my_user LOGIN PASSWORD 'my_password';
        EXCEPTION WHEN others THEN
            RAISE NOTICE 'my_user role exists, not re-creating';
        END
        $body$

অন্যান্য ব্যতিক্রমগুলি অস্বীকার করার জন্য এটি সম্ভবত আরও নির্দিষ্ট করা যেতে পারে।


3
Pg_user টেবিলটিতে কেবলমাত্র লোগিন রয়েছে এমন ভূমিকা অন্তর্ভুক্ত বলে মনে হচ্ছে। কোনও ভূমিকায় যদি নলোগিন থাকে তবে এটি পিজি_উজারে প্রদর্শিত হবে না, কমপক্ষে পোস্টগ্র্যাসকিউএল 10 তে
গ্রেগরি অ্যারেনিয়াস

2

আপনি আপনার ব্যাচ ফাইলে এটির আউটপুট বিশ্লেষণ করে এটি করতে পারেন:

SELECT * FROM pg_user WHERE usename = 'my_user'

এবং তারপরে psql.exeভূমিকাটির অস্তিত্ব না থাকলে আবার চলমান ।


2
"ব্যবহারকারীর নাম" কলামটি বিদ্যমান নেই। এটি "ব্যবহারের নাম" হওয়া উচিত।
মোহাম্মদ সৌদিদান

3
"ইউজারনেম" হ'ল এটির অস্তিত্ব নেই। :)
গ্যারেন

1
দয়া করে pg_user ভিউ ডকটি দেখুন। 7.4-9.6 সংস্করণগুলিতে কোনও "ব্যবহারকারীর নাম" কলাম নেই, "ব্যবহারের নাম" সঠিক।
শেভা 19

1

সিমুলেট ক্রিয়েট ডেটাবেসের ক্ষেত্রে একই সমাধান যদি পোস্টগ্রিসকিউএল এর জন্য উপস্থিত না থাকে? কাজ করা উচিত - একটি পাঠাতে CREATE USER …করতে \gexec

পিএসএইচএল এর মধ্যে থেকে কার্যবিধির

SELECT 'CREATE USER my_user'
WHERE NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'my_user')\gexec

শেল থেকে কার্যকরী

echo "SELECT 'CREATE USER my_user' WHERE NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'my_user')\gexec" | psql

আরও তথ্যের জন্য গৃহীত উত্তর দেখুন ।


আপনার সমাধানটির এখনও একটি রেসের শর্ত রয়েছে যা আমি আমার উত্তরে বর্ণনা করেছি stackoverflow.com/a/55954480/7878845 আপনি যদি আপনার শেল স্ক্রিপ্টটি সমান্তরালভাবে আরও বেশি বার চালনা করেন তবে আপনি ERROR পান: ভূমিকা "my_user" ইতিমধ্যে বিদ্যমান রয়েছে
পালি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.