Koşullu olarak bir psql komut dosyasını (değişken bir değere dayalı olarak) nasıl durdurabilirim?


10

Aşağıdaki örneği ele alalım (psql betiğinin başından itibaren):

\c :db_to_run_on

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

Şimdi bunu komut tarafından çalıştırılıyorsa

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

sonra sadece çalışır ve kullanıcı mutlu. Peki ya belirtmeye karar verirse -v db_to_run_on=production_database? (Diyelim ki, tıpkı insanlar zaman zaman koşuyor gibi rm -rf / # don't try this at home!!!.) Umarım bu tablonun yeni bir yedeği vardır ...

Böylece soru ortaya çıkıyor: bir betiğe geçirilen değişkenler nasıl kontrol edilir ve değerlerine göre daha fazla işlem nasıl durdurulur?

Yanıtlar:


13

psqlHata halinde komutları çalıştırmayı durduran bir seçenek var , bu ON_ERROR_STOP. Bir şekilde bir hata oluşturabilirsek, bu istediğimizi yapar.

Sorun, değişkeni test etmemiz ve bir şekilde bir hata üretmemiz gerektiğidir. Biri kontrol yapılarını kullanamadığı için psql(hiçbiri olmadığı için) *, tek fikrim test için SQL kullanmaktı. Şartlı olarak bir hata üretmek pl/pgsqloldukça iyi bir şeydir , bu yüzden hata oluşturacak bir fonksiyon yazdım. Şimdi bu işlevi basit bir CASEyapıdan çağırabilirim . Basit bir örnek:

-- 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;

*: Kabuktan sonraki herhangi bir kabuk komutunu \!ve koşulunu kullanabilirsiniz , ancak \!yeni bir kabuk açtığından, herhangi bir şey yürütmenin geçerli psql betiği için herhangi bir etkisi yoktur.


\set ON_ERROR_STOP on- Güzel!
— msciwoj

5

PostgreSQL 10

PostgreSQL 10, psql'ye koşul getiriyor. Bu artık sorun değil.

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

Sanırım sen de kullanabilirsin DO..

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

... PostgreSQL 10 çalıştırıyorsanız artık sorun değil
— Steve Bennett

1
@SteveBennett bu konuda oldukça net. Ama bence bu tamamen doğru değil. Sunucu arka ucuna değil, yalnızca sürüm 10'da psql'ye ihtiyacınız vardır.
— Evan Carroll

Vay ilginçmiş. Ama evet, eski versiyonlar çok uzun süre kalabilir.
— Steve Bennett

Ayrıca edebilir \set ON_ERROR_STOP 1ve daha sonra \if yes \endifpsql'in sürüm 10 veya daha yüksek gerektirecek. :) (Önceki sürümler \ifgeçersiz olmaktan şikayet edecek ve sonra kapanacaktır .)
— Wildcard

1

Bulduğum şey benim için çok iyi çalışıyor, daha sonra psql içine boru gibi bir SQL dosyası oluşturmak için bir komut dosyası dili kullanmaktır:

#!/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"

Sonra, bunu bir sürücü komut dosyasından çağırıyorum:

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

Sürücü betiğim genellikle bir Rake dosyasıdır, ancak fikri anlarsınız.


2
İyi evet. Anladım :) Girişinizi takdir ederken, tam olarak kaçınmak istediğim şey bu - ek bir katman kullanarak.
— dezso

1

Dezso'nun cevabının daha özlü bir versiyonu:

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

Daha sonra bunu şöyle çağırabilirsiniz:

\set ON_ERROR_STOP on

SELECT CASE WHEN (
  SELECT COUNT(*) FROM mytable
) > 0 THEN pg_temp.err('Already loaded') END;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.