Melewati argumen ke psql

10

Saya menjalankan skrip plpgsql di Postgres 8.3 - Saya ingin meneruskan argumen ke skrip ini melalui psql. Saat ini saya sedang menjalankan skrip seperti:

psql -d database -u user -f update_file.sql 

Saya menemukan tautan ini yang menjelaskan variabel lingkungan PGOPTIONS, tetapi itu tidak berfungsi untuk argumen "khusus". yaitu saya menerima kesalahan karena pengaturan tidak tercantum dalam file postgres.conf.

-bash-3.2$ export PGOPTIONS='--pretend=true'
-bash-3.2$ psql -d my_db -f update_database.sql
psql: FATAL:  unrecognized configuration parameter "pretend"

Ada ide lain? Idealnya saya ingin menghindari variabel lingkungan ...

Jmoney38
sumber
Saya pikir Anda mencari -vargumen psql.
dezso
Saya mencoba - untuk mengambilnya dalam skrip, saya memanggil "SELECT current_setting ('pretend') INTO _result" - tidak berhasil.
Jmoney38

Jawaban:

5

Sebenarnya, tidak ada yang namanya "skrip plpgsql" - PL / pgSQL adalah bahasa prosedural default PostgreSQL. Entah itu skrip SQL atau fungsi / prosedur plpgsql. Contoh Anda tampaknya menunjukkan skrip SQL.

Anda bisa membuat fungsi (sisi server) plpgsql (atau sql) sebagai gantinya, yang mengambil sejumlah argumen. Ini sangat sederhana asalkan argumennya values. Akan sedikit lebih rumit jika argumen menyertakan pengidentifikasi. Maka Anda harus menggunakan PL / pgSQL dengan SQL dinamis dan EXECUTE.

PL / pgSQL sudah diinstal sebelumnya secara default di PostgreSQL 9.0 atau yang lebih baru. Anda harus menginstalnya sekali per basis data di Postgres 8.3, meskipun:

CREATE LANGUGAGE plpgsql;

Berbicara tentang versi: Anda harus mempertimbangkan untuk meningkatkan ke versi PostgreSQL saat ini. v8.3 sudah sangat tua sekarang, akhir kehidupan di awal 2013.

Karena Anda tampaknya memiliki skrip SQL yang siap saya akan menunjukkan fungsi SQL. Fungsi dummy sederhana dengan dua argumen integer:

CREATE OR REPLACE FUNCTION func(int, int)
    LANGUAGE sql RETURNS void AS 
$func$
    UPDATE tbl1 SET col1 = $1 WHERE id = $2;
    UPDATE tbl2 SET col1 = $1 WHERE id = $2;
$func$;

Anda dapat menemukan banyak contoh yang lebih canggih untuk plpgsql di sini di dba.SE atau SO .

Anda dapat memanggil fungsi ini dan menyerahkan parameter dalam skrip shell: Contoh dasar untuk panggilan dalam skrip shell yang menggunakan parameter input untuk parameter integer (tidak ada tanda kutip tunggal di sekitar nilai yang diperlukan):

psql mydb -c "SELECT func($1, $2)"

Atau dengan tipe data apa pun:

psql mydb -c "SELECT func2('$1'::text, '$2'::numeric)"

-cmengeksekusi satu string perintah dan kemudian keluar. Lebih lanjut tentang argumen baris perintah psql dalam manual .

Erwin Brandstetter
sumber
Terima kasih atas tanggapannya - Saya sebenarnya cukup tahu tentang plpgsql - Skrip yang saya maksud adalah file yang berisi banyak fungsi. Saya memiliki fungsi "utama" dalam arti pemrograman berorientasi-C. 2 baris terakhir dalam skrip / file adalah 1) memanggil fungsi "utama" dan kemudian 2) menjatuhkan fungsi. Jadi, dalam pengaturan ini, saya pada dasarnya memiliki skrip mandiri yang dapat dijalankan untuk melakukan pekerjaan (psql -f). Saya suka poin Anda tentang memanggil fungsi dengan "aplikasi args" melalui psql -c. Saya mungkin akan pergi rute itu, karena saya tidak bisa pergi rute menambahkan nilai ke file postgres.conf.
Jmoney38
5

Untuk menambahkan fungsionalitas lain untuk -v... Jika Anda mencoba menambahkan kutipan, tambahkan di baris perintah:

psql -v action="'drop'"

dan ini akan menjalankan kode untuk:

select * where :action;

Sama seperti

select * where 'drop';
Klein
sumber
4

Coba -v:

$ psql -U postgres -v something=\'blah-blah\'
psql (9.1.3)
Type "help" for help.

postgres=# select :something;
 ?column?
----------
 blah-blah
(1 row)

Jika Anda ingin menggunakan current_settingdan SETatau setval, Anda harus menambahkan baris postgresql.confuntuk menambahkan opsi.

dezso
sumber
2

Dari pengalaman saya, melakukan dereffing variabel psql di dalam deklarasi plpgsql seperti dalam CREATE FUNCTION BEGIN atau DO BEGIN menghasilkan kesalahan sintaksis:

/tmp $ psql -U jmindek -v action=drop
psql (9.3.4)
Type "help" for help.

jmindek=# select :'action';
 ?column? 
----------
 drop
(1 row)

jmindek=# DO $$ BEGIN RAISE INFO 'The value in variable action is (%)',:x; END $$;     
ERROR:  syntax error at or near ":"
LINE 1: ... RAISE INFO 'The value in variable action is (%)',:x; END $$...

Solusi saya adalah membuat tabel sementara dengan satu kolom dan menyimpan nilai di dalamnya. Tabel sementara ini dapat diakses melalui plpgsql dan dengan demikian saya dapat melewatkan variabel psql yang digunakan dalam blok DO.

 ~ $ psql -v action=drop
psql (9.3.4)
Type "help" for help.

jmindek=# create temporary table actions (type text);                                                             CREATE TABLE
jmindek=# insert into actions values (:'action');                                                                 INSERT 0 1
jmindek=# do $$                                                                                                   declare                                                                                                            action_type text := null;                                                                                        begin                                                                                                               select type from actions into action_type;                                                                        raise info 'Hello, the action is (%)',action_type;                                                              end $$;
INFO:  Hello, the action is (drop)
DO
jmindek=#

Untuk menggunakan variabel psql tambahan dalam CREATE FUNCTION atau DO declaration, Anda dapat membuat kolom per variabel yang diperlukan.

Jerry Mindek
sumber
0

Ini tidak terlalu elegan tetapi berhasil (pseudocode):

cat <<EOF
   UPDATE tablename SET field=$arg1 WHERE field = $arg2;
EOF | psql database
JohnP
sumber
0

Pendekatan ini akan memberikan Anda resolusi run-time penuh dari env vars ... sehingga segera setelah skrip Anda mengatur sebelumnya semua variabel shell di bawah ini akan berfungsi ( telah dijalankan ribuan kali melawan berbagai dbs dan host ):

    -- start run.sh

       # 01 create / modify the app user
       sql_script="$pgsql_scripts_dir/01.create-qto-app-user.pgsql"
       PGPASSWORD="${postgres_db_useradmin_pw:-}" psql -q -t -X -w -U "${postgres_db_useradmin:-}" \
          -h $postgres_db_host -p $postgres_db_port \
          -v ON_ERROR_STOP=1 \
          -v postgres_db_user_pw="${postgres_db_user_pw:-}" \
          -v postgres_db_name="${postgres_db_name:-}" \
          -f "$sql_script" "${postgres_db_name:-}" > "$tmp_log_file" 2>&1
       ret=$?
       cat "$tmp_log_file" ; cat "$tmp_log_file" >> $log_file # show it and save it
       test $ret -ne 0 && sleep 3
       test $ret -ne 0 && doExit 1 "pid: $$ psql ret $ret - failed to run sql_script: $sql_script !!!"
    -- stop run.sh

    -- start fun.sql
            DO
            $do$
            BEGIN
               IF NOT EXISTS (
                  SELECT
                  FROM   pg_catalog.pg_roles
                  WHERE  rolname = 'usrqtoapp') THEN
                     CREATE ROLE usrqtoapp WITH PASSWORD ':postgres_db_user_pw' LOGIN ;
               END IF;
            END
            $do$;
            ALTER ROLE usrqtoapp WITH PASSWORD  :'postgres_db_user_pw' LOGIN ;

    -- eof run.sql
Yordan Georgiev
sumber