सशर्त स्क्रिप्ट (चर मान के आधार पर) को सशर्त रूप से कैसे रोकें?


10

आइए निम्नलिखित उदाहरण पर विचार करें (एक psql स्क्रिप्ट की शुरुआत से):

\c :db_to_run_on

TRUNCATE the_most_important_table;
-- tried to avoid similarities to anything that exists out there

अब अगर इसे कमांड द्वारा चलाया जाता है

psql [connection details] -v db_to_run_on=\'dev_database\'

तब यह बस चलता है और उपयोगकर्ता खुश है। लेकिन क्या (यदि) वह निर्दिष्ट करने का फैसला करता है -v db_to_run_on=production_database? (मान लेते हैं कि ऐसा हो सकता है, ठीक वैसे ही जैसे लोग rm -rf / # don't try this at home!!!महासागर में दौड़ते हैं ।) उम्मीद है कि उस टेबल का एक नया बैकअप हो ...

तो सवाल उठता है: एक स्क्रिप्ट में पारित चर की जांच कैसे करें और उनके मूल्य के आधार पर आगे की प्रक्रिया को रोकें?

जवाबों:


13

एक विकल्प है psqlजिसमें त्रुटि पर कमांड निष्पादित करना बंद कर देता है, यह है ON_ERROR_STOP। अगर हम किसी तरह एक त्रुटि उठा सकते हैं, तो यह वही होगा जो हम चाहते हैं।

समस्या यह है कि हमें चर का परीक्षण करना होगा और किसी तरह त्रुटि उत्पन्न करनी होगी। चूंकि एक में नियंत्रण संरचनाओं का उपयोग नहीं किया जा सकता है psql(क्योंकि कोई नहीं हैं) *, मेरा एकमात्र विचार परीक्षण के लिए एसक्यूएल का उपयोग करना था। खैर, सशर्त pl/pgsqlरूप से एक त्रुटि उत्पन्न करना कुछ ऐसा है जो काफी अच्छा है, इसलिए मैंने एक फ़ंक्शन लिखा है जो एक त्रुटि उत्पन्न करेगा। मैं अब एक साधारण CASEसंरचना से इस फ़ंक्शन को कॉल कर सकता हूं । एक सरल उदाहरण:

-- let's assume for clarity that there is no function with this name in the database
CREATE OR REPLACE FUNCTION error_generator()
RETURNS boolean AS
$body$
BEGIN
    RAISE 'Meaningful error message here';
    RETURN FALSE; -- just for aesthetical purposes
END;
$body$
LANGUAGE plpgsql;

\set ON_ERROR_STOP on

BEGIN;

-- test for the variable value
-- notice that if :var is not set, it fails as well (with a syntax error)
SELECT CASE WHEN 1 = :var THEN error_generator() ELSE TRUE END;

INSERT INTO test_table (integer_value, text_value)
VALUES (:var, 'something');

COMMIT;

*: आप शेल के बाद \!और सशर्त किसी भी शेल कमांड का उपयोग कर सकते हैं , लेकिन चूंकि \!एक नया शेल खुलता है, इसलिए किसी भी चीज को निष्पादित करने से वर्तमान पीएसएल स्क्रिप्ट के लिए कोई प्रभाव नहीं पड़ता है।


\set ON_ERROR_STOP on- अच्छा!
msciwoj

5

PostgreSQL 10

PostgreSQL 10 psql में सशर्तता लाता है। यह अब कोई मुद्दा नहीं है।

\if :db_to_run_on = 'dev_database'
  TRUNCATE the_most_important_table;
\endif

मुझे लगता है कि आप भी इस्तेमाल कर सकते हैं DO..

\if :db_to_run_on != 'dev_database'
do $$
  BEGIN
    RAISE 'Meaningful error message here';
  END;
$$ LANGUAGE plpgsql;
\endif

... अब कोई मुद्दा नहीं है अगर आप PostgreSQL 10. हो रहे हैं
स्टीव बेनेट

1
@SteveBennett उस बारे में बहुत स्पष्ट है। लेकिन मुझे लगता है कि यह पूरी तरह सच नहीं है। आपको केवल संस्करण 10 पर psql की आवश्यकता है, न कि सर्वर बैकएंड की।
इवान कैरोल

ओह दिलचस्प है। लेकिन हाँ, पुराने संस्करण एक looooong समय के आसपास रह सकते हैं।
स्टीव बेनेट

तुम भी \set ON_ERROR_STOP 1और तब \if yes \endifpsql संस्करण 10 या उच्चतर की आवश्यकता हो सकती है। :) (पहले के संस्करण \ifअमान्य होने के बारे में शिकायत करेंगे , और फिर छोड़ देंगे ।)
वाइल्डकार्ड

1

मैंने जो पाया वह मेरे लिए बहुत अच्छी तरह से काम करता है एक एसक्यूएल फ़ाइल बनाने के लिए एक स्क्रिप्टिंग भाषा का उपयोग करना, जिसे मैं पीएसएल में पाइप करता हूं, कुछ इस तरह है:

#!/usr/bin/env ruby

raise "Not a good database name: #{ARGV.first.inspect}" unless ARGV.first =~ /^(dev|test)/

puts "\\timing off"
puts "set client_min_messages='warning';"
puts
puts "TRUNCATE the_most_important_table;"
puts "-- more commands"

फिर, मैं इसे ड्राइवर स्क्रिप्ट से कॉल करता हूं:

#!/bin/bash
/usr/bin/ruby generator ${1} | /usr/bin/psql --dbname=${1} --file=- --single-transaction

मेरी ड्राइवर स्क्रिप्ट आमतौर पर एक रेक फ़ाइल है, लेकिन आपको यह विचार मिलता है।


2
सही है। मुझे यह मिला :) जबकि मैं आपके इनपुट की सराहना करता हूं, यह वही है जो मैं बचना चाहता हूं - एक अतिरिक्त परत का उपयोग करना।
dezso

1

डेज़ो के उत्तर का एक और संक्षिप्त संस्करण:

CREATE OR REPLACE FUNCTION pg_temp.err(msg varchar) RETURNS boolean     
AS $$ BEGIN RAISE '%',msg; END; $$ LANGUAGE plpgsql;

आप तब इसे कॉल कर सकते हैं जैसे:

\set ON_ERROR_STOP on

SELECT CASE WHEN (
  SELECT COUNT(*) FROM mytable
) > 0 THEN pg_temp.err('Already loaded') END;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.